123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921 |
- /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /**
- * @constructor
- * @extends WebInspector.Object
- * @implements {WebInspector.SuggestBoxDelegate}
- * @param {function(Element, Range, boolean, function(!Array.<string>, number=))} completions
- * @param {string=} stopCharacters
- */
- WebInspector.TextPrompt = function(completions, stopCharacters)
- {
- /**
- * @type {Element|undefined}
- */
- this._proxyElement;
- this._proxyElementDisplay = "inline-block";
- this._loadCompletions = completions;
- this._completionStopCharacters = stopCharacters || " =:[({;,!+-*/&|^<>.";
- this._suggestForceable = true;
- }
- WebInspector.TextPrompt.Events = {
- ItemApplied: "text-prompt-item-applied",
- ItemAccepted: "text-prompt-item-accepted"
- };
- WebInspector.TextPrompt.prototype = {
- get proxyElement()
- {
- return this._proxyElement;
- },
- /**
- * @param {boolean} x
- */
- setSuggestForceable: function(x)
- {
- this._suggestForceable = x;
- },
- /**
- * @param {boolean} x
- */
- setShowSuggestForEmptyInput: function(x)
- {
- this._showSuggestForEmptyInput = x;
- },
- /**
- * @param {string} className
- */
- setSuggestBoxEnabled: function(className)
- {
- this._suggestBoxClassName = className;
- },
- renderAsBlock: function()
- {
- this._proxyElementDisplay = "block";
- },
- /**
- * Clients should never attach any event listeners to the |element|. Instead,
- * they should use the result of this method to attach listeners for bubbling events.
- *
- * @param {Element} element
- */
- attach: function(element)
- {
- return this._attachInternal(element);
- },
- /**
- * Clients should never attach any event listeners to the |element|. Instead,
- * they should use the result of this method to attach listeners for bubbling events
- * or the |blurListener| parameter to register a "blur" event listener on the |element|
- * (since the "blur" event does not bubble.)
- *
- * @param {Element} element
- * @param {function(Event)} blurListener
- */
- attachAndStartEditing: function(element, blurListener)
- {
- this._attachInternal(element);
- this._startEditing(blurListener);
- return this.proxyElement;
- },
- /**
- * @param {Element} element
- */
- _attachInternal: function(element)
- {
- if (this.proxyElement)
- throw "Cannot attach an attached TextPrompt";
- this._element = element;
- this._boundOnKeyDown = this.onKeyDown.bind(this);
- this._boundOnMouseWheel = this.onMouseWheel.bind(this);
- this._boundSelectStart = this._selectStart.bind(this);
- this._proxyElement = element.ownerDocument.createElement("span");
- this._proxyElement.style.display = this._proxyElementDisplay;
- element.parentElement.insertBefore(this.proxyElement, element);
- this.proxyElement.appendChild(element);
- this._element.addStyleClass("text-prompt");
- this._element.addEventListener("keydown", this._boundOnKeyDown, false);
- this._element.addEventListener("mousewheel", this._boundOnMouseWheel, false);
- this._element.addEventListener("selectstart", this._boundSelectStart, false);
- if (typeof this._suggestBoxClassName === "string")
- this._suggestBox = new WebInspector.SuggestBox(this, this._element, this._suggestBoxClassName);
- return this.proxyElement;
- },
- detach: function()
- {
- this._removeFromElement();
- this.proxyElement.parentElement.insertBefore(this._element, this.proxyElement);
- this.proxyElement.remove();
- delete this._proxyElement;
- this._element.removeStyleClass("text-prompt");
- this._element.removeEventListener("keydown", this._boundOnKeyDown, false);
- this._element.removeEventListener("mousewheel", this._boundOnMouseWheel, false);
- this._element.removeEventListener("selectstart", this._boundSelectStart, false);
- WebInspector.restoreFocusFromElement(this._element);
- },
- /**
- * @return string
- */
- get text()
- {
- return this._element.textContent;
- },
- /**
- * @param {string} x
- */
- set text(x)
- {
- this._removeSuggestionAids();
- if (!x) {
- // Append a break element instead of setting textContent to make sure the selection is inside the prompt.
- this._element.removeChildren();
- this._element.appendChild(document.createElement("br"));
- } else
- this._element.textContent = x;
- this.moveCaretToEndOfPrompt();
- this._element.scrollIntoView();
- },
- _removeFromElement: function()
- {
- this.clearAutoComplete(true);
- this._element.removeEventListener("keydown", this._boundOnKeyDown, false);
- this._element.removeEventListener("selectstart", this._boundSelectStart, false);
- if (this._isEditing)
- this._stopEditing();
- if (this._suggestBox)
- this._suggestBox.removeFromElement();
- },
- /**
- * @param {function(Event)=} blurListener
- */
- _startEditing: function(blurListener)
- {
- this._isEditing = true;
- this._element.addStyleClass("editing");
- if (blurListener) {
- this._blurListener = blurListener;
- this._element.addEventListener("blur", this._blurListener, false);
- }
- this._oldTabIndex = this._element.tabIndex;
- if (this._element.tabIndex < 0)
- this._element.tabIndex = 0;
- WebInspector.setCurrentFocusElement(this._element);
- if (!this.text)
- this._updateAutoComplete();
- },
- _stopEditing: function()
- {
- this._element.tabIndex = this._oldTabIndex;
- if (this._blurListener)
- this._element.removeEventListener("blur", this._blurListener, false);
- this._element.removeStyleClass("editing");
- delete this._isEditing;
- },
- _removeSuggestionAids: function()
- {
- this.clearAutoComplete();
- this.hideSuggestBox();
- },
- _selectStart: function()
- {
- if (this._selectionTimeout)
- clearTimeout(this._selectionTimeout);
- this._removeSuggestionAids();
- function moveBackIfOutside()
- {
- delete this._selectionTimeout;
- if (!this.isCaretInsidePrompt() && window.getSelection().isCollapsed) {
- this.moveCaretToEndOfPrompt();
- this.autoCompleteSoon();
- }
- }
- this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
- },
- /**
- * @param {boolean=} force
- * @return {boolean}
- */
- defaultKeyHandler: function(event, force)
- {
- this._updateAutoComplete(force);
- return false;
- },
- /**
- * @param {boolean=} force
- */
- _updateAutoComplete: function(force)
- {
- this.clearAutoComplete();
- this.autoCompleteSoon(force);
- },
- /**
- * @param {Event} event
- */
- onMouseWheel: function(event)
- {
- // Subclasses can implement.
- },
- /**
- * @param {Event} event
- */
- onKeyDown: function(event)
- {
- var handled = false;
- var invokeDefault = true;
- switch (event.keyIdentifier) {
- case "U+0009": // Tab
- handled = this.tabKeyPressed(event);
- break;
- case "Left":
- case "Home":
- this._removeSuggestionAids();
- invokeDefault = false;
- break;
- case "Right":
- case "End":
- if (this.isCaretAtEndOfPrompt())
- handled = this.acceptAutoComplete();
- else
- this._removeSuggestionAids();
- invokeDefault = false;
- break;
- case "U+001B": // Esc
- if (this.isSuggestBoxVisible()) {
- this._removeSuggestionAids();
- handled = true;
- }
- break;
- case "U+0020": // Space
- if (this._suggestForceable && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
- this.defaultKeyHandler(event, true);
- handled = true;
- }
- break;
- case "Alt":
- case "Meta":
- case "Shift":
- case "Control":
- invokeDefault = false;
- break;
- }
- if (!handled && this.isSuggestBoxVisible())
- handled = this._suggestBox.keyPressed(event);
- if (!handled && invokeDefault)
- handled = this.defaultKeyHandler(event);
- if (handled)
- event.consume(true);
- return handled;
- },
- /**
- * @return {boolean}
- */
- acceptAutoComplete: function()
- {
- var result = false;
- if (this.isSuggestBoxVisible())
- result = this._suggestBox.acceptSuggestion();
- if (!result)
- result = this.acceptSuggestion();
- return result;
- },
- /**
- * @param {boolean=} includeTimeout
- */
- clearAutoComplete: function(includeTimeout)
- {
- if (includeTimeout && this._completeTimeout) {
- clearTimeout(this._completeTimeout);
- delete this._completeTimeout;
- }
- delete this._waitingForCompletions;
- if (!this.autoCompleteElement)
- return;
- this.autoCompleteElement.remove();
- delete this.autoCompleteElement;
- if (!this._userEnteredRange || !this._userEnteredText)
- return;
- this._userEnteredRange.deleteContents();
- this._element.normalize();
- var userTextNode = document.createTextNode(this._userEnteredText);
- this._userEnteredRange.insertNode(userTextNode);
- var selectionRange = document.createRange();
- selectionRange.setStart(userTextNode, this._userEnteredText.length);
- selectionRange.setEnd(userTextNode, this._userEnteredText.length);
- var selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange(selectionRange);
- delete this._userEnteredRange;
- delete this._userEnteredText;
- },
- /**
- * @param {boolean=} force
- */
- autoCompleteSoon: function(force)
- {
- var immediately = this.isSuggestBoxVisible() || force;
- if (!this._completeTimeout)
- this._completeTimeout = setTimeout(this.complete.bind(this, force), immediately ? 0 : 250);
- },
- /**
- * @param {boolean=} reverse
- */
- complete: function(force, reverse)
- {
- this.clearAutoComplete(true);
- var selection = window.getSelection();
- if (!selection.rangeCount)
- return;
- var selectionRange = selection.getRangeAt(0);
- var shouldExit;
- if (!force && !this.isCaretAtEndOfPrompt() && !this.isSuggestBoxVisible())
- shouldExit = true;
- else if (!selection.isCollapsed)
- shouldExit = true;
- else if (!force) {
- // BUG72018: Do not show suggest box if caret is followed by a non-stop character.
- var wordSuffixRange = selectionRange.startContainer.rangeOfWord(selectionRange.endOffset, this._completionStopCharacters, this._element, "forward");
- if (wordSuffixRange.toString().length)
- shouldExit = true;
- }
- if (shouldExit) {
- this.hideSuggestBox();
- return;
- }
- var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this._completionStopCharacters, this._element, "backward");
- this._waitingForCompletions = true;
- this._loadCompletions(this.proxyElement, wordPrefixRange, force, this._completionsReady.bind(this, selection, wordPrefixRange, !!reverse));
- },
- /**
- * @param {Selection} selection
- * @param {Range} textRange
- */
- _boxForAnchorAtStart: function(selection, textRange)
- {
- var rangeCopy = selection.getRangeAt(0).cloneRange();
- var anchorElement = document.createElement("span");
- anchorElement.textContent = "\u200B";
- textRange.insertNode(anchorElement);
- var box = anchorElement.boxInWindow(window);
- anchorElement.remove();
- selection.removeAllRanges();
- selection.addRange(rangeCopy);
- return box;
- },
- /**
- * @param {Array.<string>} completions
- * @param {number} wordPrefixLength
- */
- _buildCommonPrefix: function(completions, wordPrefixLength)
- {
- var commonPrefix = completions[0];
- for (var i = 0; i < completions.length; ++i) {
- var completion = completions[i];
- var lastIndex = Math.min(commonPrefix.length, completion.length);
- for (var j = wordPrefixLength; j < lastIndex; ++j) {
- if (commonPrefix[j] !== completion[j]) {
- commonPrefix = commonPrefix.substr(0, j);
- break;
- }
- }
- }
- return commonPrefix;
- },
- /**
- * @param {Selection} selection
- * @param {Range} originalWordPrefixRange
- * @param {boolean} reverse
- * @param {!Array.<string>} completions
- * @param {number=} selectedIndex
- */
- _completionsReady: function(selection, originalWordPrefixRange, reverse, completions, selectedIndex)
- {
- if (!this._waitingForCompletions || !completions.length) {
- this.hideSuggestBox();
- return;
- }
- delete this._waitingForCompletions;
- var selectionRange = selection.getRangeAt(0);
- var fullWordRange = document.createRange();
- fullWordRange.setStart(originalWordPrefixRange.startContainer, originalWordPrefixRange.startOffset);
- fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset);
- if (originalWordPrefixRange.toString() + selectionRange.toString() != fullWordRange.toString())
- return;
- selectedIndex = selectedIndex || 0;
- this._userEnteredRange = fullWordRange;
- this._userEnteredText = fullWordRange.toString();
- if (this._suggestBox)
- this._suggestBox.updateSuggestions(this._boxForAnchorAtStart(selection, fullWordRange), completions, selectedIndex, !this.isCaretAtEndOfPrompt(), this._userEnteredText);
- var wordPrefixLength = originalWordPrefixRange.toString().length;
- this._commonPrefix = this._buildCommonPrefix(completions, wordPrefixLength);
- if (this.isCaretAtEndOfPrompt()) {
- this._userEnteredRange.deleteContents();
- this._element.normalize();
- var finalSelectionRange = document.createRange();
- var completionText = completions[selectedIndex];
- var prefixText = completionText.substring(0, wordPrefixLength);
- var suffixText = completionText.substring(wordPrefixLength);
- var prefixTextNode = document.createTextNode(prefixText);
- fullWordRange.insertNode(prefixTextNode);
- this.autoCompleteElement = document.createElement("span");
- this.autoCompleteElement.className = "auto-complete-text";
- this.autoCompleteElement.textContent = suffixText;
- prefixTextNode.parentNode.insertBefore(this.autoCompleteElement, prefixTextNode.nextSibling);
- finalSelectionRange.setStart(prefixTextNode, wordPrefixLength);
- finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength);
- selection.removeAllRanges();
- selection.addRange(finalSelectionRange);
- }
- },
- _completeCommonPrefix: function()
- {
- if (!this.autoCompleteElement || !this._commonPrefix || !this._userEnteredText || !this._commonPrefix.startsWith(this._userEnteredText))
- return;
- if (!this.isSuggestBoxVisible()) {
- this.acceptAutoComplete();
- return;
- }
- this.autoCompleteElement.textContent = this._commonPrefix.substring(this._userEnteredText.length);
- this.acceptSuggestion(true)
- },
- /**
- * @param {string} completionText
- * @param {boolean=} isIntermediateSuggestion
- */
- applySuggestion: function(completionText, isIntermediateSuggestion)
- {
- this._applySuggestion(completionText, isIntermediateSuggestion);
- },
- /**
- * @param {string} completionText
- * @param {boolean=} isIntermediateSuggestion
- * @param {Range=} originalPrefixRange
- */
- _applySuggestion: function(completionText, isIntermediateSuggestion, originalPrefixRange)
- {
- var wordPrefixLength;
- if (originalPrefixRange)
- wordPrefixLength = originalPrefixRange.toString().length;
- else
- wordPrefixLength = this._userEnteredText ? this._userEnteredText.length : 0;
- this._userEnteredRange.deleteContents();
- this._element.normalize();
- var finalSelectionRange = document.createRange();
- var completionTextNode = document.createTextNode(completionText);
- this._userEnteredRange.insertNode(completionTextNode);
- if (this.autoCompleteElement) {
- this.autoCompleteElement.remove();
- delete this.autoCompleteElement;
- }
- if (isIntermediateSuggestion)
- finalSelectionRange.setStart(completionTextNode, wordPrefixLength);
- else
- finalSelectionRange.setStart(completionTextNode, completionText.length);
- finalSelectionRange.setEnd(completionTextNode, completionText.length);
- var selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange(finalSelectionRange);
- if (isIntermediateSuggestion)
- this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApplied, { itemText: completionText });
- },
- /**
- * @param {boolean=} prefixAccepted
- */
- acceptSuggestion: function(prefixAccepted)
- {
- if (this._isAcceptingSuggestion)
- return false;
- if (!this.autoCompleteElement || !this.autoCompleteElement.parentNode)
- return false;
- var text = this.autoCompleteElement.textContent;
- var textNode = document.createTextNode(text);
- this.autoCompleteElement.parentNode.replaceChild(textNode, this.autoCompleteElement);
- delete this.autoCompleteElement;
- var finalSelectionRange = document.createRange();
- finalSelectionRange.setStart(textNode, text.length);
- finalSelectionRange.setEnd(textNode, text.length);
- var selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange(finalSelectionRange);
- if (!prefixAccepted) {
- this.hideSuggestBox();
- this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemAccepted);
- } else
- this.autoCompleteSoon(true);
- return true;
- },
- hideSuggestBox: function()
- {
- if (this.isSuggestBoxVisible())
- this._suggestBox.hide();
- },
- /**
- * @return {boolean}
- */
- isSuggestBoxVisible: function()
- {
- return this._suggestBox && this._suggestBox.visible();
- },
- /**
- * @return {boolean}
- */
- isCaretInsidePrompt: function()
- {
- return this._element.isInsertionCaretInside();
- },
- /**
- * @return {boolean}
- */
- isCaretAtEndOfPrompt: function()
- {
- var selection = window.getSelection();
- if (!selection.rangeCount || !selection.isCollapsed)
- return false;
- var selectionRange = selection.getRangeAt(0);
- var node = selectionRange.startContainer;
- if (!node.isSelfOrDescendant(this._element))
- return false;
- if (node.nodeType === Node.TEXT_NODE && selectionRange.startOffset < node.nodeValue.length)
- return false;
- var foundNextText = false;
- while (node) {
- if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) {
- if (foundNextText && (!this.autoCompleteElement || !this.autoCompleteElement.isAncestor(node)))
- return false;
- foundNextText = true;
- }
- node = node.traverseNextNode(this._element);
- }
- return true;
- },
- /**
- * @return {boolean}
- */
- isCaretOnFirstLine: function()
- {
- var selection = window.getSelection();
- var focusNode = selection.focusNode;
- if (!focusNode || focusNode.nodeType !== Node.TEXT_NODE || focusNode.parentNode !== this._element)
- return true;
- if (focusNode.textContent.substring(0, selection.focusOffset).indexOf("\n") !== -1)
- return false;
- focusNode = focusNode.previousSibling;
- while (focusNode) {
- if (focusNode.nodeType !== Node.TEXT_NODE)
- return true;
- if (focusNode.textContent.indexOf("\n") !== -1)
- return false;
- focusNode = focusNode.previousSibling;
- }
- return true;
- },
- /**
- * @return {boolean}
- */
- isCaretOnLastLine: function()
- {
- var selection = window.getSelection();
- var focusNode = selection.focusNode;
- if (!focusNode || focusNode.nodeType !== Node.TEXT_NODE || focusNode.parentNode !== this._element)
- return true;
- if (focusNode.textContent.substring(selection.focusOffset).indexOf("\n") !== -1)
- return false;
- focusNode = focusNode.nextSibling;
- while (focusNode) {
- if (focusNode.nodeType !== Node.TEXT_NODE)
- return true;
- if (focusNode.textContent.indexOf("\n") !== -1)
- return false;
- focusNode = focusNode.nextSibling;
- }
- return true;
- },
- moveCaretToEndOfPrompt: function()
- {
- var selection = window.getSelection();
- var selectionRange = document.createRange();
- var offset = this._element.childNodes.length;
- selectionRange.setStart(this._element, offset);
- selectionRange.setEnd(this._element, offset);
- selection.removeAllRanges();
- selection.addRange(selectionRange);
- },
- /**
- * @param {Event} event
- * @return {boolean}
- */
- tabKeyPressed: function(event)
- {
- this._completeCommonPrefix();
- // Consume the key.
- return true;
- },
- __proto__: WebInspector.Object.prototype
- }
- /**
- * @constructor
- * @extends {WebInspector.TextPrompt}
- * @param {function(Element, Range, boolean, function(!Array.<string>, number=))} completions
- * @param {string=} stopCharacters
- */
- WebInspector.TextPromptWithHistory = function(completions, stopCharacters)
- {
- WebInspector.TextPrompt.call(this, completions, stopCharacters);
- /**
- * @type {Array.<string>}
- */
- this._data = [];
- /**
- * 1-based entry in the history stack.
- * @type {number}
- */
- this._historyOffset = 1;
- /**
- * Whether to coalesce duplicate items in the history, default is true.
- * @type {boolean}
- */
- this._coalesceHistoryDupes = true;
- }
- WebInspector.TextPromptWithHistory.prototype = {
- /**
- * @return {Array.<string>}
- */
- get historyData()
- {
- // FIXME: do we need to copy this?
- return this._data;
- },
- /**
- * @param {boolean} x
- */
- setCoalesceHistoryDupes: function(x)
- {
- this._coalesceHistoryDupes = x;
- },
- /**
- * @param {Array.<string>} data
- */
- setHistoryData: function(data)
- {
- this._data = [].concat(data);
- this._historyOffset = 1;
- },
- /**
- * Pushes a committed text into the history.
- * @param {string} text
- */
- pushHistoryItem: function(text)
- {
- if (this._uncommittedIsTop) {
- this._data.pop();
- delete this._uncommittedIsTop;
- }
- this._historyOffset = 1;
- if (this._coalesceHistoryDupes && text === this._currentHistoryItem())
- return;
- this._data.push(text);
- },
- /**
- * Pushes the current (uncommitted) text into the history.
- */
- _pushCurrentText: function()
- {
- if (this._uncommittedIsTop)
- this._data.pop(); // Throw away obsolete uncommitted text.
- this._uncommittedIsTop = true;
- this.clearAutoComplete(true);
- this._data.push(this.text);
- },
- /**
- * @return {string|undefined}
- */
- _previous: function()
- {
- if (this._historyOffset > this._data.length)
- return undefined;
- if (this._historyOffset === 1)
- this._pushCurrentText();
- ++this._historyOffset;
- return this._currentHistoryItem();
- },
- /**
- * @return {string|undefined}
- */
- _next: function()
- {
- if (this._historyOffset === 1)
- return undefined;
- --this._historyOffset;
- return this._currentHistoryItem();
- },
- /**
- * @return {string|undefined}
- */
- _currentHistoryItem: function()
- {
- return this._data[this._data.length - this._historyOffset];
- },
- /**
- * @override
- */
- defaultKeyHandler: function(event, force)
- {
- var newText;
- var isPrevious;
- switch (event.keyIdentifier) {
- case "Up":
- if (!this.isCaretOnFirstLine())
- break;
- newText = this._previous();
- isPrevious = true;
- break;
- case "Down":
- if (!this.isCaretOnLastLine())
- break;
- newText = this._next();
- break;
- case "U+0050": // Ctrl+P = Previous
- if (WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
- newText = this._previous();
- isPrevious = true;
- }
- break;
- case "U+004E": // Ctrl+N = Next
- if (WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey)
- newText = this._next();
- break;
- }
- if (newText !== undefined) {
- event.consume(true);
- this.text = newText;
- if (isPrevious) {
- var firstNewlineIndex = this.text.indexOf("\n");
- if (firstNewlineIndex === -1)
- this.moveCaretToEndOfPrompt();
- else {
- var selection = window.getSelection();
- var selectionRange = document.createRange();
- selectionRange.setStart(this._element.firstChild, firstNewlineIndex);
- selectionRange.setEnd(this._element.firstChild, firstNewlineIndex);
- selection.removeAllRanges();
- selection.addRange(selectionRange);
- }
- }
- return true;
- }
- return WebInspector.TextPrompt.prototype.defaultKeyHandler.apply(this, arguments);
- },
- __proto__: WebInspector.TextPrompt.prototype
- }
|