Bug 1641287: Focus on browser after keyup. r=mak

Differential Revision: https://phabricator.services.mozilla.com/D92561
This commit is contained in:
Daisuke Akatsuka 2020-10-26 05:30:44 +00:00
Родитель aa2ac69761
Коммит df57cd5036
3 изменённых файлов: 143 добавлений и 15 удалений

Просмотреть файл

@ -698,7 +698,11 @@ function openLinkIn(url, where, params) {
break;
}
if (!focusUrlBar && targetBrowser == w.gBrowser.selectedBrowser) {
if (
!params.avoidBrowserFocus &&
!focusUrlBar &&
targetBrowser == w.gBrowser.selectedBrowser
) {
// Focus the content, but only if the browser used for the load is selected.
targetBrowser.focus();
}

Просмотреть файл

@ -17,6 +17,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionSearchHandler: "resource://gre/modules/ExtensionSearchHandler.jsm",
ObjectUtils: "resource://gre/modules/ObjectUtils.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
ReaderMode: "resource://gre/modules/ReaderMode.jsm",
PartnerLinkAttribution: "resource:///modules/PartnerLinkAttribution.jsm",
SearchUtils: "resource://gre/modules/SearchUtils.jsm",
@ -557,7 +558,7 @@ class UrlbarInput {
isValidUrl = true;
} catch (ex) {}
if (isValidUrl) {
this._loadURL(url, where, openParams);
this._loadURL(url, event, where, openParams);
return;
}
@ -613,7 +614,7 @@ class UrlbarInput {
browser.lastLocationChange == lastLocationChange
) {
openParams.postData = postData;
this._loadURL(uri.spec, where, openParams, null, browser);
this._loadURL(uri.spec, event, where, openParams, null, browser);
}
}
});
@ -696,7 +697,7 @@ class UrlbarInput {
selType: "canonized",
provider: result.providerName,
});
this._loadURL(this.value, where, openParams, browser);
this._loadURL(this.value, event, where, openParams, browser);
return;
}
@ -950,6 +951,7 @@ class UrlbarInput {
this._loadURL(
url,
event,
where,
openParams,
{
@ -2266,6 +2268,8 @@ class UrlbarInput {
*
* @param {string} url
* The URL to open.
* @param {Event} event
* The event that triggered to load the url.
* @param {string} openUILinkWhere
* Where we expect the result to be opened.
* @param {object} params
@ -2287,6 +2291,7 @@ class UrlbarInput {
*/
_loadURL(
url,
event,
openUILinkWhere,
params,
resultDetails = null,
@ -2345,10 +2350,19 @@ class UrlbarInput {
params.initiatingDoc = this.window.document;
}
if (event?.keyCode === KeyEvent.DOM_VK_RETURN) {
if (openUILinkWhere === "current") {
params.avoidBrowserFocus = true;
this._keyDownEnterDeferred?.resolve(browser);
}
}
// Focus the content area before triggering loads, since if the load
// occurs in a new tab, we want focus to be restored to the content
// area when the current tab is re-selected.
browser.focus();
if (!params.avoidBrowserFocus) {
browser.focus();
}
if (openUILinkWhere != "current") {
this.handleRevert();
@ -2704,6 +2718,13 @@ class UrlbarInput {
this.window.UpdatePopupNotificationsVisibility();
}
// If user move the focus to another component while pressing Enter key,
// then keyup at that component, as we can't get the event, clear the promise.
if (this._keyDownEnterDeferred) {
this._keyDownEnterDeferred.resolve();
this._keyDownEnterDeferred = null;
}
Services.obs.notifyObservers(null, "urlbar-blur");
}
@ -3030,6 +3051,13 @@ class UrlbarInput {
}
_on_keydown(event) {
if (event.keyCode === KeyEvent.DOM_VK_RETURN) {
if (this._keyDownEnterDeferred) {
this._keyDownEnterDeferred.reject();
}
this._keyDownEnterDeferred = PromiseUtils.defer();
}
// Due to event deferring, it's possible preventDefault() won't be invoked
// soon enough to actually prevent some of the default behaviors, thus we
// have to handle the event "twice". This first immediate call passes false
@ -3046,7 +3074,25 @@ class UrlbarInput {
});
}
_on_keyup(event) {
async _on_keyup(event) {
if (
event.keyCode === KeyEvent.DOM_VK_RETURN &&
this._keyDownEnterDeferred
) {
try {
const loadingBrowser = await this._keyDownEnterDeferred.promise;
// Ensure the selected browser didn't change in the meanwhile.
if (this.window.gBrowser.selectedBrowser === loadingBrowser) {
loadingBrowser.focus();
}
} catch (ex) {
// Not all the Enter actions in the urlbar will cause a navigation, then it
// is normal for this to be rejected.
}
this._keyDownEnterDeferred = null;
return;
}
this._toggleActionOverride(event);
}

Просмотреть файл

@ -6,6 +6,19 @@
const TEST_VALUE = "example.com/\xF7?\xF7";
const START_VALUE = "example.com/%C3%B7?%C3%B7";
add_task(async function setup() {
const engine = await SearchTestUtils.promiseNewSearchEngine(
getRootDirectory(gTestPath) + "searchSuggestionEngine.xml"
);
const defaultEngine = Services.search.defaultEngine;
Services.search.defaultEngine = engine;
registerCleanupFunction(async function() {
Services.search.defaultEngine = defaultEngine;
});
});
add_task(async function returnKeypress() {
info("Simple return keypress");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, START_VALUE);
@ -82,11 +95,7 @@ add_task(async function altGrReturnKeypress() {
add_task(async function searchOnEnterNoPick() {
info("Search on Enter without picking a urlbar result");
let engine = await SearchTestUtils.promiseNewSearchEngine(
getRootDirectory(gTestPath) + "searchSuggestionEngine.xml"
);
let defaultEngine = Services.search.defaultEngine;
Services.search.defaultEngine = engine;
// Why is BrowserTestUtils.openNewForegroundTab not causing the bug?
let promiseTabOpened = BrowserTestUtils.waitForEvent(
gBrowser.tabContainer,
@ -95,10 +104,6 @@ add_task(async function searchOnEnterNoPick() {
EventUtils.synthesizeMouseAtCenter(gBrowser.tabContainer.newTabButton, {});
let openEvent = await promiseTabOpened;
let tab = openEvent.target;
registerCleanupFunction(async function() {
Services.search.defaultEngine = defaultEngine;
BrowserTestUtils.removeTab(tab);
});
let loadPromise = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
@ -120,4 +125,77 @@ add_task(async function searchOnEnterNoPick() {
gURLBar.untrimmedValue,
"The location should have changed"
);
// Cleanup.
BrowserTestUtils.removeTab(tab);
});
add_task(async function searchOnEnterSoon() {
info("Search on Enter as soon as typing a char");
const tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
START_VALUE
);
const onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
const onBeforeUnload = SpecialPowers.spawn(
gBrowser.selectedBrowser,
[],
() => {
return new Promise(resolve => {
content.window.addEventListener("beforeunload", () => {
resolve();
});
});
}
);
const onResult = SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
return new Promise(resolve => {
content.window.addEventListener("keyup", () => {
resolve("keyup");
});
content.window.addEventListener("unload", () => {
resolve("unload");
});
});
});
// Focus on the input field in urlbar.
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {});
const ownerDocument = gBrowser.selectedBrowser.ownerDocument;
is(
ownerDocument.activeElement,
gURLBar.inputField,
"The input field in urlbar has focus"
);
info("Keydown a char and Enter");
EventUtils.synthesizeKey("x", { type: "keydown" });
EventUtils.synthesizeKey("KEY_Enter", { type: "keydown" });
// Wait for beforeUnload event in the content.
await onBeforeUnload;
is(
ownerDocument.activeElement,
gURLBar.inputField,
"The input field in urlbar still has focus"
);
// Keyup both key as soon as beforeUnload event happens.
EventUtils.synthesizeKey("x", { type: "keyup" });
EventUtils.synthesizeKey("KEY_Enter", { type: "keyup" });
// Wait for moving the focus.
await TestUtils.waitForCondition(
() => ownerDocument.activeElement === gBrowser.selectedBrowser
);
info("The focus is moved to the browser");
// Check whether keyup event is not captured before unload event happens.
const result = await onResult;
is(result, "unload", "Keyup event is not captured.");
// Cleanup.
await onLoad;
BrowserTestUtils.removeTab(tab);
});