119 строки
3.9 KiB
JavaScript
119 строки
3.9 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/. */
|
|
"use strict";
|
|
|
|
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
|
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
|
|
|
/**
|
|
* A Map from trigger IDs to singleton trigger listeners. Each listener must
|
|
* have idempotent `init` and `uninit` methods.
|
|
*/
|
|
this.ASRouterTriggerListeners = new Map([
|
|
|
|
/**
|
|
* Attach listeners to every browser window to detect location changes, and
|
|
* notify the trigger handler whenever we navigate to a URL with a hostname
|
|
* we're looking for.
|
|
*/
|
|
["openURL", {
|
|
_initialized: false,
|
|
_triggerHandler: null,
|
|
_hosts: null,
|
|
|
|
/*
|
|
* If the listener is already initialised, `init` will replace the trigger
|
|
* handler and add any new hosts to `this._hosts`.
|
|
*/
|
|
init(triggerHandler, hosts = []) {
|
|
if (!this._initialized) {
|
|
this.onLocationChange = this.onLocationChange.bind(this);
|
|
|
|
// Listen for new windows being opened
|
|
Services.ww.registerNotification(this);
|
|
|
|
// Add listeners to all existing browser windows
|
|
for (let win of Services.wm.getEnumerator("navigator:browser")) {
|
|
if (win.closed || PrivateBrowsingUtils.isWindowPrivate(win)) {
|
|
continue;
|
|
}
|
|
win.gBrowser.addTabsProgressListener(this);
|
|
}
|
|
|
|
this._initialized = true;
|
|
}
|
|
this._triggerHandler = triggerHandler;
|
|
if (this._hosts) {
|
|
hosts.forEach(h => this._hosts.add(h));
|
|
} else {
|
|
this._hosts = new Set(hosts); // Clone the hosts to avoid unexpected behaviour
|
|
}
|
|
},
|
|
|
|
uninit() {
|
|
if (this._initialized) {
|
|
Services.ww.unregisterNotification(this);
|
|
|
|
for (let win of Services.wm.getEnumerator("navigator:browser")) {
|
|
if (win.closed || PrivateBrowsingUtils.isWindowPrivate(win)) {
|
|
continue;
|
|
}
|
|
|
|
win.gBrowser.removeTabsProgressListener(this);
|
|
}
|
|
|
|
this._initialized = false;
|
|
this._triggerHandler = null;
|
|
this._hosts = null;
|
|
}
|
|
},
|
|
|
|
onLocationChange(aBrowser, aWebProgress, aRequest, aLocationURI, aFlags) {
|
|
const location = aLocationURI ? aLocationURI.spec : "";
|
|
// Some websites trigger redirect events after they finish loading even
|
|
// though the location remains the same. This results in onLocationChange
|
|
// events to be fired twice.
|
|
const isSameDocument = !!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
|
|
if (location && aWebProgress.isTopLevel && !isSameDocument) {
|
|
try {
|
|
const host = (new URL(location)).hostname;
|
|
if (this._hosts.has(host)) {
|
|
this._triggerHandler(aBrowser, {id: "openURL", param: host});
|
|
}
|
|
} catch (e) {} // Couldn't parse location URL
|
|
}
|
|
},
|
|
|
|
observe(win, topic, data) {
|
|
let onLoad;
|
|
|
|
switch (topic) {
|
|
case "domwindowopened":
|
|
if (!(win instanceof Ci.nsIDOMWindow) || win.closed || PrivateBrowsingUtils.isWindowPrivate(win)) {
|
|
break;
|
|
}
|
|
onLoad = () => {
|
|
// Ignore non-browser windows.
|
|
if (win.document.documentElement.getAttribute("windowtype") === "navigator:browser") {
|
|
win.gBrowser.addTabsProgressListener(this);
|
|
}
|
|
};
|
|
win.addEventListener("load", onLoad, {once: true});
|
|
break;
|
|
|
|
case "domwindowclosed":
|
|
if ((win instanceof Ci.nsIDOMWindow) &&
|
|
win.document.documentElement.getAttribute("windowtype") === "navigator:browser") {
|
|
win.gBrowser.removeTabsProgressListener(this);
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
}],
|
|
]);
|
|
|
|
const EXPORTED_SYMBOLS = ["ASRouterTriggerListeners"];
|