2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * @extends {WebInspector.Object}
33 * @implements {WebInspector.SuggestBoxDelegate}
34 * @param {function(!Element, !Range, boolean, function(!Array.<string>, number=))} completions
35 * @param {string=} stopCharacters
37 WebInspector
.TextPrompt = function(completions
, stopCharacters
)
40 * @type {!Element|undefined}
43 this._proxyElementDisplay
= "inline-block";
44 this._loadCompletions
= completions
;
45 this._completionStopCharacters
= stopCharacters
|| " =:[({;,!+-*/&|^<>.";
46 this._autocompletionTimeout
= WebInspector
.TextPrompt
.DefaultAutocompletionTimeout
;
49 WebInspector
.TextPrompt
.DefaultAutocompletionTimeout
= 250;
51 WebInspector
.TextPrompt
.Events
= {
52 ItemApplied
: "text-prompt-item-applied",
53 ItemAccepted
: "text-prompt-item-accepted"
56 WebInspector
.TextPrompt
.prototype = {
58 * @param {number} timeout
60 setAutocompletionTimeout: function(timeout
)
62 this._autocompletionTimeout
= timeout
;
66 * @param {boolean} suggestBoxEnabled
68 setSuggestBoxEnabled: function(suggestBoxEnabled
)
70 this._suggestBoxEnabled
= suggestBoxEnabled
;
73 renderAsBlock: function()
75 this._proxyElementDisplay
= "block";
79 * Clients should never attach any event listeners to the |element|. Instead,
80 * they should use the result of this method to attach listeners for bubbling events.
82 * @param {!Element} element
85 attach: function(element
)
87 return this._attachInternal(element
);
91 * Clients should never attach any event listeners to the |element|. Instead,
92 * they should use the result of this method to attach listeners for bubbling events
93 * or the |blurListener| parameter to register a "blur" event listener on the |element|
94 * (since the "blur" event does not bubble.)
96 * @param {!Element} element
97 * @param {function(!Event)} blurListener
100 attachAndStartEditing: function(element
, blurListener
)
102 var proxyElement
= this._attachInternal(element
);
103 this._startEditing(blurListener
);
108 * @param {!Element} element
111 _attachInternal: function(element
)
113 if (this._proxyElement
)
114 throw "Cannot attach an attached TextPrompt";
115 this._element
= element
;
117 this._boundOnKeyDown
= this.onKeyDown
.bind(this);
118 this._boundOnInput
= this.onInput
.bind(this);
119 this._boundOnMouseWheel
= this.onMouseWheel
.bind(this);
120 this._boundSelectStart
= this._selectStart
.bind(this);
121 this._boundRemoveSuggestionAids
= this._removeSuggestionAids
.bind(this);
122 this._proxyElement
= element
.ownerDocument
.createElement("span");
123 var shadowRoot
= WebInspector
.createShadowRootWithCoreStyles(this._proxyElement
);
124 shadowRoot
.appendChild(WebInspector
.Widget
.createStyleElement("ui/textPrompt.css"));
125 this._contentElement
= shadowRoot
.createChild("div");
126 this._contentElement
.createChild("content");
127 this._proxyElement
.style
.display
= this._proxyElementDisplay
;
128 element
.parentElement
.insertBefore(this._proxyElement
, element
);
129 this._proxyElement
.appendChild(element
);
130 this._element
.classList
.add("text-prompt");
131 this._element
.addEventListener("keydown", this._boundOnKeyDown
, false);
132 this._element
.addEventListener("input", this._boundOnInput
, false);
133 this._element
.addEventListener("mousewheel", this._boundOnMouseWheel
, false);
134 this._element
.addEventListener("selectstart", this._boundSelectStart
, false);
135 this._element
.addEventListener("blur", this._boundRemoveSuggestionAids
, false);
136 this._element
.ownerDocument
.defaultView
.addEventListener("resize", this._boundRemoveSuggestionAids
, false);
138 if (this._suggestBoxEnabled
)
139 this._suggestBox
= new WebInspector
.SuggestBox(this);
141 return this._proxyElement
;
146 this._removeFromElement();
147 this._proxyElement
.parentElement
.insertBefore(this._element
, this._proxyElement
);
148 this._proxyElement
.remove();
149 delete this._proxyElement
;
150 this._element
.classList
.remove("text-prompt");
151 WebInspector
.restoreFocusFromElement(this._element
);
159 return this._element
.textContent
;
167 this._removeSuggestionAids();
169 // Append a break element instead of setting textContent to make sure the selection is inside the prompt.
170 this._element
.removeChildren();
171 this._element
.createChild("br");
173 this._element
.textContent
= x
;
176 this.moveCaretToEndOfPrompt();
177 this._element
.scrollIntoView();
180 _removeFromElement: function()
182 this.clearAutoComplete(true);
183 this._element
.removeEventListener("keydown", this._boundOnKeyDown
, false);
184 this._element
.removeEventListener("input", this._boundOnInput
, false);
185 this._element
.removeEventListener("selectstart", this._boundSelectStart
, false);
186 this._element
.removeEventListener("blur", this._boundRemoveSuggestionAids
, false);
187 this._element
.ownerDocument
.defaultView
.removeEventListener("resize", this._boundRemoveSuggestionAids
, false);
190 if (this._suggestBox
)
191 this._suggestBox
.removeFromElement();
195 * @param {function(!Event)=} blurListener
197 _startEditing: function(blurListener
)
199 this._isEditing
= true;
200 this._contentElement
.classList
.add("text-prompt-editing");
202 this._blurListener
= blurListener
;
203 this._element
.addEventListener("blur", this._blurListener
, false);
205 this._oldTabIndex
= this._element
.tabIndex
;
206 if (this._element
.tabIndex
< 0)
207 this._element
.tabIndex
= 0;
208 WebInspector
.setCurrentFocusElement(this._element
);
210 this._updateAutoComplete();
213 _stopEditing: function()
215 this._element
.tabIndex
= this._oldTabIndex
;
216 if (this._blurListener
)
217 this._element
.removeEventListener("blur", this._blurListener
, false);
218 this._contentElement
.classList
.remove("text-prompt-editing");
219 delete this._isEditing
;
222 _removeSuggestionAids: function()
224 this.clearAutoComplete();
225 this.hideSuggestBox();
228 _selectStart: function()
230 if (this._selectionTimeout
)
231 clearTimeout(this._selectionTimeout
);
233 this._removeSuggestionAids();
236 * @this {WebInspector.TextPrompt}
238 function moveBackIfOutside()
240 delete this._selectionTimeout
;
241 if (!this.isCaretInsidePrompt() && this._element
.isComponentSelectionCollapsed()) {
242 this.moveCaretToEndOfPrompt();
243 this.autoCompleteSoon();
247 this._selectionTimeout
= setTimeout(moveBackIfOutside
.bind(this), 100);
251 * @param {boolean=} force
253 _updateAutoComplete: function(force
)
255 this.clearAutoComplete();
256 this.autoCompleteSoon(force
);
260 * @param {!Event} event
262 onMouseWheel: function(event
)
264 // Subclasses can implement.
268 * @param {!Event} event
270 onKeyDown: function(event
)
273 delete this._needUpdateAutocomplete
;
275 switch (event
.keyIdentifier
) {
276 case "U+0009": // Tab
277 handled
= this.tabKeyPressed(event
);
281 this._removeSuggestionAids();
285 if (this.isCaretAtEndOfPrompt())
286 handled
= this.acceptAutoComplete();
288 this._removeSuggestionAids();
290 case "U+001B": // Esc
291 if (this.isSuggestBoxVisible()) {
292 this._removeSuggestionAids();
296 case "U+0020": // Space
297 if (event
.ctrlKey
&& !event
.metaKey
&& !event
.altKey
&& !event
.shiftKey
) {
298 this._updateAutoComplete(true);
309 if (!handled
&& this.isSuggestBoxVisible())
310 handled
= this._suggestBox
.keyPressed(event
);
313 this._needUpdateAutocomplete
= true;
320 * @param {!Event} event
322 onInput: function(event
)
324 if (this._needUpdateAutocomplete
)
325 this._updateAutoComplete();
331 acceptAutoComplete: function()
334 if (this.isSuggestBoxVisible())
335 result
= this._suggestBox
.acceptSuggestion();
337 result
= this._acceptSuggestionInternal();
343 * @param {boolean=} includeTimeout
345 clearAutoComplete: function(includeTimeout
)
347 if (includeTimeout
&& this._completeTimeout
) {
348 clearTimeout(this._completeTimeout
);
349 delete this._completeTimeout
;
351 delete this._waitingForCompletions
;
353 if (!this.autoCompleteElement
)
356 this.autoCompleteElement
.remove();
357 delete this.autoCompleteElement
;
358 delete this._userEnteredRange
;
359 delete this._userEnteredText
;
363 * @param {boolean=} force
365 autoCompleteSoon: function(force
)
367 var immediately
= this.isSuggestBoxVisible() || force
;
368 if (!this._completeTimeout
)
369 this._completeTimeout
= setTimeout(this.complete
.bind(this, force
), immediately
? 0 : this._autocompletionTimeout
);
373 * @param {boolean=} force
374 * @param {boolean=} reverse
376 complete: function(force
, reverse
)
378 this.clearAutoComplete(true);
379 var selection
= this._element
.getComponentSelection();
380 if (!selection
.rangeCount
)
383 var selectionRange
= selection
.getRangeAt(0);
386 if (!force
&& !this.isCaretAtEndOfPrompt() && !this.isSuggestBoxVisible())
388 else if (!selection
.isCollapsed
)
391 // BUG72018: Do not show suggest box if caret is followed by a non-stop character.
392 var wordSuffixRange
= selectionRange
.startContainer
.rangeOfWord(selectionRange
.endOffset
, this._completionStopCharacters
, this._element
, "forward");
393 if (wordSuffixRange
.toString().length
)
397 this.hideSuggestBox();
401 var wordPrefixRange
= selectionRange
.startContainer
.rangeOfWord(selectionRange
.startOffset
, this._completionStopCharacters
, this._element
, "backward");
402 this._waitingForCompletions
= true;
403 this._loadCompletions(/** @type {!Element} */ (this._proxyElement
), wordPrefixRange
, force
|| false, this._completionsReady
.bind(this, selection
, wordPrefixRange
, !!reverse
));
406 disableDefaultSuggestionForEmptyInput: function()
408 this._disableDefaultSuggestionForEmptyInput
= true;
412 * @param {!Selection} selection
413 * @param {!Range} textRange
415 _boxForAnchorAtStart: function(selection
, textRange
)
417 var rangeCopy
= selection
.getRangeAt(0).cloneRange();
418 var anchorElement
= createElement("span");
419 anchorElement
.textContent
= "\u200B";
420 textRange
.insertNode(anchorElement
);
421 var box
= anchorElement
.boxInWindow(window
);
422 anchorElement
.remove();
423 selection
.removeAllRanges();
424 selection
.addRange(rangeCopy
);
429 * @param {!Array.<string>} completions
430 * @param {number} wordPrefixLength
432 _buildCommonPrefix: function(completions
, wordPrefixLength
)
434 var commonPrefix
= completions
[0];
435 for (var i
= 0; i
< completions
.length
; ++i
) {
436 var completion
= completions
[i
];
437 var lastIndex
= Math
.min(commonPrefix
.length
, completion
.length
);
438 for (var j
= wordPrefixLength
; j
< lastIndex
; ++j
) {
439 if (commonPrefix
[j
] !== completion
[j
]) {
440 commonPrefix
= commonPrefix
.substr(0, j
);
450 * @suppressGlobalPropertiesCheck
452 _createRange: function()
454 return document
.createRange();
458 * @param {!Selection} selection
459 * @param {!Range} originalWordPrefixRange
460 * @param {boolean} reverse
461 * @param {!Array.<string>} completions
462 * @param {number=} selectedIndex
464 _completionsReady: function(selection
, originalWordPrefixRange
, reverse
, completions
, selectedIndex
)
466 if (!this._waitingForCompletions
|| !completions
.length
) {
467 this.hideSuggestBox();
470 delete this._waitingForCompletions
;
472 var selectionRange
= selection
.getRangeAt(0);
474 var fullWordRange
= this._createRange();
475 fullWordRange
.setStart(originalWordPrefixRange
.startContainer
, originalWordPrefixRange
.startOffset
);
476 fullWordRange
.setEnd(selectionRange
.endContainer
, selectionRange
.endOffset
);
478 if (originalWordPrefixRange
.toString() + selectionRange
.toString() !== fullWordRange
.toString())
481 selectedIndex
= (this._disableDefaultSuggestionForEmptyInput
&& !this.text()) ? -1 : (selectedIndex
|| 0);
483 this._userEnteredRange
= fullWordRange
;
484 this._userEnteredText
= fullWordRange
.toString();
486 if (this._suggestBox
)
487 this._suggestBox
.updateSuggestions(this._boxForAnchorAtStart(selection
, fullWordRange
), completions
, selectedIndex
, !this.isCaretAtEndOfPrompt(), this._userEnteredText
);
489 if (selectedIndex
=== -1)
492 var wordPrefixLength
= originalWordPrefixRange
.toString().length
;
493 this._commonPrefix
= this._buildCommonPrefix(completions
, wordPrefixLength
);
495 if (this.isCaretAtEndOfPrompt()) {
496 var completionText
= completions
[selectedIndex
];
497 var prefixText
= this._userEnteredRange
.toString();
498 var suffixText
= completionText
.substring(wordPrefixLength
);
499 this._userEnteredRange
.deleteContents();
500 this._element
.normalize();
501 var finalSelectionRange
= this._createRange();
503 var prefixTextNode
= createTextNode(prefixText
);
504 fullWordRange
.insertNode(prefixTextNode
);
506 this.autoCompleteElement
= createElementWithClass("span", "auto-complete-text");
507 this.autoCompleteElement
.textContent
= suffixText
;
509 prefixTextNode
.parentNode
.insertBefore(this.autoCompleteElement
, prefixTextNode
.nextSibling
);
511 finalSelectionRange
.setStart(prefixTextNode
, wordPrefixLength
);
512 finalSelectionRange
.setEnd(prefixTextNode
, wordPrefixLength
);
513 selection
.removeAllRanges();
514 selection
.addRange(finalSelectionRange
);
515 this.dispatchEventToListeners(WebInspector
.TextPrompt
.Events
.ItemApplied
);
519 _completeCommonPrefix: function()
521 if (!this.autoCompleteElement
|| !this._commonPrefix
|| !this._userEnteredText
|| !this._commonPrefix
.startsWith(this._userEnteredText
))
524 if (!this.isSuggestBoxVisible()) {
525 this.acceptAutoComplete();
529 this.autoCompleteElement
.textContent
= this._commonPrefix
.substring(this._userEnteredText
.length
);
530 this._acceptSuggestionInternal(true);
535 * @param {string} completionText
536 * @param {boolean=} isIntermediateSuggestion
538 applySuggestion: function(completionText
, isIntermediateSuggestion
)
540 this._applySuggestion(completionText
, isIntermediateSuggestion
);
544 * @param {string} completionText
545 * @param {boolean=} isIntermediateSuggestion
546 * @param {!Range=} originalPrefixRange
548 _applySuggestion: function(completionText
, isIntermediateSuggestion
, originalPrefixRange
)
550 var wordPrefixLength
;
551 if (originalPrefixRange
)
552 wordPrefixLength
= originalPrefixRange
.toString().length
;
554 wordPrefixLength
= this._userEnteredText
? this._userEnteredText
.length
: 0;
556 this._userEnteredRange
.deleteContents();
557 this._element
.normalize();
558 var finalSelectionRange
= this._createRange();
559 var completionTextNode
= createTextNode(completionText
);
560 this._userEnteredRange
.insertNode(completionTextNode
);
561 if (this.autoCompleteElement
) {
562 this.autoCompleteElement
.remove();
563 delete this.autoCompleteElement
;
566 if (isIntermediateSuggestion
)
567 finalSelectionRange
.setStart(completionTextNode
, wordPrefixLength
);
569 finalSelectionRange
.setStart(completionTextNode
, completionText
.length
);
571 finalSelectionRange
.setEnd(completionTextNode
, completionText
.length
);
573 var selection
= this._element
.getComponentSelection();
574 selection
.removeAllRanges();
575 selection
.addRange(finalSelectionRange
);
576 if (isIntermediateSuggestion
)
577 this.dispatchEventToListeners(WebInspector
.TextPrompt
.Events
.ItemApplied
, { itemText
: completionText
});
583 acceptSuggestion: function()
585 this._acceptSuggestionInternal();
589 * @param {boolean=} prefixAccepted
592 _acceptSuggestionInternal: function(prefixAccepted
)
594 if (!this.autoCompleteElement
|| !this.autoCompleteElement
.parentNode
)
597 var text
= this.autoCompleteElement
.textContent
;
598 var textNode
= createTextNode(text
);
599 this.autoCompleteElement
.parentNode
.replaceChild(textNode
, this.autoCompleteElement
);
600 delete this.autoCompleteElement
;
602 var finalSelectionRange
= this._createRange();
603 finalSelectionRange
.setStart(textNode
, text
.length
);
604 finalSelectionRange
.setEnd(textNode
, text
.length
);
606 var selection
= this._element
.getComponentSelection();
607 selection
.removeAllRanges();
608 selection
.addRange(finalSelectionRange
);
610 if (!prefixAccepted
) {
611 this.hideSuggestBox();
612 this.dispatchEventToListeners(WebInspector
.TextPrompt
.Events
.ItemAccepted
);
614 this.autoCompleteSoon(true);
619 hideSuggestBox: function()
621 if (this.isSuggestBoxVisible())
622 this._suggestBox
.hide();
628 isSuggestBoxVisible: function()
630 return this._suggestBox
&& this._suggestBox
.visible();
636 isCaretInsidePrompt: function()
638 return this._element
.isInsertionCaretInside();
644 isCaretAtEndOfPrompt: function()
646 var selection
= this._element
.getComponentSelection();
647 if (!selection
.rangeCount
|| !selection
.isCollapsed
)
650 var selectionRange
= selection
.getRangeAt(0);
651 var node
= selectionRange
.startContainer
;
652 if (!node
.isSelfOrDescendant(this._element
))
655 if (node
.nodeType
=== Node
.TEXT_NODE
&& selectionRange
.startOffset
< node
.nodeValue
.length
)
658 var foundNextText
= false;
660 if (node
.nodeType
=== Node
.TEXT_NODE
&& node
.nodeValue
.length
) {
661 if (foundNextText
&& (!this.autoCompleteElement
|| !this.autoCompleteElement
.isAncestor(node
)))
663 foundNextText
= true;
666 node
= node
.traverseNextNode(this._element
);
675 isCaretOnFirstLine: function()
677 var selection
= this._element
.getComponentSelection();
678 var focusNode
= selection
.focusNode
;
679 if (!focusNode
|| focusNode
.nodeType
!== Node
.TEXT_NODE
|| focusNode
.parentNode
!== this._element
)
682 if (focusNode
.textContent
.substring(0, selection
.focusOffset
).indexOf("\n") !== -1)
684 focusNode
= focusNode
.previousSibling
;
687 if (focusNode
.nodeType
!== Node
.TEXT_NODE
)
689 if (focusNode
.textContent
.indexOf("\n") !== -1)
691 focusNode
= focusNode
.previousSibling
;
700 isCaretOnLastLine: function()
702 var selection
= this._element
.getComponentSelection();
703 var focusNode
= selection
.focusNode
;
704 if (!focusNode
|| focusNode
.nodeType
!== Node
.TEXT_NODE
|| focusNode
.parentNode
!== this._element
)
707 if (focusNode
.textContent
.substring(selection
.focusOffset
).indexOf("\n") !== -1)
709 focusNode
= focusNode
.nextSibling
;
712 if (focusNode
.nodeType
!== Node
.TEXT_NODE
)
714 if (focusNode
.textContent
.indexOf("\n") !== -1)
716 focusNode
= focusNode
.nextSibling
;
722 moveCaretToEndOfPrompt: function()
724 var selection
= this._element
.getComponentSelection();
725 var selectionRange
= this._createRange();
727 var container
= this._element
;
728 while (container
.childNodes
.length
)
729 container
= container
.lastChild
;
730 var offset
= container
.nodeType
=== Node
.TEXT_NODE
? container
.textContent
.length
: 0;
731 selectionRange
.setStart(container
, offset
);
732 selectionRange
.setEnd(container
, offset
);
734 selection
.removeAllRanges();
735 selection
.addRange(selectionRange
);
739 * @param {!Event} event
742 tabKeyPressed: function(event
)
744 this._completeCommonPrefix();
753 proxyElementForTests: function()
755 return this._proxyElement
|| null;
758 __proto__
: WebInspector
.Object
.prototype
764 * @extends {WebInspector.TextPrompt}
765 * @param {function(!Element, !Range, boolean, function(!Array.<string>, number=))} completions
766 * @param {string=} stopCharacters
768 WebInspector
.TextPromptWithHistory = function(completions
, stopCharacters
)
770 WebInspector
.TextPrompt
.call(this, completions
, stopCharacters
);
773 * @type {!Array.<string>}
778 * 1-based entry in the history stack.
781 this._historyOffset
= 1;
784 WebInspector
.TextPromptWithHistory
.prototype = {
786 * @return {!Array.<string>}
788 historyData: function()
790 // FIXME: do we need to copy this?
795 * @param {!Array.<string>} data
797 setHistoryData: function(data
)
799 this._data
= [].concat(data
);
800 this._historyOffset
= 1;
804 * Pushes a committed text into the history.
805 * @param {string} text
807 pushHistoryItem: function(text
)
809 if (this._uncommittedIsTop
) {
811 delete this._uncommittedIsTop
;
814 this._historyOffset
= 1;
815 if (text
=== this._currentHistoryItem())
817 this._data
.push(text
);
821 * Pushes the current (uncommitted) text into the history.
823 _pushCurrentText: function()
825 if (this._uncommittedIsTop
)
826 this._data
.pop(); // Throw away obsolete uncommitted text.
827 this._uncommittedIsTop
= true;
828 this.clearAutoComplete(true);
829 this._data
.push(this.text());
833 * @return {string|undefined}
835 _previous: function()
837 if (this._historyOffset
> this._data
.length
)
839 if (this._historyOffset
=== 1)
840 this._pushCurrentText();
841 ++this._historyOffset
;
842 return this._currentHistoryItem();
846 * @return {string|undefined}
850 if (this._historyOffset
=== 1)
852 --this._historyOffset
;
853 return this._currentHistoryItem();
857 * @return {string|undefined}
859 _currentHistoryItem: function()
861 return this._data
[this._data
.length
- this._historyOffset
];
867 onKeyDown: function(event
)
872 switch (event
.keyIdentifier
) {
874 if (!this.isCaretOnFirstLine() || this.isSuggestBoxVisible())
876 newText
= this._previous();
880 if (!this.isCaretOnLastLine() || this.isSuggestBoxVisible())
882 newText
= this._next();
884 case "U+0050": // Ctrl+P = Previous
885 if (WebInspector
.isMac() && event
.ctrlKey
&& !event
.metaKey
&& !event
.altKey
&& !event
.shiftKey
) {
886 newText
= this._previous();
890 case "U+004E": // Ctrl+N = Next
891 if (WebInspector
.isMac() && event
.ctrlKey
&& !event
.metaKey
&& !event
.altKey
&& !event
.shiftKey
)
892 newText
= this._next();
896 if (newText
!== undefined) {
898 this.setText(newText
);
901 var firstNewlineIndex
= this.text().indexOf("\n");
902 if (firstNewlineIndex
=== -1)
903 this.moveCaretToEndOfPrompt();
905 var selection
= this._element
.getComponentSelection();
906 var selectionRange
= this._createRange();
908 selectionRange
.setStart(this._element
.firstChild
, firstNewlineIndex
);
909 selectionRange
.setEnd(this._element
.firstChild
, firstNewlineIndex
);
911 selection
.removeAllRanges();
912 selection
.addRange(selectionRange
);
919 WebInspector
.TextPrompt
.prototype.onKeyDown
.apply(this, arguments
);
922 __proto__
: WebInspector
.TextPrompt
.prototype