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

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

Issue 2439223002: DevTools: Use grey hint text for applied suggestion in TextPrompt (Closed)
Patch Set: Was removing ghostText twice 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 unified diff | Download patch
« no previous file with comments | « third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt-hint-expected.txt ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 23 matching lines...) Expand all
34 */ 34 */
35 WebInspector.TextPrompt = function() 35 WebInspector.TextPrompt = function()
36 { 36 {
37 /** 37 /**
38 * @type {!Element|undefined} 38 * @type {!Element|undefined}
39 */ 39 */
40 this._proxyElement; 40 this._proxyElement;
41 this._proxyElementDisplay = "inline-block"; 41 this._proxyElementDisplay = "inline-block";
42 this._autocompletionTimeout = WebInspector.TextPrompt.DefaultAutocompletionT imeout; 42 this._autocompletionTimeout = WebInspector.TextPrompt.DefaultAutocompletionT imeout;
43 this._title = ""; 43 this._title = "";
44 this._prefixRange = null;
44 this._previousText = ""; 45 this._previousText = "";
45 this._currentSuggestion = ""; 46 this._currentSuggestion = "";
46 this._completionRequestId = 0; 47 this._completionRequestId = 0;
48 this._ghostTextElement = createElementWithClass("span", "auto-complete-text" );
47 }; 49 };
48 50
49 WebInspector.TextPrompt.DefaultAutocompletionTimeout = 250; 51 WebInspector.TextPrompt.DefaultAutocompletionTimeout = 250;
50 52
51 /** @enum {symbol} */ 53 /** @enum {symbol} */
52 WebInspector.TextPrompt.Events = { 54 WebInspector.TextPrompt.Events = {
53 ItemApplied: Symbol("text-prompt-item-applied"), 55 ItemApplied: Symbol("text-prompt-item-applied"),
54 ItemAccepted: Symbol("text-prompt-item-accepted") 56 ItemAccepted: Symbol("text-prompt-item-accepted")
55 }; 57 };
56 58
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 this._proxyElement.appendChild(element); 140 this._proxyElement.appendChild(element);
139 this._element.classList.add("text-prompt"); 141 this._element.classList.add("text-prompt");
140 this._element.addEventListener("keydown", this._boundOnKeyDown, false); 142 this._element.addEventListener("keydown", this._boundOnKeyDown, false);
141 this._element.addEventListener("input", this._boundOnInput, false); 143 this._element.addEventListener("input", this._boundOnInput, false);
142 this._element.addEventListener("mousewheel", this._boundOnMouseWheel, fa lse); 144 this._element.addEventListener("mousewheel", this._boundOnMouseWheel, fa lse);
143 this._element.addEventListener("selectstart", this._boundClearAutocomple te, false); 145 this._element.addEventListener("selectstart", this._boundClearAutocomple te, false);
144 this._element.addEventListener("blur", this._boundClearAutocomplete, fal se); 146 this._element.addEventListener("blur", this._boundClearAutocomplete, fal se);
145 this._element.ownerDocument.defaultView.addEventListener("resize", this. _boundClearAutocomplete, false); 147 this._element.ownerDocument.defaultView.addEventListener("resize", this. _boundClearAutocomplete, false);
146 148
147 if (this._suggestBoxEnabled) 149 if (this._suggestBoxEnabled)
148 this._suggestBox = new WebInspector.SuggestBox(this); 150 this._suggestBox = new WebInspector.SuggestBox(this, 20, true);
149 151
150 if (this._title) 152 if (this._title)
151 this._proxyElement.title = this._title; 153 this._proxyElement.title = this._title;
152 154
153 return this._proxyElement; 155 return this._proxyElement;
154 }, 156 },
155 157
156 detach: function() 158 detach: function()
157 { 159 {
158 this._removeFromElement(); 160 this._removeFromElement();
(...skipping 11 matching lines...) Expand all
170 { 172 {
171 return this._element.textContent; 173 return this._element.textContent;
172 }, 174 },
173 175
174 /** 176 /**
175 * @return {string} 177 * @return {string}
176 */ 178 */
177 text: function() 179 text: function()
178 { 180 {
179 var text = this.textWithCurrentSuggestion(); 181 var text = this.textWithCurrentSuggestion();
180 if (this._ghostTextElement) { 182 if (this._ghostTextElement.parentNode) {
181 var addition = this._ghostTextElement.textContent; 183 var addition = this._ghostTextElement.textContent;
182 text = text.substring(0, text.length - addition.length); 184 text = text.substring(0, text.length - addition.length);
183 } 185 }
184 return text; 186 return text;
185 }, 187 },
186 188
187 /** 189 /**
188 * @param {string} x 190 * @param {string} x
189 */ 191 */
190 setText: function(x) 192 setText: function(x)
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 onMouseWheel: function(event) 271 onMouseWheel: function(event)
270 { 272 {
271 // Subclasses can implement. 273 // Subclasses can implement.
272 }, 274 },
273 275
274 /** 276 /**
275 * @param {!Event} event 277 * @param {!Event} event
276 */ 278 */
277 onKeyDown: function(event) 279 onKeyDown: function(event)
278 { 280 {
279 if (isEnterKey(event))
280 return;
281
282 var handled = false; 281 var handled = false;
283 282
284 switch (event.key) { 283 switch (event.key) {
285 case "Tab": 284 case "Tab":
286 handled = this.tabKeyPressed(event); 285 handled = this.tabKeyPressed(event);
287 break; 286 break;
288 case "ArrowLeft": 287 case "ArrowLeft":
289 case "Home": 288 case "Home":
290 this.clearAutocomplete(); 289 this.clearAutocomplete();
291 break; 290 break;
(...skipping 30 matching lines...) Expand all
322 event.consume(true); 321 event.consume(true);
323 }, 322 },
324 323
325 /** 324 /**
326 * @param {!Event} event 325 * @param {!Event} event
327 */ 326 */
328 onInput: function(event) 327 onInput: function(event)
329 { 328 {
330 var text = this.text(); 329 var text = this.text();
331 var hasCommonPrefix = text.startsWith(this._previousText) || this._previ ousText.startsWith(text); 330 var hasCommonPrefix = text.startsWith(this._previousText) || this._previ ousText.startsWith(text);
332 if (this._ghostTextElement && hasCommonPrefix) 331 if (this._prefixRange && hasCommonPrefix)
333 this._ghostTextElement.textContent = this._currentSuggestion.substri ng(text.length); 332 this._prefixRange.endColumn += text.length - this._previousText.leng th;
334 else 333 this._refreshGhostText();
335 this._clearGhostTextElement();
336 this._previousText = text; 334 this._previousText = text;
337 335
338 this.autoCompleteSoon(); 336 this.autoCompleteSoon();
339 }, 337 },
340 338
341 /** 339 /**
342 * @return {boolean} 340 * @return {boolean}
343 */ 341 */
344 acceptAutoComplete: function() 342 acceptAutoComplete: function()
345 { 343 {
346 var result = false; 344 var result = false;
347 if (this._isSuggestBoxVisible()) 345 if (this._isSuggestBoxVisible())
348 result = this._suggestBox.acceptSuggestion(); 346 result = this._suggestBox.acceptSuggestion();
349 if (!result) 347 if (!result)
350 result = this._acceptSuggestionInternal(); 348 result = this._acceptSuggestionInternal();
351 349
352 return result; 350 return result;
353 }, 351 },
354 352
355 clearAutocomplete: function() 353 clearAutocomplete: function()
356 { 354 {
357 if (this._isSuggestBoxVisible()) 355 if (this._isSuggestBoxVisible())
358 this._suggestBox.hide(); 356 this._suggestBox.hide();
359 this._clearGhostTextElement(); 357 this._clearAutocompleteTimeout();
358 this._prefixRange = null;
359 this._refreshGhostText();
360 }, 360 },
361 361
362 _clearGhostTextElement: function() 362 _refreshGhostText: function()
363 { 363 {
364 this._clearAutocompleteTimeout(); 364 if (this._prefixRange && this._isCaretAtEndOfPrompt()) {
365 365 this._ghostTextElement.textContent = this._currentSuggestion.substri ng(this._prefixRange.endColumn - this._prefixRange.startColumn);
366 if (!this._ghostTextElement) 366 this._element.appendChild(this._ghostTextElement);
367 return; 367 } else {
368 368 this._ghostTextElement.remove();
369 this._ghostTextElement.remove(); 369 }
370 delete this._ghostTextElement;
371 delete this._userEnteredRange;
372 delete this._userEnteredText;
373 }, 370 },
374 371
375 _clearAutocompleteTimeout: function() 372 _clearAutocompleteTimeout: function()
376 { 373 {
377 if (this._completeTimeout) { 374 if (this._completeTimeout) {
378 clearTimeout(this._completeTimeout); 375 clearTimeout(this._completeTimeout);
379 delete this._completeTimeout; 376 delete this._completeTimeout;
380 } 377 }
381 this._completionRequestId++; 378 this._completionRequestId++;
382 }, 379 },
(...skipping 22 matching lines...) Expand all
405 402
406 var shouldExit; 403 var shouldExit;
407 404
408 if (!force && !this._isCaretAtEndOfPrompt() && !this._isSuggestBoxVisibl e()) 405 if (!force && !this._isCaretAtEndOfPrompt() && !this._isSuggestBoxVisibl e())
409 shouldExit = true; 406 shouldExit = true;
410 else if (!selection.isCollapsed) 407 else if (!selection.isCollapsed)
411 shouldExit = true; 408 shouldExit = true;
412 else if (!force) { 409 else if (!force) {
413 // BUG72018: Do not show suggest box if caret is followed by a non-s top character. 410 // BUG72018: Do not show suggest box if caret is followed by a non-s top character.
414 var wordSuffixRange = selectionRange.startContainer.rangeOfWord(sele ctionRange.endOffset, this._completionStopCharacters, this._element, "forward"); 411 var wordSuffixRange = selectionRange.startContainer.rangeOfWord(sele ctionRange.endOffset, this._completionStopCharacters, this._element, "forward");
415 var autocompleteTextLength = (this._ghostTextElement && this._ghostT extElement.parentNode) ? this._ghostTextElement.textContent.length : 0; 412 var autocompleteTextLength = this._ghostTextElement.parentNode ? thi s._ghostTextElement.textContent.length : 0;
416 if (wordSuffixRange.toString().length !== autocompleteTextLength) 413 if (wordSuffixRange.toString().length !== autocompleteTextLength)
417 shouldExit = true; 414 shouldExit = true;
418 } 415 }
419 if (shouldExit) { 416 if (shouldExit) {
420 this.clearAutocomplete(); 417 this.clearAutocomplete();
421 return; 418 return;
422 } 419 }
423 420
424 var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectio nRange.startOffset, this._completionStopCharacters, this._element, "backward"); 421 var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectio nRange.startOffset, this._completionStopCharacters, this._element, "backward");
425 this._loadCompletions(/** @type {!Element} */ (this._proxyElement), word PrefixRange, force || false, this._completionsReady.bind(this, ++this._completio nRequestId, selection, wordPrefixRange, !!reverse, !!force)); 422 this._loadCompletions(/** @type {!Element} */ (this._proxyElement), word PrefixRange, force || false, this._completionsReady.bind(this, ++this._completio nRequestId, selection, wordPrefixRange, !!reverse, !!force));
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 499
503 var fullWordRange = this._createRange(); 500 var fullWordRange = this._createRange();
504 fullWordRange.setStart(originalWordPrefixRange.startContainer, originalW ordPrefixRange.startOffset); 501 fullWordRange.setStart(originalWordPrefixRange.startContainer, originalW ordPrefixRange.startOffset);
505 fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffs et); 502 fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffs et);
506 503
507 if (prefix + selectionRange.toString() !== fullWordRange.toString()) 504 if (prefix + selectionRange.toString() !== fullWordRange.toString())
508 return; 505 return;
509 506
510 selectedIndex = (this._disableDefaultSuggestionForEmptyInput && !this.te xt()) ? -1 : (selectedIndex || 0); 507 selectedIndex = (this._disableDefaultSuggestionForEmptyInput && !this.te xt()) ? -1 : (selectedIndex || 0);
511 508
512 this._userEnteredRange = fullWordRange; 509 if (this._suggestBox)
513 this._userEnteredText = fullWordRange.toString(); 510 this._suggestBox.updateSuggestions(this._boxForAnchorAtStart(selecti on, fullWordRange), annotatedCompletions, selectedIndex, !this._isCaretAtEndOfPr ompt(), this.text());
514 511
515 if (this._suggestBox) 512 var beforeRange = this._createRange();
516 this._suggestBox.updateSuggestions(this._boxForAnchorAtStart(selecti on, fullWordRange), annotatedCompletions, selectedIndex, !this._isCaretAtEndOfPr ompt(), this._userEnteredText); 513 beforeRange.setStart(this._element, 0);
514 beforeRange.setEnd(fullWordRange.startContainer, fullWordRange.startOffs et);
515 this._prefixRange = new WebInspector.TextRange(0, beforeRange.toString() .length, 0, beforeRange.toString().length + fullWordRange.toString().length);
517 516
518 if (selectedIndex === -1) 517 if (selectedIndex === -1)
519 return; 518 return;
520 519 this.applySuggestion(annotatedCompletions[selectedIndex].title, true);
521 var wordPrefixLength = originalWordPrefixRange.toString().length;
522
523 if (this._isCaretAtEndOfPrompt()) {
524 var suggestion = annotatedCompletions[selectedIndex].title;
525 var prefixText = this._userEnteredRange.toString();
526 var suffixText = suggestion.substring(wordPrefixLength);
527 this._userEnteredRange.deleteContents();
528 this._element.normalize();
529 var finalSelectionRange = this._createRange();
530
531 var prefixTextNode = createTextNode(prefixText);
532 fullWordRange.insertNode(prefixTextNode);
533
534 if (!this._ghostTextElement)
535 this._ghostTextElement = createElementWithClass("span", "auto-co mplete-text");
536 this._ghostTextElement.textContent = suffixText;
537 this._currentSuggestion = suggestion;
538
539 prefixTextNode.parentNode.insertBefore(this._ghostTextElement, prefi xTextNode.nextSibling);
540
541 finalSelectionRange.setStart(prefixTextNode, wordPrefixLength);
542 finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength);
543 selection.removeAllRanges();
544 selection.addRange(finalSelectionRange);
545 this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApp lied);
546 }
547 }, 520 },
548 521
549 /** 522 /**
550 * @override 523 * @override
551 * @param {string} suggestion 524 * @param {string} suggestion
552 * @param {boolean=} isIntermediateSuggestion 525 * @param {boolean=} isIntermediateSuggestion
553 */ 526 */
554 applySuggestion: function(suggestion, isIntermediateSuggestion) 527 applySuggestion: function(suggestion, isIntermediateSuggestion)
555 { 528 {
556 this._applySuggestion(suggestion, isIntermediateSuggestion); 529 if (!this._prefixRange)
530 return;
531 this._currentSuggestion = suggestion;
532 this._refreshGhostText();
533 if (isIntermediateSuggestion)
534 this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApp lied);
557 }, 535 },
558 536
559 /** 537 /**
560 * @param {string} suggestion
561 * @param {boolean=} isIntermediateSuggestion
562 */
563 _applySuggestion: function(suggestion, isIntermediateSuggestion)
564 {
565 if (!this._userEnteredRange) {
566 // We could have already cleared autocompletion range by the time th is is called. (crbug.com/587683)
567 return;
568 }
569
570 var wordPrefixLength = this._userEnteredText ? this._userEnteredText.len gth : 0;
571
572 this._userEnteredRange.deleteContents();
573 this._element.normalize();
574 var finalSelectionRange = this._createRange();
575 var suggestionNode = createTextNode(suggestion);
576 this._userEnteredRange.insertNode(suggestionNode);
577 if (this._ghostTextElement) {
578 this._ghostTextElement.remove();
579 delete this._ghostTextElement;
580 }
581
582 if (isIntermediateSuggestion)
583 finalSelectionRange.setStart(suggestionNode, wordPrefixLength);
584 else
585 finalSelectionRange.setStart(suggestionNode, suggestion.length);
586
587 finalSelectionRange.setEnd(suggestionNode, suggestion.length);
588
589 var selection = this._element.getComponentSelection();
590 selection.removeAllRanges();
591 selection.addRange(finalSelectionRange);
592 if (isIntermediateSuggestion)
593 this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApp lied, { itemText: suggestion });
594 },
595
596 /**
597 * @override 538 * @override
598 */ 539 */
599 acceptSuggestion: function() 540 acceptSuggestion: function()
600 { 541 {
601 this._acceptSuggestionInternal(); 542 this._acceptSuggestionInternal();
602 }, 543 },
603 544
604 /** 545 /**
605 * @return {boolean} 546 * @return {boolean}
606 */ 547 */
607 _acceptSuggestionInternal: function() 548 _acceptSuggestionInternal: function()
608 { 549 {
609 if (!this._ghostTextElement || !this._ghostTextElement.parentNode) 550 if (!this._prefixRange)
610 return false; 551 return false;
611 552
612 var text = this._ghostTextElement.textContent; 553 var text = this.text();
613 var textNode = createTextNode(text); 554 this._element.textContent = text.substring(0, this._prefixRange.startCol umn) + this._currentSuggestion + text.substring(this._prefixRange.endColumn);
614 this._ghostTextElement.parentNode.replaceChild(textNode, this._ghostText Element); 555 this._setDOMSelection(this._prefixRange.startColumn + this._currentSugge stion.length, this._prefixRange.startColumn + this._currentSuggestion.length);
615 delete this._ghostTextElement;
616
617 var finalSelectionRange = this._createRange();
618 finalSelectionRange.setStart(textNode, text.length);
619 finalSelectionRange.setEnd(textNode, text.length);
620
621 var selection = this._element.getComponentSelection();
622 selection.removeAllRanges();
623 selection.addRange(finalSelectionRange);
624 556
625 this.clearAutocomplete(); 557 this.clearAutocomplete();
626 this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemAccepte d); 558 this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemAccepte d);
627 559
628 return true; 560 return true;
629 }, 561 },
630 562
631 /** 563 /**
564 * @param {number} startColumn
565 * @param {number} endColumn
566 */
567 _setDOMSelection: function(startColumn, endColumn)
568 {
569 this._element.normalize();
570 var node = this._element.childNodes[0];
571 if (!node || node === this._ghostTextElement)
572 return;
573 var range = this._createRange();
574 range.setStart(node, startColumn);
575 range.setEnd(node, endColumn);
576 var selection = this._element.getComponentSelection();
577 selection.removeAllRanges();
578 selection.addRange(range);
579 },
580
581 /**
632 * @return {boolean} 582 * @return {boolean}
633 */ 583 */
634 _isSuggestBoxVisible: function() 584 _isSuggestBoxVisible: function()
635 { 585 {
636 return this._suggestBox && this._suggestBox.visible(); 586 return this._suggestBox && this._suggestBox.visible();
637 }, 587 },
638 588
639 /** 589 /**
640 * @return {boolean} 590 * @return {boolean}
641 */ 591 */
(...skipping 20 matching lines...) Expand all
662 var node = selectionRange.startContainer; 612 var node = selectionRange.startContainer;
663 if (!node.isSelfOrDescendant(this._element)) 613 if (!node.isSelfOrDescendant(this._element))
664 return false; 614 return false;
665 615
666 if (node.nodeType === Node.TEXT_NODE && selectionRange.startOffset < nod e.nodeValue.length) 616 if (node.nodeType === Node.TEXT_NODE && selectionRange.startOffset < nod e.nodeValue.length)
667 return false; 617 return false;
668 618
669 var foundNextText = false; 619 var foundNextText = false;
670 while (node) { 620 while (node) {
671 if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) { 621 if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) {
672 if (foundNextText && (!this._ghostTextElement || !this._ghostTex tElement.isAncestor(node))) 622 if (foundNextText && !this._ghostTextElement.isAncestor(node))
673 return false; 623 return false;
674 foundNextText = true; 624 foundNextText = true;
675 } 625 }
676 626
677 node = node.traverseNextNode(this._element); 627 node = node.traverseNextNode(this._element);
678 } 628 }
679 629
680 return true; 630 return true;
681 }, 631 },
682 632
(...skipping 28 matching lines...) Expand all
711 /** 661 /**
712 * @return {?Element} 662 * @return {?Element}
713 */ 663 */
714 proxyElementForTests: function() 664 proxyElementForTests: function()
715 { 665 {
716 return this._proxyElement || null; 666 return this._proxyElement || null;
717 }, 667 },
718 668
719 __proto__: WebInspector.Object.prototype 669 __proto__: WebInspector.Object.prototype
720 }; 670 };
OLDNEW
« no previous file with comments | « third_party/WebKit/LayoutTests/http/tests/inspector-unit/text-prompt-hint-expected.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698