| Index: Source/WebCore/inspector/front-end/TextPrompt.js
|
| ===================================================================
|
| --- Source/WebCore/inspector/front-end/TextPrompt.js (revision 105250)
|
| +++ Source/WebCore/inspector/front-end/TextPrompt.js (working copy)
|
| @@ -137,7 +137,7 @@
|
|
|
| set text(x)
|
| {
|
| - this.clearAutoComplete(true);
|
| + this._removeSuggestionAids();
|
| if (!x) {
|
| // Append a break element instead of setting textContent to make sure the selection is inside the prompt.
|
| this._element.removeChildren();
|
| @@ -186,19 +186,26 @@
|
| WebInspector.markBeingEdited(this._element, false);
|
| },
|
|
|
| + _removeSuggestionAids: function()
|
| + {
|
| + this.clearAutoComplete();
|
| + this.hideSuggestBox();
|
| + },
|
| +
|
| _selectStart: function(event)
|
| {
|
| if (this._selectionTimeout)
|
| clearTimeout(this._selectionTimeout);
|
|
|
| - this.clearAutoComplete();
|
| + this._removeSuggestionAids();
|
|
|
| function moveBackIfOutside()
|
| {
|
| delete this._selectionTimeout;
|
| - if (!this.isCaretInsidePrompt() && window.getSelection().isCollapsed)
|
| + if (!this.isCaretInsidePrompt() && window.getSelection().isCollapsed) {
|
| this.moveCaretToEndOfPrompt();
|
| - this.autoCompleteSoon();
|
| + this.autoCompleteSoon();
|
| + }
|
| }
|
|
|
| this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
|
| @@ -226,28 +233,37 @@
|
| case "Down":
|
| handled = this.downKeyPressed(event);
|
| break;
|
| + case "PageUp":
|
| + handled = this.pageUpKeyPressed(event);
|
| + break;
|
| + case "PageDown":
|
| + handled = this.pageDownKeyPressed(event);
|
| + break;
|
| case "U+0009": // Tab
|
| handled = this.tabKeyPressed(event);
|
| break;
|
| case "Enter":
|
| handled = this.enterKeyPressed(event);
|
| break;
|
| + case "Left":
|
| + case "Home":
|
| + this._removeSuggestionAids();
|
| + invokeDefault = false;
|
| + break;
|
| case "Right":
|
| case "End":
|
| - if (this.isSuggestBoxVisible() && this.isCaretAtEndOfPrompt())
|
| - handled = this._suggestBox.tabKeyPressed(event);
|
| - else {
|
| + if (this.isCaretAtEndOfPrompt())
|
| handled = this.acceptAutoComplete();
|
| - if (!handled)
|
| - this.autoCompleteSoon();
|
| - }
|
| + else
|
| + this._removeSuggestionAids();
|
| + invokeDefault = false;
|
| break;
|
| case "U+001B": // Esc
|
| if (this.isSuggestBoxVisible()) {
|
| this._suggestBox.hide();
|
| handled = true;
|
| - break;
|
| }
|
| + break;
|
| case "U+0020": // Space
|
| if (this._suggestForceable && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
|
| this.defaultKeyHandler(event, true);
|
| @@ -275,9 +291,13 @@
|
|
|
| acceptAutoComplete: function()
|
| {
|
| + var result = false;
|
| if (this.isSuggestBoxVisible())
|
| - return this._suggestBox.acceptSuggestion();
|
| - return this.acceptSuggestion();
|
| + result = this._suggestBox.acceptSuggestion();
|
| + if (!result)
|
| + result = this.acceptSuggestion();
|
| +
|
| + return result;
|
| },
|
|
|
| /**
|
| @@ -348,7 +368,7 @@
|
| shouldExit = true;
|
| else if (!auto && !isEmptyInput && !selectionRange.commonAncestorContainer.isDescendant(this._element))
|
| shouldExit = true;
|
| - else if (auto && !this._suggestBox && !force && !this.isCaretAtEndOfPrompt())
|
| + else if (auto && !force && !this.isCaretAtEndOfPrompt() && !this.isSuggestBoxVisible())
|
| shouldExit = true;
|
| else if (!selection.isCollapsed)
|
| shouldExit = true;
|
| @@ -405,7 +425,7 @@
|
| this._userEnteredText = fullWordRange.toString();
|
|
|
| if (this._suggestBox)
|
| - this._suggestBox.updateSuggestions(this._boxForAnchorAtStart(selection, fullWordRange), completions);
|
| + this._suggestBox.updateSuggestions(this._boxForAnchorAtStart(selection, fullWordRange), completions, !this.isCaretAtEndOfPrompt());
|
|
|
| var wordPrefixLength = originalWordPrefixRange.toString().length;
|
|
|
| @@ -452,25 +472,27 @@
|
| }
|
|
|
| if (auto) {
|
| - this._userEnteredRange.deleteContents();
|
| - this._element.pruneEmptyTextNodes();
|
| - var finalSelectionRange = document.createRange();
|
| - var prefixText = completionText.substring(0, wordPrefixLength);
|
| - var suffixText = completionText.substring(wordPrefixLength);
|
| + if (this.isCaretAtEndOfPrompt()) {
|
| + this._userEnteredRange.deleteContents();
|
| + this._element.pruneEmptyTextNodes();
|
| + var finalSelectionRange = document.createRange();
|
| + var prefixText = completionText.substring(0, wordPrefixLength);
|
| + var suffixText = completionText.substring(wordPrefixLength);
|
|
|
| - var prefixTextNode = document.createTextNode(prefixText);
|
| - fullWordRange.insertNode(prefixTextNode);
|
| + var prefixTextNode = document.createTextNode(prefixText);
|
| + fullWordRange.insertNode(prefixTextNode);
|
|
|
| - this.autoCompleteElement = document.createElement("span");
|
| - this.autoCompleteElement.className = "auto-complete-text";
|
| - this.autoCompleteElement.textContent = suffixText;
|
| + this.autoCompleteElement = document.createElement("span");
|
| + this.autoCompleteElement.className = "auto-complete-text";
|
| + this.autoCompleteElement.textContent = suffixText;
|
|
|
| - prefixTextNode.parentNode.insertBefore(this.autoCompleteElement, prefixTextNode.nextSibling);
|
| + prefixTextNode.parentNode.insertBefore(this.autoCompleteElement, prefixTextNode.nextSibling);
|
|
|
| - finalSelectionRange.setStart(prefixTextNode, wordPrefixLength);
|
| - finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength);
|
| - selection.removeAllRanges();
|
| - selection.addRange(finalSelectionRange);
|
| + finalSelectionRange.setStart(prefixTextNode, wordPrefixLength);
|
| + finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength);
|
| + selection.removeAllRanges();
|
| + selection.addRange(finalSelectionRange);
|
| + }
|
| } else
|
| this.applySuggestion(completionText, completions.length > 1, originalWordPrefixRange);
|
| },
|
| @@ -565,7 +587,7 @@
|
| var foundNextText = false;
|
| while (node) {
|
| if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) {
|
| - if (foundNextText)
|
| + if (foundNextText && (!this.autoCompleteElement || !this.autoCompleteElement.isAncestor(node)))
|
| return false;
|
| foundNextText = true;
|
| }
|
| @@ -635,10 +657,7 @@
|
|
|
| tabKeyPressed: function(event)
|
| {
|
| - if (this.isSuggestBoxVisible())
|
| - return this._suggestBox.tabKeyPressed(event);
|
| -
|
| - this.complete(false, false, event.shiftKey);
|
| + // Just consume the key.
|
| return true;
|
| },
|
|
|
| @@ -664,7 +683,23 @@
|
| return this._suggestBox.downKeyPressed(event);
|
|
|
| return false;
|
| - }
|
| + },
|
| +
|
| + pageUpKeyPressed: function(event)
|
| + {
|
| + if (this.isSuggestBoxVisible())
|
| + return this._suggestBox.pageUpKeyPressed(event);
|
| +
|
| + return false;
|
| + },
|
| +
|
| + pageDownKeyPressed: function(event)
|
| + {
|
| + if (this.isSuggestBoxVisible())
|
| + return this._suggestBox.pageDownKeyPressed(event);
|
| +
|
| + return false;
|
| + },
|
| }
|
|
|
| WebInspector.TextPrompt.prototype.__proto__ = WebInspector.Object.prototype;
|
| @@ -987,31 +1022,59 @@
|
| return true;
|
| },
|
|
|
| - _onNextItem: function(event)
|
| + _onNextItem: function(event, isPageScroll)
|
| {
|
| var children = this.contentElement.childNodes;
|
| if (!children.length)
|
| return false;
|
|
|
| - if (this._selectedElement)
|
| - this._selectedElement = this._selectedElement.nextSibling || this.contentElement.firstChild;
|
| - else
|
| + if (!this._selectedElement)
|
| this._selectedElement = this.contentElement.firstChild;
|
| + else {
|
| + if (!isPageScroll)
|
| + this._selectedElement = this._selectedElement.nextSibling || this.contentElement.firstChild;
|
| + else {
|
| + var candidate = this._selectedElement;
|
| +
|
| + for (var itemsLeft = this._rowCountPerViewport; itemsLeft; --itemsLeft) {
|
| + if (candidate.nextSibling)
|
| + candidate = candidate.nextSibling;
|
| + else
|
| + break;
|
| + }
|
| +
|
| + this._selectedElement = candidate;
|
| + }
|
| + }
|
| this._updateSelection();
|
| this._applySuggestion(undefined, true);
|
| return true;
|
| },
|
|
|
| - _onPreviousItem: function(event)
|
| + _onPreviousItem: function(event, isPageScroll)
|
| {
|
| var children = this.contentElement.childNodes;
|
| if (!children.length)
|
| return false;
|
|
|
| - if (this._selectedElement)
|
| - this._selectedElement = this._selectedElement.previousSibling || this.contentElement.lastChild;
|
| - else
|
| + if (!this._selectedElement)
|
| this._selectedElement = this.contentElement.lastChild;
|
| + else {
|
| + if (!isPageScroll)
|
| + this._selectedElement = this._selectedElement.previousSibling || this.contentElement.lastChild;
|
| + else {
|
| + var candidate = this._selectedElement;
|
| +
|
| + for (var itemsLeft = this._rowCountPerViewport; itemsLeft; --itemsLeft) {
|
| + if (candidate.previousSibling)
|
| + candidate = candidate.previousSibling;
|
| + else
|
| + break;
|
| + }
|
| +
|
| + this._selectedElement = candidate;
|
| + }
|
| + }
|
| this._updateSelection();
|
| this._applySuggestion(undefined, true);
|
| return true;
|
| @@ -1020,14 +1083,15 @@
|
| /**
|
| * @param {AnchorBox} anchorBox
|
| * @param {Array.<string>=} completions
|
| + * @param {boolean=} canShowForSingleItem
|
| */
|
| - updateSuggestions: function(anchorBox, completions)
|
| + updateSuggestions: function(anchorBox, completions, canShowForSingleItem)
|
| {
|
| if (this._suggestTimeout) {
|
| clearTimeout(this._suggestTimeout);
|
| delete this._suggestTimeout;
|
| }
|
| - this._completionsReady(anchorBox, completions);
|
| + this._completionsReady(anchorBox, completions, canShowForSingleItem);
|
| },
|
|
|
| _onItemMouseDown: function(text, event)
|
| @@ -1055,14 +1119,11 @@
|
| return element;
|
| },
|
|
|
| - _updateItems: function(items)
|
| + /**
|
| + * @param {boolean=} canShowForSingleItem
|
| + */
|
| + _updateItems: function(items, canShowForSingleItem)
|
| {
|
| - var children = this.contentElement.children;
|
| - this._selectedIndex = Math.min(children.length - 1, this._selectedIndex);
|
| - var selectedItemText = this._selectedIndex >= 0 ? children[this._selectedIndex].textContent : null;
|
| - var itemIndex = 0;
|
| - var child = this.contentElement.firstChild;
|
| - var childText = child ? child.textContent : null;
|
| this.contentElement.removeChildren();
|
|
|
| var userEnteredText = this._textPrompt._userEnteredText;
|
| @@ -1072,7 +1133,7 @@
|
| this.contentElement.appendChild(currentItemElement);
|
| }
|
|
|
| - this._selectedElement = this.contentElement.firstChild;
|
| + this._selectedElement = canShowForSingleItem ? this.contentElement.firstChild : null;
|
| this._updateSelection();
|
| },
|
|
|
| @@ -1090,21 +1151,41 @@
|
| },
|
|
|
| /**
|
| - * @param {AnchorBox} anchorBox
|
| * @param {Array.<string>=} completions
|
| + * @param {boolean=} canShowForSingleItem
|
| */
|
| - _completionsReady: function(anchorBox, completions)
|
| + _canShowBox: function(completions, canShowForSingleItem)
|
| {
|
| - if (!completions || !completions.length) {
|
| - this.hide()
|
| + if (!completions || !completions.length)
|
| + return false;
|
| +
|
| + if (completions.length > 1)
|
| + return true;
|
| +
|
| + // Do not show a single suggestion if it is the same as user-entered prefix, even if allowed to show single-item suggest boxes.
|
| + return canShowForSingleItem && completions[0] !== this._textPrompt._userEnteredText;
|
| + },
|
| +
|
| + _rememberRowCountPerViewport: function()
|
| + {
|
| + if (!this.contentElement.firstChild)
|
| return;
|
| - }
|
|
|
| - this._updateItems(completions);
|
| - this._updateBoxPosition(anchorBox);
|
| - if (this.contentElement.children.length && this.contentElement.children.length > 1) {
|
| - // Will not be shown if a sole suggestion is equal to the user input.
|
| + this._rowCountPerViewport = Math.floor(this.containerElement.offsetHeight / this.contentElement.firstChild.offsetHeight);
|
| + },
|
| +
|
| + /**
|
| + * @param {AnchorBox} anchorBox
|
| + * @param {Array.<string>=} completions
|
| + * @param {boolean=} canShowForSingleItem
|
| + */
|
| + _completionsReady: function(anchorBox, completions, canShowForSingleItem)
|
| + {
|
| + if (this._canShowBox(completions, canShowForSingleItem)) {
|
| + this._updateItems(completions, canShowForSingleItem);
|
| + this._updateBoxPosition(anchorBox);
|
| this._element.addStyleClass("visible");
|
| + this._rememberRowCountPerViewport();
|
| } else
|
| this.hide();
|
| },
|
| @@ -1119,10 +1200,24 @@
|
| return this._onNextItem(event);
|
| },
|
|
|
| + pageUpKeyPressed: function(event)
|
| + {
|
| + return this._onPreviousItem(event, true);
|
| + },
|
| +
|
| + pageDownKeyPressed: function(event)
|
| + {
|
| + return this._onNextItem(event, true);
|
| + },
|
| +
|
| enterKeyPressed: function(event)
|
| {
|
| + var hasSelectedItem = !!this._selectedElement;
|
| this.acceptSuggestion();
|
| - return true;
|
| +
|
| + // Report the event as non-handled if there is no selected item,
|
| + // to commit the input or handle it otherwise.
|
| + return hasSelectedItem;
|
| },
|
|
|
| tabKeyPressed: function(event)
|
|
|