| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 }; |
| OLD | NEW |