aboutsummaryrefslogtreecommitdiffstats
path: root/js/vapi-background.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/vapi-background.js')
-rw-r--r--js/vapi-background.js712
1 files changed, 8 insertions, 704 deletions
diff --git a/js/vapi-background.js b/js/vapi-background.js
index f861338..d939186 100644
--- a/js/vapi-background.js
+++ b/js/vapi-background.js
@@ -90,6 +90,14 @@
// eMatrix: do we?
let expectedNumberOfCleanups = 7;
+ vAPI.addCleanUpTask = function (task) {
+ if (typeof task !== 'function') {
+ return;
+ }
+
+ cleanupTasks.push(task);
+ }
+
window.addEventListener('unload', function () {
// if (typeof vAPI.app.onShutdown === 'function') {
// vAPI.app.onShutdown();
@@ -770,710 +778,6 @@
return tabId.toString() === '-1';
};
- vAPI.noTabId = '-1';
-
- // Tabs and related functions
- vAPI.tabs = {};
-
- vAPI.tabs.registerListeners = function() {
- tabWatcher.start();
- };
-
- vAPI.tabs.get = function (tabId, callback) {
- // eMatrix: the following might be obsoleted (though probably
- // still relevant at least for Pale Moon.)
- //
- // Firefox:
- //
- // browser -> ownerDocument -> defaultView -> gBrowser -> browsers --+
- // ^ |
- // | |
- // +--------------------------------------------------------------+
- //
- // browser (browser)
- // contentTitle
- // currentURI
- // ownerDocument (XULDocument)
- // defaultView (ChromeWindow)
- // gBrowser (tabbrowser OR browser)
- // browsers (browser)
- // selectedBrowser
- // selectedTab
- // tabs (tab.tabbrowser-tab)
- //
- // Fennec: (what I figured so far)
- //
- // tab -> browser windows -> window -> BrowserApp -> tabs --+
- // ^ window |
- // | |
- // +-----------------------------------------------------------+
- //
- // tab
- // browser
- // [manual search to go back to tab from list of windows]
- let browser;
-
- if (tabId === null) {
- browser = tabWatcher.currentBrowser();
- tabId = tabWatcher.tabIdFromTarget(browser);
- } else {
- browser = tabWatcher.browserFromTabId(tabId);
- }
-
- // For internal use
- if (typeof callback !== 'function') {
- return browser;
- }
-
- if (!browser || !browser.currentURI) {
- callback();
- return;
- }
-
- let win = getOwnerWindow(browser);
- let tabBrowser = getTabBrowser(win);
-
- callback({
- id: tabId,
- windowId: winWatcher.idFromWindow(win),
- active: tabBrowser !== null
- && browser === tabBrowser.selectedBrowser,
- url: browser.currentURI.asciiSpec,
- title: browser.contentTitle
- });
- };
-
- vAPI.tabs.getAllSync = function (window) {
- let win;
- let tabs = [];
-
- for (let win of winWatcher.getWindows()) {
- if (window && window !== win) {
- continue;
- }
-
- let tabBrowser = getTabBrowser(win);
- if (tabBrowser === null) {
- continue;
- }
-
- // This can happens if a tab-less window is currently opened.
- // Example of a tab-less window: one opened from clicking
- // "View Page Source".
- if (!tabBrowser.tabs) {
- continue;
- }
-
- for (let tab of tabBrowser.tabs) {
- tabs.push(tab);
- }
- }
-
- return tabs;
- };
-
- vAPI.tabs.getAll = function (callback) {
- let tabs = [];
-
- for (let browser of tabWatcher.browsers()) {
- let tab = tabWatcher.tabFromBrowser(browser);
-
- if (tab === null) {
- continue;
- }
-
- if (tab.hasAttribute('pending')) {
- continue;
- }
-
- tabs.push({
- id: tabWatcher.tabIdFromTarget(browser),
- url: browser.currentURI.asciiSpec
- });
- }
-
- callback(tabs);
- };
-
- vAPI.tabs.open = function (details) {
- // properties of the details object:
- // + url - the address that will be opened
- // + tabId:- the tab is used if set, instead of creating a new one
- // + index: - undefined: end of the list, -1: following tab, or
- // after index
- // + active: - opens the tab in background - true and undefined:
- // foreground
- // + select: - if a tab is already opened with that url, then
- // select it instead of opening a new one
- if (!details.url) {
- return null;
- }
-
- // extension pages
- if (/^[\w-]{2,}:/.test(details.url) === false) {
- details.url = vAPI.getURL(details.url);
- }
-
- if (details.select) {
- let URI = Services.io.newURI(details.url, null, null);
-
- for (let tab of this.getAllSync()) {
- let browser = tabWatcher.browserFromTarget(tab);
-
- // https://github.com/gorhill/uBlock/issues/2558
- if (browser === null) {
- continue;
- }
-
- // Or simply .equals if we care about the fragment
- if (URI.equalsExceptRef(browser.currentURI) === false) {
- continue;
- }
-
- this.select(tab);
-
- // Update URL if fragment is different
- if (URI.equals(browser.currentURI) === false) {
- browser.loadURI(URI.asciiSpec);
- }
-
- return;
- }
- }
-
- if (details.active === undefined) {
- details.active = true;
- }
-
- if (details.tabId) {
- let tab = tabWatcher.browserFromTabId(details.tabId);
-
- if (tab) {
- tabWatcher.browserFromTarget(tab).loadURI(details.url);
- return;
- }
- }
-
- // Open in a standalone window
- if (details.popup === true) {
- Services.ww.openWindow(self,
- details.url,
- null,
- 'location=1,menubar=1,personalbar=1,'
- +'resizable=1,toolbar=1',
- null);
- return;
- }
-
- let win = winWatcher.getCurrentWindow();
- let tabBrowser = getTabBrowser(win);
-
- if (tabBrowser === null) {
- return;
- }
-
- if (details.index === -1) {
- details.index =
- tabBrowser.browsers.indexOf(tabBrowser.selectedBrowser) + 1;
- }
-
- let tab = tabBrowser.loadOneTab(details.url, {
- inBackground: !details.active
- });
-
- if (details.index !== undefined) {
- tabBrowser.moveTabTo(tab, details.index);
- }
- };
-
- vAPI.tabs.replace = function (tabId, url) {
- // Replace the URL of a tab. Noop if the tab does not exist.
- let targetURL = url;
-
- // extension pages
- if (/^[\w-]{2,}:/.test(targetURL) !== true) {
- targetURL = vAPI.getURL(targetURL);
- }
-
- let browser = tabWatcher.browserFromTabId(tabId);
- if (browser) {
- browser.loadURI(targetURL);
- }
- };
-
- vAPI.tabs._remove = function (tab, tabBrowser) {
- if (tabBrowser) {
- tabBrowser.removeTab(tab);
- }
- };
- function removeInternal(tab, tabBrowser) {
- if (tabBrowser) {
- tabBrowser.removeTab(tab);
- }
- }
-
- vAPI.tabs.remove = function (tabId) {
- let browser = tabWatcher.browserFromTabId(tabId);
- if (!browser) {
- return;
- }
-
- let tab = tabWatcher.tabFromBrowser(browser);
- if (!tab) {
- return;
- }
-
- removeInternal(tab, getTabBrowser(getOwnerWindow(browser)));
- };
-
- vAPI.tabs.reload = function (tabId) {
- let browser = tabWatcher.browserFromTabId(tabId);
- if (!browser) {
- return;
- }
-
- browser.webNavigation.reload(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
- };
-
- vAPI.tabs.select = function (tab) {
- if (typeof tab !== 'object') {
- tab = tabWatcher.tabFromBrowser(tabWatcher.browserFromTabId(tab));
- }
- if (!tab) {
- return;
- }
-
- // https://github.com/gorhill/uBlock/issues/470
- let win = getOwnerWindow(tab);
- win.focus();
-
- let tabBrowser = getTabBrowser(win);
- if (tabBrowser) {
- tabBrowser.selectedTab = tab;
- }
- };
-
- vAPI.tabs.injectScript = function (tabId, details, callback) {
- let browser = tabWatcher.browserFromTabId(tabId);
- if (!browser) {
- return;
- }
-
- if (typeof details.file !== 'string') {
- return;
- }
-
- details.file = vAPI.getURL(details.file);
- browser.messageManager.sendAsyncMessage(location.host + ':broadcast',
- JSON.stringify({
- broadcast: true,
- channelName: 'vAPI',
- msg: {
- cmd: 'injectScript',
- details: details
- }
- }));
-
- if (typeof callback === 'function') {
- vAPI.setTimeout(callback, 13);
- }
- };
-
- let tabWatcher = (function () {
- // TODO: find out whether we need a janitor to take care of stale entries.
-
- // https://github.com/gorhill/uMatrix/issues/540
- // Use only weak references to hold onto browser references.
- let browserToTabIdMap = new WeakMap();
- let tabIdToBrowserMap = new Map();
- let tabIdGenerator = 1;
-
- let indexFromBrowser = function (browser) {
- if (!browser) {
- return -1;
- }
-
- let win = getOwnerWindow(browser);
- if (!win) {
- return -1;
- }
-
- let tabBrowser = getTabBrowser(win);
- if (tabBrowser === null) {
- return -1;
- }
-
- // This can happen, for example, the `view-source:`
- // window, there is no tabbrowser object, the browser
- // object sits directly in the window.
- if (tabBrowser === browser) {
- return 0;
- }
-
- return tabBrowser.browsers.indexOf(browser);
- };
-
- let indexFromTarget = function (target) {
- return indexFromBrowser(browserFromTarget(target));
- };
-
- let tabFromBrowser = function (browser) {
- let i = indexFromBrowser(browser);
- if (i === -1) {
- return null;
- }
-
- let win = getOwnerWindow(browser);
- if (!win) {
- return null;
- }
-
- let tabBrowser = getTabBrowser(win);
- if (tabBrowser === null) {
- return null;
- }
-
- if (!tabBrowser.tabs || i >= tabBrowser.tabs.length) {
- return null;
- }
-
- return tabBrowser.tabs[i];
- };
-
- let browserFromTarget = function (target) {
- if (!target) {
- return null;
- }
-
- if (target.linkedPanel) {
- // target is a tab
- target = target.linkedBrowser;
- }
-
- if (target.localName !== 'browser') {
- return null;
- }
-
- return target;
- };
-
- let tabIdFromTarget = function (target) {
- let browser = browserFromTarget(target);
- if (browser === null) {
- return vAPI.noTabId;
- }
-
- let tabId = browserToTabIdMap.get(browser);
- if (tabId === undefined) {
- tabId = '' + tabIdGenerator++;
- browserToTabIdMap.set(browser, tabId);
- tabIdToBrowserMap.set(tabId, Cu.getWeakReference(browser));
- }
-
- return tabId;
- };
-
- let browserFromTabId = function (tabId) {
- let weakref = tabIdToBrowserMap.get(tabId);
- let browser = weakref && weakref.get();
-
- return browser || null;
- };
-
- let currentBrowser = function () {
- let win = winWatcher.getCurrentWindow();
-
- // https://github.com/gorhill/uBlock/issues/399
- // getTabBrowser() can return null at browser launch time.
- let tabBrowser = getTabBrowser(win);
- if (tabBrowser === null) {
- return null;
- }
-
- return browserFromTarget(tabBrowser.selectedTab);
- };
-
- let removeBrowserEntry = function (tabId, browser) {
- if (tabId && tabId !== vAPI.noTabId) {
- vAPI.tabs.onClosed(tabId);
- delete vAPI.toolbarButton.tabs[tabId];
- tabIdToBrowserMap.delete(tabId);
- }
-
- if (browser) {
- browserToTabIdMap.delete(browser);
- }
- };
-
- let removeTarget = function (target) {
- onClose({
- target: target
- });
- };
-
- let getAllBrowsers = function () {
- let browsers = [];
-
- for (let [tabId, weakref] of tabIdToBrowserMap) {
- let browser = weakref.get();
-
- // TODO: Maybe call removeBrowserEntry() if the
- // browser no longer exists?
- if (browser) {
- browsers.push(browser);
- }
- }
-
- return browsers;
- };
-
- // var onOpen = function (target) {
- // var tabId = tabIdFromTarget(target);
- // var browser = browserFromTabId(tabId);
- // vAPI.tabs.onNavigation({
- // frameId: 0,
- // tabId: tabId,
- // url: browser.currentURI.asciiSpec,
- // });
- // };
-
- var onShow = function ({target}) {
- tabIdFromTarget(target);
- };
-
- var onClose = function ({target}) {
- // target is tab in Firefox, browser in Fennec
- let browser = browserFromTarget(target);
- let tabId = browserToTabIdMap.get(browser);
- removeBrowserEntry(tabId, browser);
- };
-
- var onSelect = function ({target}) {
- // This is an entry point: when creating a new tab, it is
- // not always reported through onLocationChanged...
- // Sigh. It is "reported" here however.
- let browser = browserFromTarget(target);
- let tabId = browserToTabIdMap.get(browser);
-
- if (tabId === undefined) {
- tabId = tabIdFromTarget(target);
- vAPI.tabs.onNavigation({
- frameId: 0,
- tabId: tabId,
- url: browser.currentURI.asciiSpec
- });
- }
-
- vAPI.setIcon(tabId, getOwnerWindow(target));
- };
-
- let locationChangedMessageName = location.host + ':locationChanged';
-
- let onLocationChanged = function (e) {
- let details = e.data;
-
- // Ignore notifications related to our popup
- if (details.url.lastIndexOf(vAPI.getURL('popup.html'), 0) === 0) {
- return;
- }
-
- let browser = e.target;
- let tabId = tabIdFromTarget(browser);
- if (tabId === vAPI.noTabId) {
- return;
- }
-
- // LOCATION_CHANGE_SAME_DOCUMENT = "did not load a new document"
- if (details.flags
- & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
- vAPI.tabs.onUpdated(tabId, {url: details.url}, {
- frameId: 0,
- tabId: tabId,
- url: browser.currentURI.asciiSpec
- });
- return;
- }
-
- // https://github.com/chrisaljoudi/uBlock/issues/105
- // Allow any kind of pages
- vAPI.tabs.onNavigation({
- frameId: 0,
- tabId: tabId,
- url: details.url
- });
- };
-
- let attachToTabBrowser = function (window) {
- if (typeof vAPI.toolbarButton.attachToNewWindow === 'function') {
- vAPI.toolbarButton.attachToNewWindow(window);
- }
-
- let tabBrowser = getTabBrowser(window);
- if (tabBrowser === null) {
- return;
- }
-
- let tabContainer;
- if (tabBrowser.deck) {
- // Fennec
- tabContainer = tabBrowser.deck;
- } else if (tabBrowser.tabContainer) {
- // Firefox
- tabContainer = tabBrowser.tabContainer;
- vAPI.contextMenu.register(document);
- }
-
- // https://github.com/gorhill/uBlock/issues/697
- // Ignore `TabShow` events: unfortunately the `pending`
- // attribute is not set when a tab is opened as a result
- // of session restore -- it is set *after* the event is
- // fired in such case.
- if (tabContainer) {
- tabContainer.addEventListener('TabShow', onShow);
- tabContainer.addEventListener('TabClose', onClose);
- // when new window is opened TabSelect doesn't run on
- // the selected tab?
- tabContainer.addEventListener('TabSelect', onSelect);
- }
- };
-
- var canAttachToTabBrowser = function (window) {
- // https://github.com/gorhill/uBlock/issues/906
- // Ensure the environment is ready before trying to attaching.
- let document = window && window.document;
- if (!document || document.readyState !== 'complete') {
- return false;
- }
-
- // On some platforms, the tab browser isn't immediately
- // available, try waiting a bit if this
- // https://github.com/gorhill/uBlock/issues/763
- // Not getting a tab browser should not prevent from
- // attaching ourself to the window.
- let tabBrowser = getTabBrowser(window);
- if (tabBrowser === null) {
- return false;
- }
-
- return winWatcher.toBrowserWindow(window) !== null;
- };
-
- let onWindowLoad = function (win) {
- deferUntil(canAttachToTabBrowser.bind(null, win),
- attachToTabBrowser.bind(null, win));
- };
-
- let onWindowUnload = function (win) {
- vAPI.contextMenu.unregister(win.document);
-
- let tabBrowser = getTabBrowser(win);
- if (tabBrowser === null) {
- return;
- }
-
- let tabContainer = tabBrowser.tabContainer;
- if (tabContainer) {
- tabContainer.removeEventListener('TabShow', onShow);
- tabContainer.removeEventListener('TabClose', onClose);
- tabContainer.removeEventListener('TabSelect', onSelect);
- }
-
- // https://github.com/gorhill/uBlock/issues/574
- // To keep in mind: not all windows are tab containers,
- // sometimes the window IS the tab.
- let tabs;
- if (tabBrowser.tabs) {
- tabs = tabBrowser.tabs;
- } else if (tabBrowser.localName === 'browser') {
- tabs = [tabBrowser];
- } else {
- tabs = [];
- }
-
- let browser;
- let URI;
- let tabId;
- for (let i=tabs.length-1; i>=0; --i) {
- let tab = tabs[i];
- browser = browserFromTarget(tab);
- if (browser === null) {
- continue;
- }
-
- URI = browser.currentURI;
- // Close extension tabs
- if (URI.schemeIs('chrome') && URI.host === location.host) {
- removeInternal(tab, getTabBrowser(win));
- }
-
- tabId = browserToTabIdMap.get(browser);
- if (tabId !== undefined) {
- removeBrowserEntry(tabId, browser);
- tabIdToBrowserMap.delete(tabId);
- }
- browserToTabIdMap.delete(browser);
- }
- };
-
- var start = function () {
- // Initialize map with existing active tabs
- let tabBrowser;
- let tabs;
-
- for (let win of winWatcher.getWindows()) {
- onWindowLoad(win);
-
- tabBrowser = getTabBrowser(win);
- if (tabBrowser === null) {
- continue;
- }
-
- for (let tab of tabBrowser.tabs) {
- if (!tab.hasAttribute('pending')) {
- tabIdFromTarget(tab);
- }
- }
- }
-
- winWatcher.onOpenWindow = onWindowLoad;
- winWatcher.onCloseWindow = onWindowUnload;
-
- vAPI.messaging.globalMessageManager
- .addMessageListener(locationChangedMessageName,
- onLocationChanged);
- };
-
- let stop = function () {
- winWatcher.onOpenWindow = null;
- winWatcher.onCloseWindow = null;
-
- vAPI.messaging.globalMessageManager
- .removeMessageListener(locationChangedMessageName,
- onLocationChanged);
-
- for (let win of winWatcher.getWindows()) {
- onWindowUnload(win);
- }
-
- browserToTabIdMap = new WeakMap();
- tabIdToBrowserMap.clear();
- };
-
- cleanupTasks.push(stop);
-
- return {
- browsers: getAllBrowsers,
- browserFromTabId: browserFromTabId,
- browserFromTarget: browserFromTarget,
- currentBrowser: currentBrowser,
- indexFromTarget: indexFromTarget,
- removeTarget: removeTarget,
- start: start,
- tabFromBrowser: tabFromBrowser,
- tabIdFromTarget: tabIdFromTarget
- };
- })();
-
// Icon-related stuff
vAPI.setIcon = function (tabId, iconId, badge) {
// If badge is undefined, then setIcon was called from the