diff options
author | Alessio Vanni <vannilla@firemail.cc> | 2019-06-21 22:03:03 +0200 |
---|---|---|
committer | Alessio Vanni <vannilla@firemail.cc> | 2019-06-21 22:03:03 +0200 |
commit | bdc82e65c4d30f541b5e0efcd3c0723103435c4e (patch) | |
tree | 43bbac3804e4fd006e75779b2537164ea1b9f91c /js/vapi-background.js | |
parent | 23f2978b8a41649c93f8b46c0f967f8b226928a4 (diff) | |
download | ematrix-bdc82e65c4d30f541b5e0efcd3c0723103435c4e.tar.lz ematrix-bdc82e65c4d30f541b5e0efcd3c0723103435c4e.tar.xz ematrix-bdc82e65c4d30f541b5e0efcd3c0723103435c4e.zip |
Split tab handling from vapi-background
That file is too large, let's split it up.
Diffstat (limited to 'js/vapi-background.js')
-rw-r--r-- | js/vapi-background.js | 712 |
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 |