Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(370)

Unified Diff: third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
index 5bccf6fa1966d3b9bcf28da25e82a5408e03df8a..4866d067f770a1ad358e81b5c6a4a224ab8d1a97 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
@@ -26,645 +26,620 @@
* (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}
+ * @unrestricted
*/
-WebInspector.TextPrompt = function()
-{
+WebInspector.TextPrompt = class extends WebInspector.Object {
+ constructor() {
+ super();
/**
* @type {!Element|undefined}
*/
this._proxyElement;
- this._proxyElementDisplay = "inline-block";
+ this._proxyElementDisplay = 'inline-block';
this._autocompletionTimeout = WebInspector.TextPrompt.DefaultAutocompletionTimeout;
- this._title = "";
+ this._title = '';
this._prefixRange = null;
- this._previousText = "";
- this._currentSuggestion = "";
+ this._previousText = '';
+ this._currentSuggestion = '';
this._completionRequestId = 0;
- this._ghostTextElement = createElementWithClass("span", "auto-complete-text");
+ this._ghostTextElement = createElementWithClass('span', 'auto-complete-text');
+ }
+
+ /**
+ * @param {function(!Element, !Range, boolean, function(!Array.<string>, number=))} completions
+ * @param {string=} stopCharacters
+ */
+ initialize(completions, stopCharacters) {
+ this._loadCompletions = completions;
+ this._completionStopCharacters = stopCharacters || ' =:[({;,!+-*/&|^<>.';
+ }
+
+ /**
+ * @param {number} timeout
+ */
+ setAutocompletionTimeout(timeout) {
+ this._autocompletionTimeout = timeout;
+ }
+
+ /**
+ * @param {boolean} suggestBoxEnabled
+ */
+ setSuggestBoxEnabled(suggestBoxEnabled) {
+ this._suggestBoxEnabled = suggestBoxEnabled;
+ }
+
+ renderAsBlock() {
+ 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
+ * @return {!Element}
+ */
+ attach(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
+ * @return {!Element}
+ */
+ attachAndStartEditing(element, blurListener) {
+ var proxyElement = this._attachInternal(element);
+ this._startEditing(blurListener);
+ return proxyElement;
+ }
+
+ /**
+ * @param {!Element} element
+ * @return {!Element}
+ */
+ _attachInternal(element) {
+ if (this._proxyElement)
+ throw 'Cannot attach an attached TextPrompt';
+ this._element = element;
+
+ this._boundOnKeyDown = this.onKeyDown.bind(this);
+ this._boundOnInput = this.onInput.bind(this);
+ this._boundOnMouseWheel = this.onMouseWheel.bind(this);
+ this._boundClearAutocomplete = this.clearAutocomplete.bind(this);
+ this._proxyElement = element.ownerDocument.createElement('span');
+ var shadowRoot = WebInspector.createShadowRootWithCoreStyles(this._proxyElement, 'ui/textPrompt.css');
+ this._contentElement = shadowRoot.createChild('div');
+ this._contentElement.createChild('content');
+ this._proxyElement.style.display = this._proxyElementDisplay;
+ element.parentElement.insertBefore(this._proxyElement, element);
+ this._proxyElement.appendChild(element);
+ this._element.classList.add('text-prompt');
+ this._element.addEventListener('keydown', this._boundOnKeyDown, false);
+ this._element.addEventListener('input', this._boundOnInput, false);
+ this._element.addEventListener('mousewheel', this._boundOnMouseWheel, false);
+ this._element.addEventListener('selectstart', this._boundClearAutocomplete, false);
+ this._element.addEventListener('blur', this._boundClearAutocomplete, false);
+ this._element.ownerDocument.defaultView.addEventListener('resize', this._boundClearAutocomplete, false);
+
+ if (this._suggestBoxEnabled)
+ this._suggestBox = new WebInspector.SuggestBox(this, 20, true);
+
+ if (this._title)
+ this._proxyElement.title = this._title;
+
+ return this._proxyElement;
+ }
+
+ detach() {
+ this._removeFromElement();
+ this._proxyElement.parentElement.insertBefore(this._element, this._proxyElement);
+ this._proxyElement.remove();
+ delete this._proxyElement;
+ this._element.classList.remove('text-prompt');
+ this._focusRestorer.restore();
+ }
+
+ /**
+ * @return {string}
+ */
+ textWithCurrentSuggestion() {
+ return this._element.textContent;
+ }
+
+ /**
+ * @return {string}
+ */
+ text() {
+ var text = this.textWithCurrentSuggestion();
+ if (this._ghostTextElement.parentNode) {
+ var addition = this._ghostTextElement.textContent;
+ text = text.substring(0, text.length - addition.length);
+ }
+ return text;
+ }
+
+ /**
+ * @param {string} x
+ */
+ setText(x) {
+ this.clearAutocomplete();
+ if (!x) {
+ // Append a break element instead of setting textContent to make sure the selection is inside the prompt.
+ this._element.removeChildren();
+ this._element.createChild('br');
+ } else {
+ this._element.textContent = x;
+ }
+ this._previousText = this.text();
+
+ this.moveCaretToEndOfPrompt();
+ this._element.scrollIntoView();
+ }
+
+ /**
+ * @return {string}
+ */
+ title() {
+ return this._title;
+ }
+
+ /**
+ * @param {string} title
+ */
+ setTitle(title) {
+ this._title = title;
+ if (this._proxyElement)
+ this._proxyElement.title = title;
+ }
+
+ _removeFromElement() {
+ this.clearAutocomplete();
+ this._element.removeEventListener('keydown', this._boundOnKeyDown, false);
+ this._element.removeEventListener('input', this._boundOnInput, false);
+ this._element.removeEventListener('selectstart', this._boundClearAutocomplete, false);
+ this._element.removeEventListener('blur', this._boundClearAutocomplete, false);
+ this._element.ownerDocument.defaultView.removeEventListener('resize', this._boundClearAutocomplete, false);
+ if (this._isEditing)
+ this._stopEditing();
+ if (this._suggestBox)
+ this._suggestBox.removeFromElement();
+ }
+
+ /**
+ * @param {function(!Event)=} blurListener
+ */
+ _startEditing(blurListener) {
+ this._isEditing = true;
+ this._contentElement.classList.add('text-prompt-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;
+ this._focusRestorer = new WebInspector.ElementFocusRestorer(this._element);
+ if (!this.text())
+ this.autoCompleteSoon();
+ }
+
+ _stopEditing() {
+ this._element.tabIndex = this._oldTabIndex;
+ if (this._blurListener)
+ this._element.removeEventListener('blur', this._blurListener, false);
+ this._contentElement.classList.remove('text-prompt-editing');
+ delete this._isEditing;
+ }
+
+ /**
+ * @param {!Event} event
+ */
+ onMouseWheel(event) {
+ // Subclasses can implement.
+ }
+
+ /**
+ * @param {!Event} event
+ */
+ onKeyDown(event) {
+ var handled = false;
+
+ switch (event.key) {
+ case 'Tab':
+ handled = this.tabKeyPressed(event);
+ break;
+ case 'ArrowLeft':
+ case 'Home':
+ this.clearAutocomplete();
+ break;
+ case 'ArrowRight':
+ case 'End':
+ if (this._isCaretAtEndOfPrompt())
+ handled = this.acceptAutoComplete();
+ else
+ this.clearAutocomplete();
+ break;
+ case 'Escape':
+ if (this._isSuggestBoxVisible()) {
+ this.clearAutocomplete();
+ handled = true;
+ }
+ break;
+ case ' ': // Space
+ if (event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
+ this.autoCompleteSoon(true);
+ handled = true;
+ }
+ break;
+ case 'Alt':
+ case 'Meta':
+ case 'Shift':
+ case 'Control':
+ break;
+ }
+
+ if (!handled && this._isSuggestBoxVisible())
+ handled = this._suggestBox.keyPressed(event);
+
+ if (handled)
+ event.consume(true);
+ }
+
+ /**
+ * @param {!Event} event
+ */
+ onInput(event) {
+ var text = this.text();
+ var hasCommonPrefix = text.startsWith(this._previousText) || this._previousText.startsWith(text);
+ if (this._prefixRange && hasCommonPrefix)
+ this._prefixRange.endColumn += text.length - this._previousText.length;
+ this._refreshGhostText();
+ this._previousText = text;
+
+ this.autoCompleteSoon();
+ }
+
+ /**
+ * @return {boolean}
+ */
+ acceptAutoComplete() {
+ var result = false;
+ if (this._isSuggestBoxVisible())
+ result = this._suggestBox.acceptSuggestion();
+ if (!result)
+ result = this._acceptSuggestionInternal();
+
+ return result;
+ }
+
+ clearAutocomplete() {
+ if (this._isSuggestBoxVisible())
+ this._suggestBox.hide();
+ this._clearAutocompleteTimeout();
+ this._prefixRange = null;
+ this._refreshGhostText();
+ }
+
+ _refreshGhostText() {
+ if (this._prefixRange && this._isCaretAtEndOfPrompt()) {
+ this._ghostTextElement.textContent =
+ this._currentSuggestion.substring(this._prefixRange.endColumn - this._prefixRange.startColumn);
+ this._element.appendChild(this._ghostTextElement);
+ } else {
+ this._ghostTextElement.remove();
+ }
+ }
+
+ _clearAutocompleteTimeout() {
+ if (this._completeTimeout) {
+ clearTimeout(this._completeTimeout);
+ delete this._completeTimeout;
+ }
+ this._completionRequestId++;
+ }
+
+ /**
+ * @param {boolean=} force
+ */
+ autoCompleteSoon(force) {
+ var immediately = this._isSuggestBoxVisible() || force;
+ if (!this._completeTimeout)
+ this._completeTimeout =
+ setTimeout(this.complete.bind(this, force), immediately ? 0 : this._autocompletionTimeout);
+ }
+
+ /**
+ * @param {boolean=} force
+ * @param {boolean=} reverse
+ */
+ complete(force, reverse) {
+ this._clearAutocompleteTimeout();
+ var selection = this._element.getComponentSelection();
+ var selectionRange = selection && selection.rangeCount ? selection.getRangeAt(0) : null;
+ if (!selectionRange)
+ return;
+
+ 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');
+ var autocompleteTextLength = this._ghostTextElement.parentNode ? this._ghostTextElement.textContent.length : 0;
+ if (wordSuffixRange.toString().length !== autocompleteTextLength)
+ shouldExit = true;
+ }
+ if (shouldExit) {
+ this.clearAutocomplete();
+ return;
+ }
+
+ var wordPrefixRange = selectionRange.startContainer.rangeOfWord(
+ selectionRange.startOffset, this._completionStopCharacters, this._element, 'backward');
+ this._loadCompletions(
+ /** @type {!Element} */ (this._proxyElement), wordPrefixRange, force || false,
+ this._completionsReady.bind(this, ++this._completionRequestId, selection, wordPrefixRange, !!reverse, !!force));
+ }
+
+ disableDefaultSuggestionForEmptyInput() {
+ this._disableDefaultSuggestionForEmptyInput = true;
+ }
+
+ /**
+ * @param {!Selection} selection
+ * @param {!Range} textRange
+ */
+ _boxForAnchorAtStart(selection, textRange) {
+ var rangeCopy = selection.getRangeAt(0).cloneRange();
+ var anchorElement = createElement('span');
+ anchorElement.textContent = '\u200B';
+ textRange.insertNode(anchorElement);
+ var box = anchorElement.boxInWindow(window);
+ anchorElement.remove();
+ selection.removeAllRanges();
+ selection.addRange(rangeCopy);
+ return box;
+ }
+
+ /**
+ * @return {?Range}
+ * @suppressGlobalPropertiesCheck
+ */
+ _createRange() {
+ return document.createRange();
+ }
+
+ /**
+ * @param {string} prefix
+ * @return {!WebInspector.SuggestBox.Suggestions}
+ */
+ additionalCompletions(prefix) {
+ return [];
+ }
+
+ /**
+ * @param {number} completionRequestId
+ * @param {!Selection} selection
+ * @param {!Range} originalWordPrefixRange
+ * @param {boolean} reverse
+ * @param {boolean} force
+ * @param {!Array.<string>} completions
+ * @param {number=} selectedIndex
+ */
+ _completionsReady(
+ completionRequestId,
+ selection,
+ originalWordPrefixRange,
+ reverse,
+ force,
+ completions,
+ selectedIndex) {
+ if (this._completionRequestId !== completionRequestId)
+ return;
+
+ var prefix = originalWordPrefixRange.toString();
+
+ // Filter out dupes.
+ var store = new Set();
+ completions = completions.filter(item => !store.has(item) && !!store.add(item));
+ var annotatedCompletions = completions.map(item => ({title: item}));
+
+ if (prefix || force) {
+ if (prefix)
+ annotatedCompletions = annotatedCompletions.concat(this.additionalCompletions(prefix));
+ else
+ annotatedCompletions = this.additionalCompletions(prefix).concat(annotatedCompletions);
+ }
+
+ if (!annotatedCompletions.length) {
+ this.clearAutocomplete();
+ return;
+ }
+
+ var selectionRange = selection.getRangeAt(0);
+
+ var fullWordRange = this._createRange();
+ fullWordRange.setStart(originalWordPrefixRange.startContainer, originalWordPrefixRange.startOffset);
+ fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset);
+
+ if (prefix + selectionRange.toString() !== fullWordRange.toString())
+ return;
+
+ selectedIndex = (this._disableDefaultSuggestionForEmptyInput && !this.text()) ? -1 : (selectedIndex || 0);
+
+ if (this._suggestBox)
+ this._suggestBox.updateSuggestions(
+ this._boxForAnchorAtStart(selection, fullWordRange), annotatedCompletions, selectedIndex,
+ !this._isCaretAtEndOfPrompt(), this.text());
+
+ var beforeRange = this._createRange();
+ beforeRange.setStart(this._element, 0);
+ beforeRange.setEnd(fullWordRange.startContainer, fullWordRange.startOffset);
+ this._prefixRange = new WebInspector.TextRange(
+ 0, beforeRange.toString().length, 0, beforeRange.toString().length + fullWordRange.toString().length);
+
+ if (selectedIndex === -1)
+ return;
+ this.applySuggestion(annotatedCompletions[selectedIndex].title, true);
+ }
+
+ /**
+ * @override
+ * @param {string} suggestion
+ * @param {boolean=} isIntermediateSuggestion
+ */
+ applySuggestion(suggestion, isIntermediateSuggestion) {
+ if (!this._prefixRange)
+ return;
+ this._currentSuggestion = suggestion;
+ this._refreshGhostText();
+ if (isIntermediateSuggestion)
+ this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApplied);
+ }
+
+ /**
+ * @override
+ */
+ acceptSuggestion() {
+ this._acceptSuggestionInternal();
+ }
+
+ /**
+ * @return {boolean}
+ */
+ _acceptSuggestionInternal() {
+ if (!this._prefixRange)
+ return false;
+
+ var text = this.text();
+ this._element.textContent = text.substring(0, this._prefixRange.startColumn) + this._currentSuggestion +
+ text.substring(this._prefixRange.endColumn);
+ this._setDOMSelection(
+ this._prefixRange.startColumn + this._currentSuggestion.length,
+ this._prefixRange.startColumn + this._currentSuggestion.length);
+
+ this.clearAutocomplete();
+ this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemAccepted);
+
+ return true;
+ }
+
+ /**
+ * @param {number} startColumn
+ * @param {number} endColumn
+ */
+ _setDOMSelection(startColumn, endColumn) {
+ this._element.normalize();
+ var node = this._element.childNodes[0];
+ if (!node || node === this._ghostTextElement)
+ return;
+ var range = this._createRange();
+ range.setStart(node, startColumn);
+ range.setEnd(node, endColumn);
+ var selection = this._element.getComponentSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+ }
+
+ /**
+ * @return {boolean}
+ */
+ _isSuggestBoxVisible() {
+ return this._suggestBox && this._suggestBox.visible();
+ }
+
+ /**
+ * @return {boolean}
+ */
+ isCaretInsidePrompt() {
+ var selection = this._element.getComponentSelection();
+ // @see crbug.com/602541
+ var selectionRange = selection && selection.rangeCount ? selection.getRangeAt(0) : null;
+ if (!selectionRange || !selection.isCollapsed)
+ return false;
+ return selectionRange.startContainer.isSelfOrDescendant(this._element);
+ }
+
+ /**
+ * @return {boolean}
+ */
+ _isCaretAtEndOfPrompt() {
+ var selection = this._element.getComponentSelection();
+ var selectionRange = selection && selection.rangeCount ? selection.getRangeAt(0) : null;
+ if (!selectionRange || !selection.isCollapsed)
+ return false;
+
+ 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._ghostTextElement.isAncestor(node))
+ return false;
+ foundNextText = true;
+ }
+
+ node = node.traverseNextNode(this._element);
+ }
+
+ return true;
+ }
+
+ moveCaretToEndOfPrompt() {
+ var selection = this._element.getComponentSelection();
+ var selectionRange = this._createRange();
+
+ var container = this._element;
+ while (container.childNodes.length)
+ container = container.lastChild;
+ var offset = container.nodeType === Node.TEXT_NODE ? container.textContent.length : 0;
+ selectionRange.setStart(container, offset);
+ selectionRange.setEnd(container, offset);
+
+ selection.removeAllRanges();
+ selection.addRange(selectionRange);
+ }
+
+ /**
+ * @param {!Event} event
+ * @return {boolean}
+ */
+ tabKeyPressed(event) {
+ this.acceptAutoComplete();
+
+ // Consume the key.
+ return true;
+ }
+
+ /**
+ * @return {?Element}
+ */
+ proxyElementForTests() {
+ return this._proxyElement || null;
+ }
};
WebInspector.TextPrompt.DefaultAutocompletionTimeout = 250;
/** @enum {symbol} */
WebInspector.TextPrompt.Events = {
- ItemApplied: Symbol("text-prompt-item-applied"),
- ItemAccepted: Symbol("text-prompt-item-accepted")
-};
-
-WebInspector.TextPrompt.prototype = {
- /**
- * @param {function(!Element, !Range, boolean, function(!Array.<string>, number=))} completions
- * @param {string=} stopCharacters
- */
- initialize: function(completions, stopCharacters)
- {
- this._loadCompletions = completions;
- this._completionStopCharacters = stopCharacters || " =:[({;,!+-*/&|^<>.";
- },
-
- /**
- * @param {number} timeout
- */
- setAutocompletionTimeout: function(timeout)
- {
- this._autocompletionTimeout = timeout;
- },
-
- /**
- * @param {boolean} suggestBoxEnabled
- */
- setSuggestBoxEnabled: function(suggestBoxEnabled)
- {
- this._suggestBoxEnabled = suggestBoxEnabled;
- },
-
- 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
- * @return {!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
- * @return {!Element}
- */
- attachAndStartEditing: function(element, blurListener)
- {
- var proxyElement = this._attachInternal(element);
- this._startEditing(blurListener);
- return proxyElement;
- },
-
- /**
- * @param {!Element} element
- * @return {!Element}
- */
- _attachInternal: function(element)
- {
- if (this._proxyElement)
- throw "Cannot attach an attached TextPrompt";
- this._element = element;
-
- this._boundOnKeyDown = this.onKeyDown.bind(this);
- this._boundOnInput = this.onInput.bind(this);
- this._boundOnMouseWheel = this.onMouseWheel.bind(this);
- this._boundClearAutocomplete = this.clearAutocomplete.bind(this);
- this._proxyElement = element.ownerDocument.createElement("span");
- var shadowRoot = WebInspector.createShadowRootWithCoreStyles(this._proxyElement, "ui/textPrompt.css");
- this._contentElement = shadowRoot.createChild("div");
- this._contentElement.createChild("content");
- this._proxyElement.style.display = this._proxyElementDisplay;
- element.parentElement.insertBefore(this._proxyElement, element);
- this._proxyElement.appendChild(element);
- this._element.classList.add("text-prompt");
- this._element.addEventListener("keydown", this._boundOnKeyDown, false);
- this._element.addEventListener("input", this._boundOnInput, false);
- this._element.addEventListener("mousewheel", this._boundOnMouseWheel, false);
- this._element.addEventListener("selectstart", this._boundClearAutocomplete, false);
- this._element.addEventListener("blur", this._boundClearAutocomplete, false);
- this._element.ownerDocument.defaultView.addEventListener("resize", this._boundClearAutocomplete, false);
-
- if (this._suggestBoxEnabled)
- this._suggestBox = new WebInspector.SuggestBox(this, 20, true);
-
- if (this._title)
- this._proxyElement.title = this._title;
-
- return this._proxyElement;
- },
-
- detach: function()
- {
- this._removeFromElement();
- this._proxyElement.parentElement.insertBefore(this._element, this._proxyElement);
- this._proxyElement.remove();
- delete this._proxyElement;
- this._element.classList.remove("text-prompt");
- this._focusRestorer.restore();
- },
-
- /**
- * @return {string}
- */
- textWithCurrentSuggestion: function()
- {
- return this._element.textContent;
- },
-
- /**
- * @return {string}
- */
- text: function()
- {
- var text = this.textWithCurrentSuggestion();
- if (this._ghostTextElement.parentNode) {
- var addition = this._ghostTextElement.textContent;
- text = text.substring(0, text.length - addition.length);
- }
- return text;
- },
-
- /**
- * @param {string} x
- */
- setText: function(x)
- {
- this.clearAutocomplete();
- if (!x) {
- // Append a break element instead of setting textContent to make sure the selection is inside the prompt.
- this._element.removeChildren();
- this._element.createChild("br");
- } else {
- this._element.textContent = x;
- }
- this._previousText = this.text();
-
- this.moveCaretToEndOfPrompt();
- this._element.scrollIntoView();
- },
-
- /**
- * @return {string}
- */
- title: function()
- {
- return this._title;
- },
-
- /**
- * @param {string} title
- */
- setTitle: function(title)
- {
- this._title = title;
- if (this._proxyElement)
- this._proxyElement.title = title;
- },
-
- _removeFromElement: function()
- {
- this.clearAutocomplete();
- this._element.removeEventListener("keydown", this._boundOnKeyDown, false);
- this._element.removeEventListener("input", this._boundOnInput, false);
- this._element.removeEventListener("selectstart", this._boundClearAutocomplete, false);
- this._element.removeEventListener("blur", this._boundClearAutocomplete, false);
- this._element.ownerDocument.defaultView.removeEventListener("resize", this._boundClearAutocomplete, false);
- if (this._isEditing)
- this._stopEditing();
- if (this._suggestBox)
- this._suggestBox.removeFromElement();
- },
-
- /**
- * @param {function(!Event)=} blurListener
- */
- _startEditing: function(blurListener)
- {
- this._isEditing = true;
- this._contentElement.classList.add("text-prompt-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;
- this._focusRestorer = new WebInspector.ElementFocusRestorer(this._element);
- if (!this.text())
- this.autoCompleteSoon();
- },
-
- _stopEditing: function()
- {
- this._element.tabIndex = this._oldTabIndex;
- if (this._blurListener)
- this._element.removeEventListener("blur", this._blurListener, false);
- this._contentElement.classList.remove("text-prompt-editing");
- delete this._isEditing;
- },
-
- /**
- * @param {!Event} event
- */
- onMouseWheel: function(event)
- {
- // Subclasses can implement.
- },
-
- /**
- * @param {!Event} event
- */
- onKeyDown: function(event)
- {
- var handled = false;
-
- switch (event.key) {
- case "Tab":
- handled = this.tabKeyPressed(event);
- break;
- case "ArrowLeft":
- case "Home":
- this.clearAutocomplete();
- break;
- case "ArrowRight":
- case "End":
- if (this._isCaretAtEndOfPrompt())
- handled = this.acceptAutoComplete();
- else
- this.clearAutocomplete();
- break;
- case "Escape":
- if (this._isSuggestBoxVisible()) {
- this.clearAutocomplete();
- handled = true;
- }
- break;
- case " ": // Space
- if (event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
- this.autoCompleteSoon(true);
- handled = true;
- }
- break;
- case "Alt":
- case "Meta":
- case "Shift":
- case "Control":
- break;
- }
-
- if (!handled && this._isSuggestBoxVisible())
- handled = this._suggestBox.keyPressed(event);
-
- if (handled)
- event.consume(true);
- },
-
- /**
- * @param {!Event} event
- */
- onInput: function(event)
- {
- var text = this.text();
- var hasCommonPrefix = text.startsWith(this._previousText) || this._previousText.startsWith(text);
- if (this._prefixRange && hasCommonPrefix)
- this._prefixRange.endColumn += text.length - this._previousText.length;
- this._refreshGhostText();
- this._previousText = text;
-
- this.autoCompleteSoon();
- },
-
- /**
- * @return {boolean}
- */
- acceptAutoComplete: function()
- {
- var result = false;
- if (this._isSuggestBoxVisible())
- result = this._suggestBox.acceptSuggestion();
- if (!result)
- result = this._acceptSuggestionInternal();
-
- return result;
- },
-
- clearAutocomplete: function()
- {
- if (this._isSuggestBoxVisible())
- this._suggestBox.hide();
- this._clearAutocompleteTimeout();
- this._prefixRange = null;
- this._refreshGhostText();
- },
-
- _refreshGhostText: function()
- {
- if (this._prefixRange && this._isCaretAtEndOfPrompt()) {
- this._ghostTextElement.textContent = this._currentSuggestion.substring(this._prefixRange.endColumn - this._prefixRange.startColumn);
- this._element.appendChild(this._ghostTextElement);
- } else {
- this._ghostTextElement.remove();
- }
- },
-
- _clearAutocompleteTimeout: function()
- {
- if (this._completeTimeout) {
- clearTimeout(this._completeTimeout);
- delete this._completeTimeout;
- }
- this._completionRequestId++;
- },
-
- /**
- * @param {boolean=} force
- */
- autoCompleteSoon: function(force)
- {
- var immediately = this._isSuggestBoxVisible() || force;
- if (!this._completeTimeout)
- this._completeTimeout = setTimeout(this.complete.bind(this, force), immediately ? 0 : this._autocompletionTimeout);
- },
-
- /**
- * @param {boolean=} force
- * @param {boolean=} reverse
- */
- complete: function(force, reverse)
- {
- this._clearAutocompleteTimeout();
- var selection = this._element.getComponentSelection();
- var selectionRange = selection && selection.rangeCount ? selection.getRangeAt(0) : null;
- if (!selectionRange)
- return;
-
- 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");
- var autocompleteTextLength = this._ghostTextElement.parentNode ? this._ghostTextElement.textContent.length : 0;
- if (wordSuffixRange.toString().length !== autocompleteTextLength)
- shouldExit = true;
- }
- if (shouldExit) {
- this.clearAutocomplete();
- return;
- }
-
- var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this._completionStopCharacters, this._element, "backward");
- this._loadCompletions(/** @type {!Element} */ (this._proxyElement), wordPrefixRange, force || false, this._completionsReady.bind(this, ++this._completionRequestId, selection, wordPrefixRange, !!reverse, !!force));
- },
-
- disableDefaultSuggestionForEmptyInput: function()
- {
- this._disableDefaultSuggestionForEmptyInput = true;
- },
-
- /**
- * @param {!Selection} selection
- * @param {!Range} textRange
- */
- _boxForAnchorAtStart: function(selection, textRange)
- {
- var rangeCopy = selection.getRangeAt(0).cloneRange();
- var anchorElement = createElement("span");
- anchorElement.textContent = "\u200B";
- textRange.insertNode(anchorElement);
- var box = anchorElement.boxInWindow(window);
- anchorElement.remove();
- selection.removeAllRanges();
- selection.addRange(rangeCopy);
- return box;
- },
-
- /**
- * @return {?Range}
- * @suppressGlobalPropertiesCheck
- */
- _createRange: function()
- {
- return document.createRange();
- },
-
- /**
- * @param {string} prefix
- * @return {!WebInspector.SuggestBox.Suggestions}
- */
- additionalCompletions: function(prefix)
- {
- return [];
- },
-
- /**
- * @param {number} completionRequestId
- * @param {!Selection} selection
- * @param {!Range} originalWordPrefixRange
- * @param {boolean} reverse
- * @param {boolean} force
- * @param {!Array.<string>} completions
- * @param {number=} selectedIndex
- */
- _completionsReady: function(completionRequestId, selection, originalWordPrefixRange, reverse, force, completions, selectedIndex)
- {
- if (this._completionRequestId !== completionRequestId)
- return;
-
- var prefix = originalWordPrefixRange.toString();
-
- // Filter out dupes.
- var store = new Set();
- completions = completions.filter(item => !store.has(item) && !!store.add(item));
- var annotatedCompletions = completions.map(item => ({title: item}));
-
- if (prefix || force) {
- if (prefix)
- annotatedCompletions = annotatedCompletions.concat(this.additionalCompletions(prefix));
- else
- annotatedCompletions = this.additionalCompletions(prefix).concat(annotatedCompletions);
- }
-
- if (!annotatedCompletions.length) {
- this.clearAutocomplete();
- return;
- }
-
- var selectionRange = selection.getRangeAt(0);
-
- var fullWordRange = this._createRange();
- fullWordRange.setStart(originalWordPrefixRange.startContainer, originalWordPrefixRange.startOffset);
- fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset);
-
- if (prefix + selectionRange.toString() !== fullWordRange.toString())
- return;
-
- selectedIndex = (this._disableDefaultSuggestionForEmptyInput && !this.text()) ? -1 : (selectedIndex || 0);
-
- if (this._suggestBox)
- this._suggestBox.updateSuggestions(this._boxForAnchorAtStart(selection, fullWordRange), annotatedCompletions, selectedIndex, !this._isCaretAtEndOfPrompt(), this.text());
-
- var beforeRange = this._createRange();
- beforeRange.setStart(this._element, 0);
- beforeRange.setEnd(fullWordRange.startContainer, fullWordRange.startOffset);
- this._prefixRange = new WebInspector.TextRange(0, beforeRange.toString().length, 0, beforeRange.toString().length + fullWordRange.toString().length);
-
- if (selectedIndex === -1)
- return;
- this.applySuggestion(annotatedCompletions[selectedIndex].title, true);
- },
-
- /**
- * @override
- * @param {string} suggestion
- * @param {boolean=} isIntermediateSuggestion
- */
- applySuggestion: function(suggestion, isIntermediateSuggestion)
- {
- if (!this._prefixRange)
- return;
- this._currentSuggestion = suggestion;
- this._refreshGhostText();
- if (isIntermediateSuggestion)
- this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApplied);
- },
-
- /**
- * @override
- */
- acceptSuggestion: function()
- {
- this._acceptSuggestionInternal();
- },
-
- /**
- * @return {boolean}
- */
- _acceptSuggestionInternal: function()
- {
- if (!this._prefixRange)
- return false;
-
- var text = this.text();
- this._element.textContent = text.substring(0, this._prefixRange.startColumn) + this._currentSuggestion + text.substring(this._prefixRange.endColumn);
- this._setDOMSelection(this._prefixRange.startColumn + this._currentSuggestion.length, this._prefixRange.startColumn + this._currentSuggestion.length);
-
- this.clearAutocomplete();
- this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemAccepted);
-
- return true;
- },
-
- /**
- * @param {number} startColumn
- * @param {number} endColumn
- */
- _setDOMSelection: function(startColumn, endColumn)
- {
- this._element.normalize();
- var node = this._element.childNodes[0];
- if (!node || node === this._ghostTextElement)
- return;
- var range = this._createRange();
- range.setStart(node, startColumn);
- range.setEnd(node, endColumn);
- var selection = this._element.getComponentSelection();
- selection.removeAllRanges();
- selection.addRange(range);
- },
-
- /**
- * @return {boolean}
- */
- _isSuggestBoxVisible: function()
- {
- return this._suggestBox && this._suggestBox.visible();
- },
-
- /**
- * @return {boolean}
- */
- isCaretInsidePrompt: function()
- {
- var selection = this._element.getComponentSelection();
- // @see crbug.com/602541
- var selectionRange = selection && selection.rangeCount ? selection.getRangeAt(0) : null;
- if (!selectionRange || !selection.isCollapsed)
- return false;
- return selectionRange.startContainer.isSelfOrDescendant(this._element);
- },
-
- /**
- * @return {boolean}
- */
- _isCaretAtEndOfPrompt: function()
- {
- var selection = this._element.getComponentSelection();
- var selectionRange = selection && selection.rangeCount ? selection.getRangeAt(0) : null;
- if (!selectionRange || !selection.isCollapsed)
- return false;
-
- 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._ghostTextElement.isAncestor(node))
- return false;
- foundNextText = true;
- }
-
- node = node.traverseNextNode(this._element);
- }
-
- return true;
- },
-
- moveCaretToEndOfPrompt: function()
- {
- var selection = this._element.getComponentSelection();
- var selectionRange = this._createRange();
-
- var container = this._element;
- while (container.childNodes.length)
- container = container.lastChild;
- var offset = container.nodeType === Node.TEXT_NODE ? container.textContent.length : 0;
- selectionRange.setStart(container, offset);
- selectionRange.setEnd(container, offset);
-
- selection.removeAllRanges();
- selection.addRange(selectionRange);
- },
-
- /**
- * @param {!Event} event
- * @return {boolean}
- */
- tabKeyPressed: function(event)
- {
- this.acceptAutoComplete();
-
- // Consume the key.
- return true;
- },
-
- /**
- * @return {?Element}
- */
- proxyElementForTests: function()
- {
- return this._proxyElement || null;
- },
-
- __proto__: WebInspector.Object.prototype
+ ItemApplied: Symbol('text-prompt-item-applied'),
+ ItemAccepted: Symbol('text-prompt-item-accepted')
};

Powered by Google App Engine
This is Rietveld 408576698