fune/browser/components/ssb/content/ssb.js

261 lines
7 KiB
JavaScript

/* 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/. */
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.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",
WindowsSupport: "resource:///modules/ssb/WindowsSupport.jsm",
});
let gSSBBrowser = null;
var gSSB = null;
function init() {
gSSB = SiteSpecificBrowser.get(window.arguments[0]);
let uri = gSSB.startURI;
if (window.arguments.length > 1) {
uri = Services.io.newURI(window.arguments[1]);
}
window.browserDOMWindow = new BrowserDOMWindow();
gSSBBrowser = document.createXULElement("browser");
gSSBBrowser.setAttribute("id", "browser");
gSSBBrowser.setAttribute("type", "content");
gSSBBrowser.setAttribute("remote", "true");
gSSBBrowser.setAttribute("nodefaultsrc", "true");
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.addProgressListener(
new ProgressListener(),
Ci.nsIWebProgress.NOTIFY_STATE_ALL
);
gSSBBrowser.src = uri.spec;
document.getElementById("title").textContent = gSSB.name;
}
class ProgressListener {
constructor() {
this.isInitial = true;
}
/**
* Called when the load state changes
*
* @param {nsIWebProgress} webProgress
* @param {nsIRequest} request
* @param {Number} state
* @param {Number} status
*/
async onStateChange(webProgress, request, state, status) {
if (!webProgress.isTopLevel) {
return;
}
let final =
Ci.nsIWebProgressListener.STATE_IS_WINDOW +
Ci.nsIWebProgressListener.STATE_STOP;
if ((state & final) != final) {
return;
}
// Load complete. Does the SSB need an update?
let { isInitial } = this;
this.isInitial = false;
if (isInitial && gSSB.needsUpdate) {
await gSSB.updateFromBrowser(gSSBBrowser);
if (Services.appinfo.OS == "WINNT") {
WindowsSupport.applyOSIntegration(gSSB, window);
}
}
// So the testing harness knows when the ssb is properly initialized.
let event = new CustomEvent("SSBLoad");
gSSBBrowser.dispatchEvent(event);
}
}
ProgressListener.prototype.QueryInterface = ChromeUtils.generateQI([
"nsIWebProgressListener",
"nsISupportsWeakReference",
]);
class BrowserDOMWindow {
/**
* Called when a page in the main process needs a new window to display a new
* page in.
*
* @param {nsIURI?} uri
* @param {nsIOpenWindowInfo} openWindowInfo
* @param {Number} where
* @param {Number} flags
* @param {nsIPrincipal} triggeringPrincipal
* @param {nsIContentSecurityPolicy?} csp
* @return {BrowsingContext} the BrowsingContext the URI should be loaded in.
*/
createContentWindow(
uri,
openWindowInfo,
where,
flags,
triggeringPrincipal,
csp
) {
console.error(
"createContentWindow should never be called from a remote browser"
);
throw Components.Exception("", Cr.NS_ERROR_FAILURE);
}
/**
* Called from a page in the main process to open a new URI.
*
* @param {nsIURI} uri
* @param {nsIOpenWindowInfo} openWindowInfo
* @param {Number} where
* @param {Number} flags
* @param {nsIPrincipal} triggeringPrincipal
* @param {nsIContentSecurityPolicy?} csp
* @return {BrowsingContext} the BrowsingContext the URI should be loaded in.
*/
openURI(uri, openWindowInfo, where, flags, triggeringPrincipal, csp) {
console.error("openURI should never be called from a remote browser");
throw Components.Exception("", 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 {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,
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,
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 {string} name
* @return {Element} the frame element the URI should be loaded in.
*/
createContentWindowInFrame(uri, params, where, flags, name) {
return this.getContentWindowOrOpenURIInFrame(
uri,
params,
where,
flags,
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 {string} name
* @return {Element} the frame element the URI is loading in.
*/
openURIInFrame(uri, params, where, flags, name) {
return this.getContentWindowOrOpenURIInFrame(
uri,
params,
where,
flags,
name,
true
);
}
isTabContentWindow(window) {
// This method is probably not needed anymore: bug 1602915
return gSSBBrowser.contentWindow == window;
}
canClose() {
/* globals docShell */
for (let i = 0; i < docShell.childCount; i++) {
let childShell = docShell.getChildAt(i).QueryInterface(Ci.nsIDocShell);
let { contentViewer } = childShell;
if (contentViewer && !contentViewer.permitUnload()) {
return false;
}
}
return true;
}
get tabCount() {
return 1;
}
}
BrowserDOMWindow.prototype.QueryInterface = ChromeUtils.generateQI([
"nsIBrowserDOMWindow",
]);
window.addEventListener("DOMContentLoaded", init, true);