зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1602173: Capture attempts to load pages and redirect back to the browser when needed. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D56286 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
5577453668
Коммит
e5bd7eee3c
|
@ -279,6 +279,17 @@ let ACTORS = {
|
||||||
allFrames: true,
|
allFrames: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
SiteSpecificBrowser: {
|
||||||
|
parent: {
|
||||||
|
moduleURI: "resource:///actors/SiteSpecificBrowserParent.jsm",
|
||||||
|
},
|
||||||
|
child: {
|
||||||
|
moduleURI: "resource:///actors/SiteSpecificBrowserChild.jsm",
|
||||||
|
},
|
||||||
|
|
||||||
|
allFrames: true,
|
||||||
|
},
|
||||||
|
|
||||||
UITour: {
|
UITour: {
|
||||||
parent: {
|
parent: {
|
||||||
moduleURI: "resource:///modules/UITourParent.jsm",
|
moduleURI: "resource:///modules/UITourParent.jsm",
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const EXPORTED_SYMBOLS = ["SiteSpecificBrowserChild"];
|
||||||
|
|
||||||
|
const { SiteSpecificBrowserBase } = ChromeUtils.import(
|
||||||
|
"resource:///modules/SiteSpecificBrowserService.jsm"
|
||||||
|
);
|
||||||
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
const { E10SUtils } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/E10SUtils.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
class SiteSpecificBrowserChild extends JSWindowActorChild {
|
||||||
|
receiveMessage(message) {
|
||||||
|
switch (message.name) {
|
||||||
|
case "SetSSB":
|
||||||
|
// Note that this sets the webbrowserchrome for the top-level browser
|
||||||
|
// child in this page. This means that any inner-frames loading in
|
||||||
|
// different processes will not be handled correctly. Fixing this will
|
||||||
|
// happen in bug 1602849.
|
||||||
|
this.docShell.browserChild.webBrowserChrome = new WebBrowserChrome(
|
||||||
|
message.data
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActor(docShell) {
|
||||||
|
return docShell.domWindow
|
||||||
|
.getWindowGlobalChild()
|
||||||
|
.getActor("SiteSpecificBrowser");
|
||||||
|
}
|
||||||
|
|
||||||
|
// JS actors can't generally be XPCOM objects so we must use a separate class.
|
||||||
|
class WebBrowserChrome {
|
||||||
|
constructor(id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get ssb() {
|
||||||
|
return SiteSpecificBrowserBase.get(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsIWebBrowserChrome3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This gets called when a user clicks on a link or submits a form. We can use
|
||||||
|
* it to see where the resulting page load will occur and if needed redirect
|
||||||
|
* it to a different target.
|
||||||
|
*
|
||||||
|
* @param {string} originalTarget the target intended for the load.
|
||||||
|
* @param {nsIURI} linkURI the URI that will be loaded.
|
||||||
|
* @param {Node} linkNode the element causing the load.
|
||||||
|
* @param {boolean} isAppTab whether the source docshell is marked as an
|
||||||
|
* app tab.
|
||||||
|
* @return {string} the target to use for the load.
|
||||||
|
*/
|
||||||
|
onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab) {
|
||||||
|
// Our actor is for the top-level frame in the page while this may be being
|
||||||
|
// called for a navigation in an inner frame. First we have to find the
|
||||||
|
// browsing context for the frame doing the load.
|
||||||
|
|
||||||
|
let docShell = linkNode.ownerGlobal.docShell;
|
||||||
|
let bc = docShell.browsingContext;
|
||||||
|
|
||||||
|
// Which browsing context is this link targetting?
|
||||||
|
let target = originalTarget ? bc.findWithName(originalTarget) : bc;
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
// If we found a target then it must be one of the frames within this
|
||||||
|
// frame tree since we don't support popup windows.
|
||||||
|
if (target.parent) {
|
||||||
|
// An inner frame, continue.
|
||||||
|
return originalTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A top-level load. If our SSB cannot load this URI then start the
|
||||||
|
// process of opening it into a new tab somewhere.
|
||||||
|
return this.ssb.canLoad(linkURI) ? originalTarget : "_blank";
|
||||||
|
}
|
||||||
|
|
||||||
|
// An attempt to open a new window/tab. If the new URI can be loaded by our
|
||||||
|
// SSB then load it at the top-level. Note that we override the requested
|
||||||
|
// target so that this page can't reach the new context.
|
||||||
|
return this.ssb.canLoad(linkURI) ? "_top" : "_blank";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A load is about to occur in a frame. This is an opportunity to stop it
|
||||||
|
* and redirect it somewhere.
|
||||||
|
*
|
||||||
|
* @param {nsIDocShell} docShell the current docshell.
|
||||||
|
* @param {nsIURI} uri the URI that will be loaded.
|
||||||
|
* @param {nsIReferrerInfo} referrerInfo the referrer info.
|
||||||
|
* @param {boolean} hasPostData whether there is POST data
|
||||||
|
* for the load.
|
||||||
|
* @param {nsIPrincipal} triggeringPrincipal the triggering principal.
|
||||||
|
* @param {nsIContentSecurityPolicy} csp the content security policy.
|
||||||
|
* @return {boolean} whether the load should proceed or not.
|
||||||
|
*/
|
||||||
|
shouldLoadURI(
|
||||||
|
docShell,
|
||||||
|
uri,
|
||||||
|
referrerInfo,
|
||||||
|
hasPostData,
|
||||||
|
triggeringPrincipal,
|
||||||
|
csp
|
||||||
|
) {
|
||||||
|
// As above, our actor is for the top-level frame in the page however we
|
||||||
|
// are passed the docshell potentially handling the load here so we can
|
||||||
|
// do the right thing.
|
||||||
|
|
||||||
|
// We only police loads at the top level.
|
||||||
|
if (docShell.browsingContext.parent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.ssb.canLoad(uri)) {
|
||||||
|
// Should only have got this far for a window.location manipulation.
|
||||||
|
|
||||||
|
getActor(docShell).sendAsyncMessage("RetargetOutOfScopeURIToBrowser", {
|
||||||
|
uri: uri.spec,
|
||||||
|
referrerInfo: E10SUtils.serializeReferrerInfo(referrerInfo),
|
||||||
|
triggeringPrincipal: E10SUtils.serializePrincipal(
|
||||||
|
triggeringPrincipal ||
|
||||||
|
Services.scriptSecurityManager.createNullPrincipal({})
|
||||||
|
),
|
||||||
|
csp: csp ? E10SUtils.serializeCSP(csp) : null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple check for whether this is the correct process to load this URI.
|
||||||
|
*
|
||||||
|
* @param {nsIURI} uri the URI that will be loaded.
|
||||||
|
* @return {boolean} whether the load should proceed or not.
|
||||||
|
*/
|
||||||
|
shouldLoadURIInThisProcess(uri) {
|
||||||
|
return this.ssb.canLoad(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs us to start a fresh process to load this URI. Usually used for
|
||||||
|
* large allocation sites. SSB does not support this.
|
||||||
|
*
|
||||||
|
* @param {nsIDocShell} docShell the current docshell.
|
||||||
|
* @param {nsIURI} uri the URI that will be loaded.
|
||||||
|
* @param {nsIReferrerInfo} referrerInfo the referrer info.
|
||||||
|
* @param {nsIPrincipal} triggeringPrincipal the triggering principal.
|
||||||
|
* @param {Number} loadFlags the load flags.
|
||||||
|
* @param {nsIContentSecurityPolicy} csp the content security policy.
|
||||||
|
* @return {boolean} whether the load should proceed or not.
|
||||||
|
*/
|
||||||
|
reloadInFreshProcess(
|
||||||
|
docShell,
|
||||||
|
uri,
|
||||||
|
referrerInfo,
|
||||||
|
triggeringPrincipal,
|
||||||
|
loadFlags,
|
||||||
|
csp
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* vim: set ts=2 sw=2 sts=2 et 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/. */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var EXPORTED_SYMBOLS = ["SiteSpecificBrowserParent"];
|
||||||
|
|
||||||
|
const { BrowserWindowTracker } = ChromeUtils.import(
|
||||||
|
"resource:///modules/BrowserWindowTracker.jsm"
|
||||||
|
);
|
||||||
|
const { E10SUtils } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/E10SUtils.jsm"
|
||||||
|
);
|
||||||
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
const { AppConstants } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/AppConstants.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
class SiteSpecificBrowserParent extends JSWindowActorParent {
|
||||||
|
receiveMessage(message) {
|
||||||
|
switch (message.name) {
|
||||||
|
case "RetargetOutOfScopeURIToBrowser":
|
||||||
|
// The content process found a URI that needs to be loaded in the main
|
||||||
|
// browser.
|
||||||
|
let triggeringPrincipal = E10SUtils.deserializePrincipal(
|
||||||
|
message.data.triggeringPrincipal
|
||||||
|
);
|
||||||
|
let referrerInfo = E10SUtils.deserializeReferrerInfo(
|
||||||
|
message.data.referrerInfo
|
||||||
|
);
|
||||||
|
let csp = E10SUtils.deserializeCSP(message.data.csp);
|
||||||
|
|
||||||
|
// Attempt to find an existing window to open it in.
|
||||||
|
let win = BrowserWindowTracker.getTopWindow();
|
||||||
|
if (win) {
|
||||||
|
win.gBrowser.selectedTab = win.gBrowser.addTab(message.data.uri, {
|
||||||
|
triggeringPrincipal,
|
||||||
|
csp,
|
||||||
|
referrerInfo,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let sa = Cc["@mozilla.org/array;1"].createInstance(
|
||||||
|
Ci.nsIMutableArray
|
||||||
|
);
|
||||||
|
|
||||||
|
let wuri = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||||
|
Ci.nsISupportsString
|
||||||
|
);
|
||||||
|
wuri.data = message.data.uri;
|
||||||
|
|
||||||
|
sa.appendElement(wuri);
|
||||||
|
sa.appendElement(null); // unused (bug 871161)
|
||||||
|
sa.appendElement(referrerInfo);
|
||||||
|
sa.appendElement(null); // postData
|
||||||
|
sa.appendElement(null); // allowThirdPartyFixup
|
||||||
|
sa.appendElement(null); // userContextId
|
||||||
|
sa.appendElement(null); // originPrincipal
|
||||||
|
sa.appendElement(null); // originStoragePrincipal
|
||||||
|
sa.appendElement(triggeringPrincipal);
|
||||||
|
sa.appendElement(null); // allowInheritPrincipal
|
||||||
|
sa.appendElement(csp);
|
||||||
|
|
||||||
|
Services.ww.openWindow(
|
||||||
|
null,
|
||||||
|
AppConstants.BROWSER_CHROME_URL,
|
||||||
|
null,
|
||||||
|
"chrome,dialog=no,all",
|
||||||
|
sa
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,24 +2,194 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
ChromeUtils.defineModuleGetter(
|
const { XPCOMUtils } = ChromeUtils.import(
|
||||||
this,
|
"resource://gre/modules/XPCOMUtils.jsm"
|
||||||
"SiteSpecificBrowser",
|
|
||||||
"resource:///modules/SiteSpecificBrowserService.jsm"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
|
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
|
||||||
|
Services: "resource://gre/modules/Services.jsm",
|
||||||
|
SiteSpecificBrowser: "resource:///modules/SiteSpecificBrowserService.jsm",
|
||||||
|
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||||
|
});
|
||||||
|
|
||||||
let gSSBBrowser = null;
|
let gSSBBrowser = null;
|
||||||
let gSSB = null;
|
let gSSB = null;
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
gSSB = SiteSpecificBrowser.get(window.arguments[0]);
|
gSSB = SiteSpecificBrowser.get(window.arguments[0]);
|
||||||
|
|
||||||
|
window.browserDOMWindow = new BrowserDOMWindow();
|
||||||
|
|
||||||
gSSBBrowser = document.createXULElement("browser");
|
gSSBBrowser = document.createXULElement("browser");
|
||||||
gSSBBrowser.setAttribute("id", "browser");
|
gSSBBrowser.setAttribute("id", "browser");
|
||||||
gSSBBrowser.setAttribute("type", "content");
|
gSSBBrowser.setAttribute("type", "content");
|
||||||
gSSBBrowser.setAttribute("remote", "true");
|
gSSBBrowser.setAttribute("remote", "true");
|
||||||
|
gSSBBrowser.setAttribute("nodefaultsrc", "true");
|
||||||
document.getElementById("browser-container").appendChild(gSSBBrowser);
|
document.getElementById("browser-container").appendChild(gSSBBrowser);
|
||||||
|
|
||||||
|
// Give our actor the SSB's ID.
|
||||||
|
let actor = gSSBBrowser.browsingContext.currentWindowGlobal.getActor(
|
||||||
|
"SiteSpecificBrowser"
|
||||||
|
);
|
||||||
|
actor.sendAsyncMessage("SetSSB", gSSB.id);
|
||||||
|
|
||||||
gSSBBrowser.src = gSSB.startURI.spec;
|
gSSBBrowser.src = gSSB.startURI.spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", init, true);
|
class BrowserDOMWindow {
|
||||||
|
/**
|
||||||
|
* Called when a page in the main process needs a new window to display a new
|
||||||
|
* page in.
|
||||||
|
*
|
||||||
|
* @param {nsIURI?} uri
|
||||||
|
* @param {Window} opener
|
||||||
|
* @param {Number} where
|
||||||
|
* @param {Number} flags
|
||||||
|
* @param {nsIPrincipal} triggeringPrincipal
|
||||||
|
* @param {nsIContentSecurityPolicy?} csp
|
||||||
|
* @return {BrowsingContext} the BrowsingContext the URI should be loaded in.
|
||||||
|
*/
|
||||||
|
createContentWindow(uri, opener, where, flags, triggeringPrincipal, csp) {
|
||||||
|
console.error(
|
||||||
|
"createContentWindow should never be called from a remote browser"
|
||||||
|
);
|
||||||
|
throw Cr.NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from a page in the main process to open a new URI.
|
||||||
|
*
|
||||||
|
* @param {nsIURI} uri
|
||||||
|
* @param {Window} opener
|
||||||
|
* @param {Number} where
|
||||||
|
* @param {Number} flags
|
||||||
|
* @param {nsIPrincipal} triggeringPrincipal
|
||||||
|
* @param {nsIContentSecurityPolicy?} csp
|
||||||
|
* @return {BrowsingContext} the BrowsingContext the URI should be loaded in.
|
||||||
|
*/
|
||||||
|
openURI(uri, opener, where, flags, triggeringPrincipal, csp) {
|
||||||
|
console.error("openURI should never be called from a remote browser");
|
||||||
|
throw Cr.NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a new frame to load some content in.
|
||||||
|
*
|
||||||
|
* @param {nsIURI?} uri
|
||||||
|
* @param {nsIOpenURIInFrameParams} params
|
||||||
|
* @param {Number} where
|
||||||
|
* @param {Number} flags
|
||||||
|
* @param {Number} nextRemoteTabId
|
||||||
|
* @param {string} name
|
||||||
|
* @param {boolean} shouldOpen should the load start or not.
|
||||||
|
* @return {Element} the frame element the URI should be loaded in.
|
||||||
|
*/
|
||||||
|
getContentWindowOrOpenURIInFrame(
|
||||||
|
uri,
|
||||||
|
params,
|
||||||
|
where,
|
||||||
|
flags,
|
||||||
|
nextRemoteTabId,
|
||||||
|
name,
|
||||||
|
shouldOpen
|
||||||
|
) {
|
||||||
|
// It's been determined that this load needs to happen in a new frame.
|
||||||
|
// Either onBeforeLinkTraversal set this correctly or this is the result
|
||||||
|
// of a window.open call.
|
||||||
|
|
||||||
|
// If this ssb can load the url then just load it internally.
|
||||||
|
if (gSSB.canLoad(uri)) {
|
||||||
|
return gSSBBrowser;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try and find a browser window to open in.
|
||||||
|
let win = BrowserWindowTracker.getTopWindow({
|
||||||
|
private: params.isPrivate,
|
||||||
|
allowPopups: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (win) {
|
||||||
|
// Just hand off to the window's handler
|
||||||
|
win.focus();
|
||||||
|
return win.browserDOMWindow.openURIInFrame(
|
||||||
|
shouldOpen ? uri : null,
|
||||||
|
params,
|
||||||
|
where,
|
||||||
|
flags,
|
||||||
|
nextRemoteTabId,
|
||||||
|
name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to open a new browser window and a tab in it. That's an
|
||||||
|
// asychronous operation but luckily if we return null here the platform
|
||||||
|
// handles doing that for us.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an nsFrameLoaderOwner to load some new content in.
|
||||||
|
*
|
||||||
|
* @param {nsIURI?} uri
|
||||||
|
* @param {nsIOpenURIInFrameParams} params
|
||||||
|
* @param {Number} where
|
||||||
|
* @param {Number} flags
|
||||||
|
* @param {Number} nextRemoteTabId
|
||||||
|
* @param {string} name
|
||||||
|
* @return {Element} the frame element the URI should be loaded in.
|
||||||
|
*/
|
||||||
|
createContentWindowInFrame(uri, params, where, flags, nextRemoteTabId, name) {
|
||||||
|
return this.getContentWindowOrOpenURIInFrame(
|
||||||
|
uri,
|
||||||
|
params,
|
||||||
|
where,
|
||||||
|
flags,
|
||||||
|
nextRemoteTabId,
|
||||||
|
name,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new nsFrameLoaderOwner and load some content into it.
|
||||||
|
*
|
||||||
|
* @param {nsIURI} uri
|
||||||
|
* @param {nsIOpenURIInFrameParams} params
|
||||||
|
* @param {Number} where
|
||||||
|
* @param {Number} flags
|
||||||
|
* @param {Number} nextRemoteTabId
|
||||||
|
* @param {string} name
|
||||||
|
* @return {Element} the frame element the URI is loading in.
|
||||||
|
*/
|
||||||
|
openURIInFrame(uri, params, where, flags, nextRemoteTabId, name) {
|
||||||
|
return this.getContentWindowOrOpenURIInFrame(
|
||||||
|
uri,
|
||||||
|
params,
|
||||||
|
where,
|
||||||
|
flags,
|
||||||
|
nextRemoteTabId,
|
||||||
|
name,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isTabContentWindow(window) {
|
||||||
|
// This method is probably not needed anymore: bug 1602915
|
||||||
|
return gSSBBrowser.contentWindow == window;
|
||||||
|
}
|
||||||
|
|
||||||
|
canClose() {
|
||||||
|
return BrowserUtils.canCloseWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
get tabCount() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BrowserDOMWindow.prototype.QueryInterface = ChromeUtils.generateQI([
|
||||||
|
Ci.nsIBrowserDOMWindow,
|
||||||
|
]);
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", init, true);
|
||||||
|
|
|
@ -14,3 +14,8 @@ XPCOM_MANIFESTS += [
|
||||||
EXTRA_JS_MODULES += [
|
EXTRA_JS_MODULES += [
|
||||||
'SiteSpecificBrowserService.jsm',
|
'SiteSpecificBrowserService.jsm',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
FINAL_TARGET_FILES.actors += [
|
||||||
|
'SiteSpecificBrowserChild.jsm',
|
||||||
|
'SiteSpecificBrowserParent.jsm',
|
||||||
|
]
|
||||||
|
|
|
@ -2,9 +2,16 @@
|
||||||
support-files =
|
support-files =
|
||||||
head.js
|
head.js
|
||||||
test_page.html
|
test_page.html
|
||||||
|
empty_page.html
|
||||||
prefs =
|
prefs =
|
||||||
browser.ssb.enabled=true
|
browser.ssb.enabled=true
|
||||||
|
|
||||||
|
[browser_ssb_direct.js]
|
||||||
[browser_ssb_lasttab.js]
|
[browser_ssb_lasttab.js]
|
||||||
[browser_ssb_menu.js]
|
[browser_ssb_menu.js]
|
||||||
|
[browser_ssb_newtab.js]
|
||||||
|
[browser_ssb_newwindow.js]
|
||||||
[browser_ssb_open.js]
|
[browser_ssb_open.js]
|
||||||
|
[browser_ssb_windowlocation.js]
|
||||||
|
[browser_ssb_windowopen.js]
|
||||||
|
skip-if = true # It is unclear what we want to do here.
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
async function testDirectLoad(target, checker) {
|
||||||
|
let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target);
|
||||||
|
|
||||||
|
let promise = checker(ssb);
|
||||||
|
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||||
|
"#direct",
|
||||||
|
{},
|
||||||
|
getBrowser(ssb)
|
||||||
|
);
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
await BrowserTestUtils.closeWindow(ssb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A link that should load inside the ssb
|
||||||
|
add_task(async function local() {
|
||||||
|
await testDirectLoad(gHttpsTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
await expectSSBLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
getBrowser(ssb).currentURI.spec,
|
||||||
|
gHttpsTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to an insecure site should load outside the ssb
|
||||||
|
add_task(async function insecure() {
|
||||||
|
await testDirectLoad(gHttpTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to a different host should load outside the ssb
|
||||||
|
add_task(async function external() {
|
||||||
|
await testDirectLoad(gHttpsOtherRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpsOtherRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
async function testNewTabLoad(target, checker) {
|
||||||
|
let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target);
|
||||||
|
|
||||||
|
let promise = checker(ssb);
|
||||||
|
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||||
|
"#new-tab",
|
||||||
|
{},
|
||||||
|
getBrowser(ssb)
|
||||||
|
);
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
await BrowserTestUtils.closeWindow(ssb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A link that should load inside the ssb
|
||||||
|
add_task(async function local() {
|
||||||
|
await testNewTabLoad(gHttpsTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
await expectSSBLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
getBrowser(ssb).currentURI.spec,
|
||||||
|
gHttpsTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to an insecure site should load outside the ssb
|
||||||
|
add_task(async function insecure() {
|
||||||
|
await testNewTabLoad(gHttpTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to a different host should load outside the ssb
|
||||||
|
add_task(async function external() {
|
||||||
|
await testNewTabLoad(gHttpsOtherRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpsOtherRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
async function testNewWindowLoad(target, checker) {
|
||||||
|
let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target);
|
||||||
|
|
||||||
|
let promise = checker(ssb);
|
||||||
|
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||||
|
"#new-window",
|
||||||
|
{},
|
||||||
|
getBrowser(ssb)
|
||||||
|
);
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
await BrowserTestUtils.closeWindow(ssb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A link that should load inside the ssb
|
||||||
|
add_task(async function local() {
|
||||||
|
await testNewWindowLoad(gHttpsTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
await expectSSBLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
getBrowser(ssb).currentURI.spec,
|
||||||
|
gHttpsTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to an insecure site should load outside the ssb
|
||||||
|
add_task(async function insecure() {
|
||||||
|
await testNewWindowLoad(gHttpTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to a different host should load outside the ssb
|
||||||
|
add_task(async function external() {
|
||||||
|
await testNewWindowLoad(gHttpsOtherRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpsOtherRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
async function testWindowLocationLoad(target, checker) {
|
||||||
|
let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target);
|
||||||
|
|
||||||
|
let promise = checker(ssb);
|
||||||
|
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||||
|
"#window-location",
|
||||||
|
{},
|
||||||
|
getBrowser(ssb)
|
||||||
|
);
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
await BrowserTestUtils.closeWindow(ssb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A link that should load inside the ssb
|
||||||
|
add_task(async function local() {
|
||||||
|
await testWindowLocationLoad(
|
||||||
|
gHttpsTestRoot + "empty_page.html",
|
||||||
|
async ssb => {
|
||||||
|
try {
|
||||||
|
await expectSSBLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
getBrowser(ssb).currentURI.spec,
|
||||||
|
gHttpsTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to an insecure site should load outside the ssb
|
||||||
|
add_task(async function insecure() {
|
||||||
|
await testWindowLocationLoad(gHttpTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to a different host should load outside the ssb
|
||||||
|
add_task(async function external() {
|
||||||
|
await testWindowLocationLoad(
|
||||||
|
gHttpsOtherRoot + "empty_page.html",
|
||||||
|
async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpsOtherRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
async function testWindowOpenLoad(target, checker) {
|
||||||
|
let ssb = await openSSB(gHttpsTestRoot + "test_page.html#" + target);
|
||||||
|
|
||||||
|
let promise = checker(ssb);
|
||||||
|
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||||
|
"#window-open",
|
||||||
|
{},
|
||||||
|
getBrowser(ssb)
|
||||||
|
);
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
await BrowserTestUtils.closeWindow(ssb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A link that should load inside the ssb
|
||||||
|
add_task(async function local() {
|
||||||
|
await testWindowOpenLoad(gHttpsTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
await expectSSBLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
getBrowser(ssb).currentURI.spec,
|
||||||
|
gHttpsTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to an insecure site should load outside the ssb
|
||||||
|
add_task(async function insecure() {
|
||||||
|
await testWindowOpenLoad(gHttpTestRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpTestRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// A link to a different host should load outside the ssb
|
||||||
|
add_task(async function external() {
|
||||||
|
await testWindowOpenLoad(gHttpsOtherRoot + "empty_page.html", async ssb => {
|
||||||
|
try {
|
||||||
|
let tab = await expectTabLoad(ssb);
|
||||||
|
Assert.equal(
|
||||||
|
tab.linkedBrowser.currentURI.spec,
|
||||||
|
gHttpsOtherRoot + "empty_page.html",
|
||||||
|
"Should have loaded the right uri."
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
} catch (e) {
|
||||||
|
// Any error will already have logged a failure.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -13,9 +13,34 @@ const gHttpsTestRoot = getRootDirectory(gTestPath).replace(
|
||||||
"https://example.com/"
|
"https://example.com/"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// A different secure site to use.
|
||||||
|
const gHttpsOtherRoot = getRootDirectory(gTestPath).replace(
|
||||||
|
"chrome://mochitests/content/",
|
||||||
|
"https://example.org/"
|
||||||
|
);
|
||||||
|
|
||||||
// The chrome url for the SSB UI.
|
// The chrome url for the SSB UI.
|
||||||
const SSB_WINDOW = "chrome://browser/content/ssb/ssb.html";
|
const SSB_WINDOW = "chrome://browser/content/ssb/ssb.html";
|
||||||
|
|
||||||
|
// Directly opens an SSB for the given URI. Resolves to the SSB DOM window after
|
||||||
|
// the SSB content has loaded.
|
||||||
|
async function openSSB(uri) {
|
||||||
|
if (!(uri instanceof Ci.nsIURI)) {
|
||||||
|
uri = Services.io.newURI(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
let openPromise = BrowserTestUtils.domWindowOpened(null, async domwin => {
|
||||||
|
await BrowserTestUtils.waitForEvent(domwin, "load");
|
||||||
|
return domwin.location.toString() == SSB_WINDOW;
|
||||||
|
});
|
||||||
|
|
||||||
|
SiteSpecificBrowserService.launchFromURI(uri);
|
||||||
|
|
||||||
|
let ssbwin = await openPromise;
|
||||||
|
await BrowserTestUtils.browserLoaded(getBrowser(ssbwin), true, uri.spec);
|
||||||
|
return ssbwin;
|
||||||
|
}
|
||||||
|
|
||||||
// Simulates opening a SSB from the main browser window. Resolves to the SSB
|
// Simulates opening a SSB from the main browser window. Resolves to the SSB
|
||||||
// DOM window after the SSB content has loaded.
|
// DOM window after the SSB content has loaded.
|
||||||
async function openSSBFromBrowserWindow(win = window) {
|
async function openSSBFromBrowserWindow(win = window) {
|
||||||
|
@ -34,7 +59,7 @@ async function openSSBFromBrowserWindow(win = window) {
|
||||||
Assert.ok(!openItem.hidden, "Open menu item should not be hidden");
|
Assert.ok(!openItem.hidden, "Open menu item should not be hidden");
|
||||||
|
|
||||||
let openPromise = BrowserTestUtils.domWindowOpened(null, async domwin => {
|
let openPromise = BrowserTestUtils.domWindowOpened(null, async domwin => {
|
||||||
await BrowserTestUtils.waitForEvent(domwin, "load");
|
await BrowserTestUtils.waitForEvent(domwin, "DOMContentLoaded");
|
||||||
return domwin.location.toString() == SSB_WINDOW;
|
return domwin.location.toString() == SSB_WINDOW;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -49,3 +74,135 @@ async function openSSBFromBrowserWindow(win = window) {
|
||||||
function getBrowser(ssbwin) {
|
function getBrowser(ssbwin) {
|
||||||
return ssbwin.document.getElementById("browser");
|
return ssbwin.document.getElementById("browser");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for a load in response to an attempt to navigate from the SSB. It
|
||||||
|
* listens for new tab opens in the main window, new window opens and loads in
|
||||||
|
* the SSB itself. It returns a promise.
|
||||||
|
*
|
||||||
|
* The `where` argument is a string saying where the load is expected to
|
||||||
|
* happen, "ssb", "tab" or "window". The promise rejects if the load happens
|
||||||
|
* somewhere else and the offending new item (tab or window) get closed. When
|
||||||
|
* the load is seen in the correct location different things are returned
|
||||||
|
* depending on `where`. For "tab" the new tab is returned (it will have
|
||||||
|
* finished loading), for "window" the new window is returned (it will have
|
||||||
|
* finished loading). The "ssb" case doesn't return anything.
|
||||||
|
*
|
||||||
|
* Generally use the methods below this as they look more obvious.
|
||||||
|
*/
|
||||||
|
function expectLoadSomewhere(ssb, where, win = window) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// Listens for a new tab opening in the main window.
|
||||||
|
const tabListener = async ({ target: tab }) => {
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
await BrowserTestUtils.browserLoaded(
|
||||||
|
tab.linkedBrowser,
|
||||||
|
true,
|
||||||
|
uri => uri != "about:blank"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (where != "tab") {
|
||||||
|
Assert.ok(
|
||||||
|
false,
|
||||||
|
`Did not expect ${
|
||||||
|
tab.linkedBrowser.currentURI.spec
|
||||||
|
} to load in a new tab.`
|
||||||
|
);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
reject(new Error("Page unexpectedly loaded in a new tab."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assert.ok(
|
||||||
|
true,
|
||||||
|
`${tab.linkedBrowser.currentURI.spec} loaded in a new tab as expected.`
|
||||||
|
);
|
||||||
|
resolve(tab);
|
||||||
|
};
|
||||||
|
win.gBrowser.tabContainer.addEventListener("TabOpen", tabListener);
|
||||||
|
|
||||||
|
// Listens for new top-level windows.
|
||||||
|
const winObserver = async (domwin, topic) => {
|
||||||
|
if (topic != "domwindowopened") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
await BrowserTestUtils.waitForEvent(
|
||||||
|
domwin,
|
||||||
|
"load",
|
||||||
|
uri => uri != "about:blank"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (where != "window") {
|
||||||
|
Assert.ok(false, `Did not expect a new ${domwin.location} to open.`);
|
||||||
|
await BrowserTestUtils.closeWindow(domwin);
|
||||||
|
reject(new Error("New window unexpectedly opened."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assert.ok(true, `${domwin.location} opened as expected.`);
|
||||||
|
resolve(domwin);
|
||||||
|
};
|
||||||
|
Services.ww.registerNotification(winObserver);
|
||||||
|
|
||||||
|
BrowserTestUtils.browserLoaded(
|
||||||
|
getBrowser(ssb),
|
||||||
|
true,
|
||||||
|
uri => uri != "about:blank"
|
||||||
|
).then(() => {
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
if (where != "ssb") {
|
||||||
|
Assert.ok(
|
||||||
|
false,
|
||||||
|
`Did not expect ${
|
||||||
|
getBrowser(ssb).currentURI.spec
|
||||||
|
} to load in the ssb window.`
|
||||||
|
);
|
||||||
|
reject(new Error("Page unexpectedly loaded in the ssb window."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assert.ok(
|
||||||
|
true,
|
||||||
|
`${
|
||||||
|
getBrowser(ssb).currentURI.spec
|
||||||
|
} loaded in the ssb window as expected.`
|
||||||
|
);
|
||||||
|
resolve();
|
||||||
|
}, reject);
|
||||||
|
|
||||||
|
// Makes sure that no notifications fire after the test is done. We assume
|
||||||
|
// that the SSB window will be closed between tests and so don't need to
|
||||||
|
// unregister the load listener for the SSB browser itself.
|
||||||
|
const cleanup = () => {
|
||||||
|
win.gBrowser.tabContainer.removeEventListener("TabOpen", tabListener);
|
||||||
|
Services.ww.unregisterNotification(winObserver);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for a load to occur in the ssb window but rejects if a new tab or
|
||||||
|
* window get opened.
|
||||||
|
*/
|
||||||
|
function expectSSBLoad(ssb, win = window) {
|
||||||
|
return expectLoadSomewhere(ssb, "ssb", win);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for a new tab to be opened and loaded. Rejects if a new window is
|
||||||
|
* opened or the ssb loads something before. Resolves with the new loaded tab.
|
||||||
|
*/
|
||||||
|
function expectTabLoad(ssb, win = window) {
|
||||||
|
return expectLoadSomewhere(ssb, "tab", win);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for a new window to be opened and loaded. Rejects if a new tab is
|
||||||
|
* opened or the ssb loads something before. Resolves with the new loaded
|
||||||
|
* window.
|
||||||
|
*/
|
||||||
|
function expectWindowOpen(ssb, win = window) {
|
||||||
|
return expectLoadSomewhere(ssb, "window", win);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,46 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script type="text/javascript">
|
||||||
|
function initialize() {
|
||||||
|
let target = window.location.hash;
|
||||||
|
if (target.length < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
target = target.substring(1);
|
||||||
|
|
||||||
|
let anchor = document.getElementById("direct");
|
||||||
|
anchor.href = target;
|
||||||
|
|
||||||
|
anchor = document.getElementById("new-tab");
|
||||||
|
anchor.href = target;
|
||||||
|
|
||||||
|
anchor = document.getElementById("new-window");
|
||||||
|
anchor.href = target;
|
||||||
|
|
||||||
|
anchor = document.getElementById("window-open");
|
||||||
|
anchor.onclick = (e) => {
|
||||||
|
window.open(target, "foo", "height=300,width=400");
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
anchor = document.getElementById("window-location");
|
||||||
|
anchor.onclick = (e) => {
|
||||||
|
window.location = target;
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", initialize, true);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<p><a id="direct">Direct link</a></p>
|
||||||
|
<p><a id="new-tab" target="_blank">New tab link</a></p>
|
||||||
|
<p><a id="new-window" target="foo">New window link</a></p>
|
||||||
|
<p><a id="window-open" href="#">window.open call</a></p>
|
||||||
|
<p><a id="window-location" href="#">window.location manipulation</a></p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче