Bug 1522278 - Use nsIEditActionListener to detect when the user deletes autofilled substrings. r=mak

Differential Revision: https://phabricator.services.mozilla.com/D27637

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Drew Willcoxon 2019-04-17 15:19:23 +00:00
parent a8f6e0defb
commit 1bc115e695

View File

@ -92,6 +92,7 @@ class UrlbarInput {
this.lastQueryContextPromise = Promise.resolve();
this._actionOverrideKeyCount = 0;
this._autofillPlaceholder = "";
this._deletedEndOfAutofillPlaceholder = false;
this._lastSearchString = "";
this._resultForCurrentValue = null;
this._suppressStartQuery = false;
@ -182,6 +183,8 @@ class UrlbarInput {
}
this.removeEventListener("mousedown", this);
this.editor.removeEditActionListener(this);
this.view.panel.remove();
this.inputField.controllers.removeControllerAt(0);
@ -668,6 +671,31 @@ class UrlbarInput {
this.textbox.classList.remove("hidden-focus");
}
/**
* nsIEditActionListener method implementation. We use this to detect when
* the user deletes autofilled substrings.
*
* There is also a DidDeleteSelection method, but it's called before the input
* event is fired. So the order is: WillDeleteSelection, DidDeleteSelection,
* input event. Further, in DidDeleteSelection, the passed-in selection
* object is the same as the object passed to WillDeleteSelection, but by that
* point its properties have been adjusted to account for the deletion. For
* example, the endOffset property of its range will be smaller than it was in
* WillDeleteSelection. Therefore we compute whether the user deleted the
* autofilled substring here in WillDeleteSelection instead of deferring it to
* when we handle the input event.
*
* @param {Selection} selection
* The Selection object.
*/
WillDeleteSelection(selection) {
this._deletedEndOfAutofillPlaceholder =
selection &&
selection.getRangeAt(0).endOffset ==
this._autofillPlaceholder.length &&
this._autofillPlaceholder.endsWith(String(selection));
}
// Getters and Setters below.
get focused() {
@ -1273,6 +1301,9 @@ class UrlbarInput {
this._untrimmedValue = value;
this.window.gBrowser.userTypedValue = value;
let deletedEndOfAutofillPlaceholder = this._deletedEndOfAutofillPlaceholder;
this._deletedEndOfAutofillPlaceholder = false;
let compositionState = this._compositionState;
let compositionClosedPopup = this._compositionClosedPopup;
@ -1311,13 +1342,8 @@ class UrlbarInput {
}
let sameSearchStrings = value == this._lastSearchString;
// TODO (bug 1524550): Properly detect autofill removal, rather than
// guessing based on string prefixes.
let deletedAutofilledSubstring =
sameSearchStrings &&
value.length < this._autofillPlaceholder.length &&
this._autofillPlaceholder.startsWith(value);
deletedEndOfAutofillPlaceholder && sameSearchStrings;
// Don't search again when the new search would produce the same results.
// If we're handling a composition input, we must continue the search
@ -1342,11 +1368,18 @@ class UrlbarInput {
}
_on_select(event) {
if (!Services.clipboard.supportsSelectionClipboard()) {
if (!this.window.windowUtils.isHandlingUserInput) {
// Register the editor listener we use to detect when the user deletes
// autofilled substrings. The editor is destroyed and removes all its
// listeners at various surprising times, and autofill causes a non-user
// select, which is why we do this here instead of, for example, in the
// constructor. addEditActionListener is idempotent, so it's OK to call
// it even when we're already registered.
this.editor.addEditActionListener(this);
return;
}
if (!this.window.windowUtils.isHandlingUserInput) {
if (!Services.clipboard.supportsSelectionClipboard()) {
return;
}