зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1303838 - Switch to existing target tab when clicking links. r=smaug
Merge "DOMServiceWorkerFocusClient" & "DOMWebNotificationClicked" to "DOMWindowFocus" event. Utilize the event to switch tab when loading links to an existing target tab. MozReview-Commit-ID: Hd1NkVkrJA1 --HG-- extra : rebase_source : 745c0d66c3afd8e487c616891c0f10bd820da1fe
This commit is contained in:
Родитель
5c092525e2
Коммит
d19130f17a
|
@ -698,12 +698,8 @@ ContentLinkHandler.init(this);
|
|||
// TODO: Load this lazily so the JSM is run only if a relevant event/message fires.
|
||||
var pluginContent = new PluginContent(global);
|
||||
|
||||
addEventListener("DOMWebNotificationClicked", function(event) {
|
||||
sendAsyncMessage("DOMWebNotificationClicked", {});
|
||||
}, false);
|
||||
|
||||
addEventListener("DOMServiceWorkerFocusClient", function(event) {
|
||||
sendAsyncMessage("DOMServiceWorkerFocusClient", {});
|
||||
addEventListener("DOMWindowFocus", function(event) {
|
||||
sendAsyncMessage("DOMWindowFocus", {});
|
||||
}, false);
|
||||
|
||||
ContentWebRTC.init();
|
||||
|
|
|
@ -5007,8 +5007,7 @@
|
|||
popup.openPopupAtScreen(event.screenX, event.screenY, true);
|
||||
break;
|
||||
}
|
||||
case "DOMServiceWorkerFocusClient":
|
||||
case "DOMWebNotificationClicked": {
|
||||
case "DOMWindowFocus": {
|
||||
let tab = this.getTabForBrowser(browser);
|
||||
if (!tab)
|
||||
return undefined;
|
||||
|
@ -5240,8 +5239,7 @@
|
|||
this._outerWindowIDBrowserMap.set(this.mCurrentBrowser.outerWindowID,
|
||||
this.mCurrentBrowser);
|
||||
}
|
||||
messageManager.addMessageListener("DOMWebNotificationClicked", this);
|
||||
messageManager.addMessageListener("DOMServiceWorkerFocusClient", this);
|
||||
messageManager.addMessageListener("DOMWindowFocus", this);
|
||||
messageManager.addMessageListener("RefreshBlocker:Blocked", this);
|
||||
messageManager.addMessageListener("Browser:WindowCreated", this);
|
||||
|
||||
|
|
|
@ -10199,6 +10199,19 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
|||
// window will need to be made visible... For now,
|
||||
// do nothing.
|
||||
}
|
||||
|
||||
// Switch to target tab if we're currently focused window.
|
||||
// Take loadDivertedInBackground into account so the behavior would be
|
||||
// the same as how the tab first opened.
|
||||
bool isTargetActive = false;
|
||||
targetDocShell->GetIsActive(&isTargetActive);
|
||||
if (mIsActive && !isTargetActive &&
|
||||
!Preferences::GetBool("browser.tabs.loadDivertedInBackground", false)) {
|
||||
if (NS_FAILED(nsContentUtils::DispatchFocusChromeEvent(
|
||||
targetDocShell->GetWindow()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Else we ran out of memory, or were a popup and got blocked,
|
||||
|
|
|
@ -4127,7 +4127,7 @@ nsContentUtils::DispatchFocusChromeEvent(nsPIDOMWindowOuter* aWindow)
|
|||
}
|
||||
|
||||
return DispatchChromeEvent(doc, aWindow,
|
||||
NS_LITERAL_STRING("DOMServiceWorkerFocusClient"),
|
||||
NS_LITERAL_STRING("DOMWindowFocus"),
|
||||
true, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -1256,7 +1256,7 @@ public:
|
|||
bool *aDefaultAction = nullptr);
|
||||
|
||||
/**
|
||||
* Helper function for dispatching a "DOMServiceWorkerFocusClient" event to
|
||||
* Helper function for dispatching a "DOMWindowFocus" event to
|
||||
* the chrome event handler of the given DOM Window. This has the effect
|
||||
* of focusing the corresponding tab and bringing the browser window
|
||||
* to the foreground.
|
||||
|
|
|
@ -6,6 +6,9 @@ support-files =
|
|||
file_audioLoopInIframe.html
|
||||
file_bug1011748_redirect.sjs
|
||||
file_bug1011748_OK.sjs
|
||||
file_bug1303838.html
|
||||
file_bug1303838_target.html
|
||||
file_bug1303838_with_iframe.html
|
||||
file_messagemanager_unload.html
|
||||
file_pluginAudio.html
|
||||
file_use_counter_outer.html
|
||||
|
@ -33,3 +36,4 @@ skip-if = true # Bug 1271028
|
|||
[browser_use_counters.js]
|
||||
[browser_bug1307747.js]
|
||||
[browser_timeout_throttling_with_audio_playback.js]
|
||||
[browser_bug1303838.js]
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Test for bug 1303838.
|
||||
* Load a tab with some links, emulate link clicks and check if the
|
||||
* browser would switch to the existing target tab opened by previous
|
||||
* link click if loadDivertedInBackground is set to true.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const BASE_URL = "http://mochi.test:8888/browser/dom/base/test/";
|
||||
|
||||
add_task(function*() {
|
||||
yield* testLinkClick(false, false);
|
||||
yield* testLinkClick(false, true);
|
||||
yield* testLinkClick(true, false);
|
||||
yield* testLinkClick(true, true);
|
||||
});
|
||||
|
||||
function* testLinkClick(withFrame, loadDivertedInBackground) {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [["browser.tabs.loadDivertedInBackground", loadDivertedInBackground]]});
|
||||
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
|
||||
BASE_URL + (withFrame ? "file_bug1303838_with_iframe.html" : "file_bug1303838.html"));
|
||||
is(gBrowser.tabs.length, 2, "check tabs.length");
|
||||
is(gBrowser.selectedTab, tab, "check selectedTab");
|
||||
|
||||
info("Test normal links with loadDivertedInBackground=" + loadDivertedInBackground + ", withFrame=" + withFrame);
|
||||
|
||||
let [testTab] = yield clickLink(withFrame, "#link-1", tab.linkedBrowser);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#link-2", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#link-3", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#link-4", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground, 2);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
info("Test anchor links with loadDivertedInBackground=" + loadDivertedInBackground + ", withFrame=" + withFrame);
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#anchor-link-1", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#anchor-link-2", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#anchor-link-3", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
info("Test iframe links with loadDivertedInBackground=" + loadDivertedInBackground + ", withFrame=" + withFrame);
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#frame-link-1", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#frame-link-2", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
if (!loadDivertedInBackground) {
|
||||
yield BrowserTestUtils.switchTab(gBrowser, tab);
|
||||
}
|
||||
yield clickLink(withFrame, "#frame-link-3", tab.linkedBrowser, testTab.linkedBrowser, !loadDivertedInBackground);
|
||||
is(gBrowser.tabs.length, 3, "check tabs.length");
|
||||
is(gBrowser.selectedTab, loadDivertedInBackground ? tab : testTab, "check selectedTab");
|
||||
|
||||
yield BrowserTestUtils.removeTab(testTab);
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
function clickLink(isFrame, linkId, browser, testBrowser, awaitTabSwitch = false, locationChangeNum = 1) {
|
||||
let promises = [];
|
||||
if (awaitTabSwitch) {
|
||||
promises.push(waitForTabSwitch(gBrowser));
|
||||
}
|
||||
promises.push(testBrowser ?
|
||||
waitForLocationChange(testBrowser, locationChangeNum) :
|
||||
BrowserTestUtils.waitForNewTab(gBrowser));
|
||||
promises.push(ContentTask.spawn(browser, [isFrame, linkId],
|
||||
([contentIsFrame, contentLinkId]) => {
|
||||
let doc = content.document;
|
||||
if (contentIsFrame) {
|
||||
let frame = content.document.getElementById("frame");
|
||||
doc = frame.contentDocument;
|
||||
}
|
||||
info("Clicking " + contentLinkId);
|
||||
doc.querySelector(contentLinkId).click();
|
||||
}));
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function waitForTabSwitch(tabbrowser) {
|
||||
info("Waiting for TabSwitch");
|
||||
return new Promise(resolve => {
|
||||
tabbrowser.addEventListener("TabSwitchDone", function onSwitch() {
|
||||
info("TabSwitch done");
|
||||
tabbrowser.removeEventListener("TabSwitchDone", onSwitch);
|
||||
resolve(tabbrowser.selectedTab);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// We need a longer lifetime reference to ensure the listener is alive when
|
||||
// location change occurs.
|
||||
let locationChangeListener;
|
||||
function waitForLocationChange(browser, locationChangeNum) {
|
||||
info("Waiting for " + locationChangeNum + " LocationChange");
|
||||
return new Promise(resolve => {
|
||||
let seen = 0;
|
||||
locationChangeListener = {
|
||||
onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
|
||||
info("LocationChange: " + aLocation.spec);
|
||||
if (++seen == locationChangeNum) {
|
||||
browser.removeProgressListener(this);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
browser.addProgressListener(locationChangeListener);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Tests for tab switching on link clicks.
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tests for tab switching on link clicks.</title>
|
||||
</head>
|
||||
<body>
|
||||
<a id="link-1" target="testTab" href="data:text/html;charset=utf-8,foo">Link 1</a><br>
|
||||
<a id="link-2" target="testTab" href="data:text/html;charset=utf-8,bar">Link 2</a><br>
|
||||
<a id="link-3" target="testTab" href="data:text/html;charset=utf-8,baz">Link 3</a><br>
|
||||
<a id="link-4" target="testTab" href="file_bug1303838_target.html">Link 4</a><br>
|
||||
<a id="anchor-link-1" target="testTab" href="file_bug1303838_target.html#foo">Anchor Link 1</a><br>
|
||||
<a id="anchor-link-2" target="testTab" href="file_bug1303838_target.html#bar">Anchor Link 2</a><br>
|
||||
<a id="anchor-link-3" target="testTab" href="file_bug1303838_target.html#baz">Anchor Link 3</a><br>
|
||||
<a id="frame-link-1" target="testFrame" href="data:text/html;charset=utf-8,ifoo">Frame Link 1</a><br>
|
||||
<a id="frame-link-2" target="testFrame" href="data:text/html;charset=utf-8,ibar">Frame Link 2</a><br>
|
||||
<a id="frame-link-3" target="testFrame" href="data:text/html;charset=utf-8,ibaz">Frame Link 3</a><br>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Tests for tab switching on link clicks.
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tests for tab switching on link clicks.</title>
|
||||
</head>
|
||||
<body onload="setTimeout(loadTestFrame, 0);">
|
||||
<div id="foo">Foo</div>
|
||||
<div id="bar">Bar</div>
|
||||
<div id="baz">Baz</div>
|
||||
<iframe name="testFrame"></iframe>
|
||||
<script>
|
||||
function loadTestFrame() {
|
||||
window.open("data:text/html;charset=utf-8,testFrame", "testFrame");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Tests for tab switching on link clicks.
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tests for tab switching on link clicks.</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="frame" src="file_bug1303838.html"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -322,14 +322,9 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIDocument* doc = mWindow->GetExtantDoc();
|
||||
if (doc) {
|
||||
// Browser UI may use DOMWebNotificationClicked to focus the tab
|
||||
// from which the event was dispatched.
|
||||
nsContentUtils::DispatchChromeEvent(doc, mWindow->GetOuterWindow(),
|
||||
NS_LITERAL_STRING("DOMWebNotificationClicked"),
|
||||
true, true);
|
||||
}
|
||||
// Browser UI may use DOMWindowFocus to focus the tab
|
||||
// from which the event was dispatched.
|
||||
nsContentUtils::DispatchFocusChromeEvent(mWindow->GetOuterWindow());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1500,14 +1495,9 @@ MainThreadNotificationObserver::Observe(nsISupports* aSubject, const char* aTopi
|
|||
|
||||
bool doDefaultAction = notification->DispatchClickEvent();
|
||||
if (doDefaultAction) {
|
||||
nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
|
||||
if (doc) {
|
||||
// Browser UI may use DOMWebNotificationClicked to focus the tab
|
||||
// from which the event was dispatched.
|
||||
nsContentUtils::DispatchChromeEvent(doc, window->GetOuterWindow(),
|
||||
NS_LITERAL_STRING("DOMWebNotificationClicked"),
|
||||
true, true);
|
||||
}
|
||||
// Browser UI may use DOMWindowFocus to focus the tab
|
||||
// from which the event was dispatched.
|
||||
nsContentUtils::DispatchFocusChromeEvent(window->GetOuterWindow());
|
||||
}
|
||||
} else if (!strcmp("alertfinished", aTopic)) {
|
||||
notification->UnpersistNotification();
|
||||
|
|
|
@ -3629,7 +3629,7 @@ Tab.prototype = {
|
|||
this.browser.addEventListener("pageshow", this, true);
|
||||
this.browser.addEventListener("MozApplicationManifest", this, true);
|
||||
this.browser.addEventListener("TabPreZombify", this, true);
|
||||
this.browser.addEventListener("DOMServiceWorkerFocusClient", this, true);
|
||||
this.browser.addEventListener("DOMWindowFocus", this, true);
|
||||
|
||||
// Note that the XBL binding is untrusted
|
||||
this.browser.addEventListener("PluginBindingAttached", this, true, true);
|
||||
|
@ -3745,7 +3745,7 @@ Tab.prototype = {
|
|||
this.browser.removeEventListener("pageshow", this, true);
|
||||
this.browser.removeEventListener("MozApplicationManifest", this, true);
|
||||
this.browser.removeEventListener("TabPreZombify", this, true);
|
||||
this.browser.removeEventListener("DOMServiceWorkerFocusClient", this, true);
|
||||
this.browser.removeEventListener("DOMWindowFocus", this, true);
|
||||
|
||||
this.browser.removeEventListener("PluginBindingAttached", this, true, true);
|
||||
this.browser.removeEventListener("VideoBindingAttached", this, true, true);
|
||||
|
@ -4268,7 +4268,7 @@ Tab.prototype = {
|
|||
break;
|
||||
}
|
||||
|
||||
case "DOMServiceWorkerFocusClient": {
|
||||
case "DOMWindowFocus": {
|
||||
GlobalEventDispatcher.sendRequest({
|
||||
type: "Tab:Select",
|
||||
tabID: this.id,
|
||||
|
|
Загрузка…
Ссылка в новой задаче