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

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

Issue 2285993002: DevTools: Fix flickering hint when typing in TextPrompt (Closed)
Patch Set: fix test Created 4 years, 2 months 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 27 matching lines...) Expand all
38 { 38 {
39 /** 39 /**
40 * @type {!Element|undefined} 40 * @type {!Element|undefined}
41 */ 41 */
42 this._proxyElement; 42 this._proxyElement;
43 this._proxyElementDisplay = "inline-block"; 43 this._proxyElementDisplay = "inline-block";
44 this._loadCompletions = completions; 44 this._loadCompletions = completions;
45 this._completionStopCharacters = stopCharacters || " =:[({;,!+-*/&|^<>."; 45 this._completionStopCharacters = stopCharacters || " =:[({;,!+-*/&|^<>.";
46 this._autocompletionTimeout = WebInspector.TextPrompt.DefaultAutocompletionT imeout; 46 this._autocompletionTimeout = WebInspector.TextPrompt.DefaultAutocompletionT imeout;
47 this._title = ""; 47 this._title = "";
48 this._previousText = "";
49 this._currentHintText = "";
48 this._completionRequestId = 0; 50 this._completionRequestId = 0;
49 } 51 }
50 52
51 WebInspector.TextPrompt.DefaultAutocompletionTimeout = 250; 53 WebInspector.TextPrompt.DefaultAutocompletionTimeout = 250;
52 54
53 /** @enum {symbol} */ 55 /** @enum {symbol} */
54 WebInspector.TextPrompt.Events = { 56 WebInspector.TextPrompt.Events = {
55 ItemApplied: Symbol("text-prompt-item-applied"), 57 ItemApplied: Symbol("text-prompt-item-applied"),
56 ItemAccepted: Symbol("text-prompt-item-accepted") 58 ItemAccepted: Symbol("text-prompt-item-accepted")
57 }; 59 };
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 setText: function(x) 185 setText: function(x)
184 { 186 {
185 this.clearAutocomplete(); 187 this.clearAutocomplete();
186 if (!x) { 188 if (!x) {
187 // Append a break element instead of setting textContent to make sur e the selection is inside the prompt. 189 // Append a break element instead of setting textContent to make sur e the selection is inside the prompt.
188 this._element.removeChildren(); 190 this._element.removeChildren();
189 this._element.createChild("br"); 191 this._element.createChild("br");
190 } else { 192 } else {
191 this._element.textContent = x; 193 this._element.textContent = x;
192 } 194 }
195 this._previousText = this.userEnteredText();
193 196
194 this.moveCaretToEndOfPrompt(); 197 this.moveCaretToEndOfPrompt();
195 this._element.scrollIntoView(); 198 this._element.scrollIntoView();
196 }, 199 },
197 200
198 /** 201 /**
199 * @return {string} 202 * @return {string}
200 */ 203 */
201 title: function() 204 title: function()
202 { 205 {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 this._contentElement.classList.add("text-prompt-editing"); 239 this._contentElement.classList.add("text-prompt-editing");
237 if (blurListener) { 240 if (blurListener) {
238 this._blurListener = blurListener; 241 this._blurListener = blurListener;
239 this._element.addEventListener("blur", this._blurListener, false); 242 this._element.addEventListener("blur", this._blurListener, false);
240 } 243 }
241 this._oldTabIndex = this._element.tabIndex; 244 this._oldTabIndex = this._element.tabIndex;
242 if (this._element.tabIndex < 0) 245 if (this._element.tabIndex < 0)
243 this._element.tabIndex = 0; 246 this._element.tabIndex = 0;
244 this._focusRestorer = new WebInspector.ElementFocusRestorer(this._elemen t); 247 this._focusRestorer = new WebInspector.ElementFocusRestorer(this._elemen t);
245 if (!this.text()) 248 if (!this.text())
246 this._updateAutoComplete(); 249 this.autoCompleteSoon();
247 }, 250 },
248 251
249 _stopEditing: function() 252 _stopEditing: function()
250 { 253 {
251 this._element.tabIndex = this._oldTabIndex; 254 this._element.tabIndex = this._oldTabIndex;
252 if (this._blurListener) 255 if (this._blurListener)
253 this._element.removeEventListener("blur", this._blurListener, false) ; 256 this._element.removeEventListener("blur", this._blurListener, false) ;
254 this._contentElement.classList.remove("text-prompt-editing"); 257 this._contentElement.classList.remove("text-prompt-editing");
255 delete this._isEditing; 258 delete this._isEditing;
256 }, 259 },
(...skipping 13 matching lines...) Expand all
270 delete this._selectionTimeout; 273 delete this._selectionTimeout;
271 if (!this.isCaretInsidePrompt() && this._element.isComponentSelectio nCollapsed()) { 274 if (!this.isCaretInsidePrompt() && this._element.isComponentSelectio nCollapsed()) {
272 this.moveCaretToEndOfPrompt(); 275 this.moveCaretToEndOfPrompt();
273 this.autoCompleteSoon(); 276 this.autoCompleteSoon();
274 } 277 }
275 } 278 }
276 279
277 this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); 280 this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
278 }, 281 },
279 282
280 /**
281 * @param {boolean=} force
282 */
283 _updateAutoComplete: function(force)
284 {
285 this._clearAutocompleteElement();
286 this.autoCompleteSoon(force);
287 },
288 283
289 /** 284 /**
290 * @param {!Event} event 285 * @param {!Event} event
291 */ 286 */
292 onMouseWheel: function(event) 287 onMouseWheel: function(event)
293 { 288 {
294 // Subclasses can implement. 289 // Subclasses can implement.
295 }, 290 },
296 291
297 /** 292 /**
298 * @param {!Event} event 293 * @param {!Event} event
299 */ 294 */
300 onKeyDown: function(event) 295 onKeyDown: function(event)
301 { 296 {
302 if (isEnterKey(event)) 297 if (isEnterKey(event))
303 return; 298 return;
304 299
305 var handled = false; 300 var handled = false;
306 delete this._needUpdateAutocomplete;
307 301
308 switch (event.key) { 302 switch (event.key) {
309 case "Tab": 303 case "Tab":
310 handled = this.tabKeyPressed(event); 304 handled = this.tabKeyPressed(event);
311 break; 305 break;
312 case "ArrowLeft": 306 case "ArrowLeft":
313 case "Home": 307 case "Home":
314 this.clearAutocomplete(); 308 this.clearAutocomplete();
315 break; 309 break;
316 case "ArrowRight": 310 case "ArrowRight":
317 case "End": 311 case "End":
318 if (this.isCaretAtEndOfPrompt()) 312 if (this.isCaretAtEndOfPrompt())
319 handled = this.acceptAutoComplete(); 313 handled = this.acceptAutoComplete();
320 else 314 else
321 this.clearAutocomplete(); 315 this.clearAutocomplete();
322 break; 316 break;
323 case "Escape": 317 case "Escape":
324 if (this.isSuggestBoxVisible()) { 318 if (this.isSuggestBoxVisible()) {
325 this.clearAutocomplete(); 319 this.clearAutocomplete();
326 handled = true; 320 handled = true;
327 } 321 }
328 break; 322 break;
329 case " ": // Space 323 case " ": // Space
330 if (event.ctrlKey && !event.metaKey && !event.altKey && !event.shift Key) { 324 if (event.ctrlKey && !event.metaKey && !event.altKey && !event.shift Key) {
331 this._updateAutoComplete(true); 325 this.autoCompleteSoon(true);
332 handled = true; 326 handled = true;
333 } 327 }
334 break; 328 break;
335 case "Alt": 329 case "Alt":
336 case "Meta": 330 case "Meta":
337 case "Shift": 331 case "Shift":
338 case "Control": 332 case "Control":
339 break; 333 break;
340 } 334 }
341 335
342 if (!handled && this.isSuggestBoxVisible()) 336 if (!handled && this.isSuggestBoxVisible())
343 handled = this._suggestBox.keyPressed(event); 337 handled = this._suggestBox.keyPressed(event);
344 338
345 if (!handled)
346 this._needUpdateAutocomplete = true;
347
348 if (handled) 339 if (handled)
349 event.consume(true); 340 event.consume(true);
350 }, 341 },
351 342
352 /** 343 /**
353 * @param {!Event} event 344 * @param {!Event} event
354 */ 345 */
355 onInput: function(event) 346 onInput: function(event)
356 { 347 {
357 if (this._needUpdateAutocomplete) 348 var text = this.userEnteredText();
358 this._updateAutoComplete(); 349 var hasCommonPrefix = text.startsWith(this._previousText) || this._previ ousText.startsWith(text);
350 if (this._autocompleteElement && hasCommonPrefix)
351 this._autocompleteElement.textContent = this._currentHintText.substr ing(text.length);
352 else
353 this._clearAutocompleteElement();
354 this._previousText = text;
355
356 this.autoCompleteSoon();
359 }, 357 },
360 358
361 /** 359 /**
362 * @return {boolean} 360 * @return {boolean}
363 */ 361 */
364 acceptAutoComplete: function() 362 acceptAutoComplete: function()
365 { 363 {
366 var result = false; 364 var result = false;
367 if (this.isSuggestBoxVisible()) 365 if (this.isSuggestBoxVisible())
368 result = this._suggestBox.acceptSuggestion(); 366 result = this._suggestBox.acceptSuggestion();
369 if (!result) 367 if (!result)
370 result = this._acceptSuggestionInternal(); 368 result = this._acceptSuggestionInternal();
371 369
372 return result; 370 return result;
373 }, 371 },
374 372
375 clearAutocomplete: function() 373 clearAutocomplete: function()
376 { 374 {
377 if (this.isSuggestBoxVisible()) 375 if (this.isSuggestBoxVisible())
378 this._suggestBox.hide(); 376 this._suggestBox.hide();
379 this._clearAutocompleteElement(); 377 this._clearAutocompleteElement();
380 }, 378 },
381 379
382 _clearAutocompleteElement: function() 380 _clearAutocompleteElement: function()
383 { 381 {
384 if (this._completeTimeout) { 382 this._clearAutocompleteTimeout();
385 clearTimeout(this._completeTimeout);
386 delete this._completeTimeout;
387 }
388 383
389 if (!this._autocompleteElement) 384 if (!this._autocompleteElement)
390 return; 385 return;
391 386
392 this._autocompleteElement.remove(); 387 this._autocompleteElement.remove();
393 delete this._autocompleteElement; 388 delete this._autocompleteElement;
394 delete this._userEnteredRange; 389 delete this._userEnteredRange;
395 delete this._userEnteredText; 390 delete this._userEnteredText;
396 }, 391 },
397 392
393 _clearAutocompleteTimeout: function()
394 {
395 if (this._completeTimeout) {
396 clearTimeout(this._completeTimeout);
397 delete this._completeTimeout;
398 }
399 this._completionRequestId++;
400 },
401
398 /** 402 /**
399 * @param {boolean=} force 403 * @param {boolean=} force
400 */ 404 */
401 autoCompleteSoon: function(force) 405 autoCompleteSoon: function(force)
402 { 406 {
403 var immediately = this.isSuggestBoxVisible() || force; 407 var immediately = this.isSuggestBoxVisible() || force;
404 if (!this._completeTimeout) 408 if (!this._completeTimeout)
405 this._completeTimeout = setTimeout(this.complete.bind(this, force), immediately ? 0 : this._autocompletionTimeout); 409 this._completeTimeout = setTimeout(this.complete.bind(this, force), immediately ? 0 : this._autocompletionTimeout);
406 }, 410 },
407 411
408 /** 412 /**
409 * @param {boolean=} force 413 * @param {boolean=} force
410 * @param {boolean=} reverse 414 * @param {boolean=} reverse
411 */ 415 */
412 complete: function(force, reverse) 416 complete: function(force, reverse)
413 { 417 {
414 this.clearAutocomplete(); 418 this._clearAutocompleteTimeout();
415 var selection = this._element.getComponentSelection(); 419 var selection = this._element.getComponentSelection();
416 var selectionRange = selection && selection.rangeCount ? selection.getRa ngeAt(0) : null; 420 var selectionRange = selection && selection.rangeCount ? selection.getRa ngeAt(0) : null;
417 if (!selectionRange) 421 if (!selectionRange)
418 return; 422 return;
419 423
420 var shouldExit; 424 var shouldExit;
421 425
422 if (!force && !this.isCaretAtEndOfPrompt() && !this.isSuggestBoxVisible( )) 426 if (!force && !this.isCaretAtEndOfPrompt() && !this.isSuggestBoxVisible( ))
423 shouldExit = true; 427 shouldExit = true;
424 else if (!selection.isCollapsed) 428 else if (!selection.isCollapsed)
425 shouldExit = true; 429 shouldExit = true;
426 else if (!force) { 430 else if (!force) {
427 // BUG72018: Do not show suggest box if caret is followed by a non-s top character. 431 // BUG72018: Do not show suggest box if caret is followed by a non-s top character.
428 var wordSuffixRange = selectionRange.startContainer.rangeOfWord(sele ctionRange.endOffset, this._completionStopCharacters, this._element, "forward"); 432 var wordSuffixRange = selectionRange.startContainer.rangeOfWord(sele ctionRange.endOffset, this._completionStopCharacters, this._element, "forward");
429 if (wordSuffixRange.toString().length) 433 var autocompleteTextLength = (this._autocompleteElement && this._aut ocompleteElement.parentNode) ? this._autocompleteElement.textContent.length : 0;
434 if (wordSuffixRange.toString().length !== autocompleteTextLength)
430 shouldExit = true; 435 shouldExit = true;
431 } 436 }
432 if (shouldExit) { 437 if (shouldExit) {
433 this.clearAutocomplete(); 438 this.clearAutocomplete();
434 return; 439 return;
435 } 440 }
436 441
437 var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectio nRange.startOffset, this._completionStopCharacters, this._element, "backward"); 442 var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectio nRange.startOffset, this._completionStopCharacters, this._element, "backward");
438 this._loadCompletions(/** @type {!Element} */ (this._proxyElement), word PrefixRange, force || false, this._completionsReady.bind(this, ++this._completio nRequestId, selection, wordPrefixRange, !!reverse, !!force)); 443 this._loadCompletions(/** @type {!Element} */ (this._proxyElement), word PrefixRange, force || false, this._completionsReady.bind(this, ++this._completio nRequestId, selection, wordPrefixRange, !!reverse, !!force));
439 }, 444 },
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 var completionText = annotatedCompletions[selectedIndex].title; 563 var completionText = annotatedCompletions[selectedIndex].title;
559 var prefixText = this._userEnteredRange.toString(); 564 var prefixText = this._userEnteredRange.toString();
560 var suffixText = completionText.substring(wordPrefixLength); 565 var suffixText = completionText.substring(wordPrefixLength);
561 this._userEnteredRange.deleteContents(); 566 this._userEnteredRange.deleteContents();
562 this._element.normalize(); 567 this._element.normalize();
563 var finalSelectionRange = this._createRange(); 568 var finalSelectionRange = this._createRange();
564 569
565 var prefixTextNode = createTextNode(prefixText); 570 var prefixTextNode = createTextNode(prefixText);
566 fullWordRange.insertNode(prefixTextNode); 571 fullWordRange.insertNode(prefixTextNode);
567 572
568 this._autocompleteElement = createElementWithClass("span", "auto-com plete-text"); 573 if (!this._autocompleteElement)
574 this._autocompleteElement = createElementWithClass("span", "auto -complete-text");
569 this._autocompleteElement.textContent = suffixText; 575 this._autocompleteElement.textContent = suffixText;
576 this._currentHintText = completionText;
570 577
571 prefixTextNode.parentNode.insertBefore(this._autocompleteElement, pr efixTextNode.nextSibling); 578 prefixTextNode.parentNode.insertBefore(this._autocompleteElement, pr efixTextNode.nextSibling);
572 579
573 finalSelectionRange.setStart(prefixTextNode, wordPrefixLength); 580 finalSelectionRange.setStart(prefixTextNode, wordPrefixLength);
574 finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength); 581 finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength);
575 selection.removeAllRanges(); 582 selection.removeAllRanges();
576 selection.addRange(finalSelectionRange); 583 selection.addRange(finalSelectionRange);
577 this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApp lied); 584 this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApp lied);
578 } 585 }
579 }, 586 },
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after
1028 }, 1035 },
1029 1036
1030 /** 1037 /**
1031 * @return {string|undefined} 1038 * @return {string|undefined}
1032 */ 1039 */
1033 _currentHistoryItem: function() 1040 _currentHistoryItem: function()
1034 { 1041 {
1035 return this._data[this._data.length - this._historyOffset]; 1042 return this._data[this._data.length - this._historyOffset];
1036 } 1043 }
1037 }; 1044 };
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