diff options
Diffstat (limited to 'js/vapi-background.js')
-rw-r--r-- | js/vapi-background.js | 1241 |
1 files changed, 525 insertions, 716 deletions
diff --git a/js/vapi-background.js b/js/vapi-background.js index ff64178..2e79839 100644 --- a/js/vapi-background.js +++ b/js/vapi-background.js @@ -2,7 +2,7 @@ ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors - Copyright (C) 2019-2020 Alessio Vanni + Copyright (C) 2019-2022 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -38,53 +38,53 @@ // Icon-related stuff vAPI.setIcon = function (tabId, iconId, badge) { - // If badge is undefined, then setIcon was called from the - // TabSelect event - let win; - if (badge === undefined) { + // If badge is undefined, then setIcon was called from the + // TabSelect event + let win; + if (badge === undefined) { win = iconId; - } else { + } else { win = vAPI.window.getCurrentWindow(); - } + } - let tabBrowser = vAPI.browser.getTabBrowser(win); - if (tabBrowser === null) { + let tabBrowser = vAPI.browser.getTabBrowser(win); + if (tabBrowser === null) { return; - } + } - let curTabId = vAPI.tabs.manager.tabIdFromTarget(tabBrowser.selectedTab); - let tb = vAPI.toolbarButton; + let curTabId = vAPI.tabs.manager.tabIdFromTarget(tabBrowser.selectedTab); + let tb = vAPI.toolbarButton; - // from 'TabSelect' event - if (tabId === undefined) { + // from 'TabSelect' event + if (tabId === undefined) { tabId = curTabId; - } else if (badge !== undefined) { + } else if (badge !== undefined) { tb.tabs[tabId] = { - badge: badge, img: iconId - }; - } + badge: badge, img: iconId + }; + } - if (tabId === curTabId) { + if (tabId === curTabId) { tb.updateState(win, tabId); - } + } }; vAPI.httpObserver = { - classDescription: 'net-channel-event-sinks for ' + location.host, - classID: Components.ID('{5d2e2797-6d68-42e2-8aeb-81ce6ba16b95}'), - contractID: '@' + location.host + '/net-channel-event-sinks;1', - REQDATAKEY: location.host + 'reqdata', - ABORT: Components.results.NS_BINDING_ABORTED, - ACCEPT: Components.results.NS_SUCCEEDED, - // Request types: - // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants - // eMatrix: we can just use nsIContentPolicy's built-in - // constants, can we? - frameTypeMap: { + classDescription: 'net-channel-event-sinks for ' + location.host, + classID: Components.ID('{5d2e2797-6d68-42e2-8aeb-81ce6ba16b95}'), + contractID: '@' + location.host + '/net-channel-event-sinks;1', + REQDATAKEY: location.host + 'reqdata', + ABORT: Components.results.NS_BINDING_ABORTED, + ACCEPT: Components.results.NS_SUCCEEDED, + // Request types: + // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants + // eMatrix: we can just use nsIContentPolicy's built-in + // constants, can we? + frameTypeMap: { 6: 'main_frame', 7: 'sub_frame' - }, - typeMap: { + }, + typeMap: { 1: 'other', 2: 'script', 3: 'image', @@ -106,434 +106,434 @@ 20: 'xmlhttprequest', 21: 'imageset', 22: 'web_manifest' - }, - mimeTypeMap: { + }, + mimeTypeMap: { 'audio': 15, 'video': 15 - }, - get componentRegistrar () { + }, + get componentRegistrar () { return Components.manager.QueryInterface(Ci.nsIComponentRegistrar); - }, - get categoryManager () { + }, + get categoryManager () { return Cc['@mozilla.org/categorymanager;1'] .getService(Ci.nsICategoryManager); - }, - QueryInterface: (function () { + }, + QueryInterface: (function () { var {XPCOMUtils} = - Cu.import('resource://gre/modules/XPCOMUtils.jsm', null); + Cu.import('resource://gre/modules/XPCOMUtils.jsm', null); return XPCOMUtils.generateQI([ - Ci.nsIFactory, - Ci.nsIObserver, - Ci.nsIChannelEventSink, - Ci.nsISupportsWeakReference + Ci.nsIFactory, + Ci.nsIObserver, + Ci.nsIChannelEventSink, + Ci.nsISupportsWeakReference ]); - })(), - createInstance: function (outer, iid) { + })(), + createInstance: function (outer, iid) { if (outer) { - throw Components.results.NS_ERROR_NO_AGGREGATION; + throw Components.results.NS_ERROR_NO_AGGREGATION; } return this.QueryInterface(iid); - }, - register: function () { + }, + register: function () { Services.obs.addObserver(this, 'http-on-modify-request', true); Services.obs.addObserver(this, 'http-on-examine-response', true); Services.obs.addObserver(this, 'http-on-examine-cached-response', true); // Guard against stale instances not having been unregistered if (this.componentRegistrar.isCIDRegistered(this.classID)) { - try { + try { this.componentRegistrar - .unregisterFactory(this.classID, - Components.manager - .getClassObject(this.classID, - Ci.nsIFactory)); - } catch (ex) { + .unregisterFactory(this.classID, + Components.manager + .getClassObject(this.classID, + Ci.nsIFactory)); + } catch (ex) { console.error('eMatrix> httpObserver > ' - +'unable to unregister stale instance: ', ex); - } + +'unable to unregister stale instance: ', ex); + } } this.componentRegistrar.registerFactory(this.classID, - this.classDescription, - this.contractID, - this); + this.classDescription, + this.contractID, + this); this.categoryManager.addCategoryEntry('net-channel-event-sinks', - this.contractID, - this.contractID, - false, - true); - }, - unregister: function () { + this.contractID, + this.contractID, + false, + true); + }, + unregister: function () { Services.obs.removeObserver(this, 'http-on-modify-request'); Services.obs.removeObserver(this, 'http-on-examine-response'); Services.obs.removeObserver(this, 'http-on-examine-cached-response'); this.componentRegistrar.unregisterFactory(this.classID, this); this.categoryManager.deleteCategoryEntry('net-channel-event-sinks', - this.contractID, - false); - }, - handleRequest: function (channel, URI, tabId, rawType) { + this.contractID, + false); + }, + handleRequest: function (channel, URI, tabId, rawType) { let type = this.typeMap[rawType] || 'other'; let onBeforeRequest = vAPI.net.onBeforeRequest; if (onBeforeRequest.types === null - || onBeforeRequest.types.has(type)) { - let result = onBeforeRequest.callback({ + || onBeforeRequest.types.has(type)) { + let result = onBeforeRequest.callback({ parentFrameId: type === 'main_frame' ? -1 : 0, tabId: tabId, type: type, url: URI.asciiSpec - }); + }); - if (typeof result === 'object') { + if (typeof result === 'object') { channel.cancel(this.ABORT); return true; - } + } } let onBeforeSendHeaders = vAPI.net.onBeforeSendHeaders; if (onBeforeSendHeaders.types === null - || onBeforeSendHeaders.types.has(type)) { - let requestHeaders = HTTPRequestHeaders.factory(channel); - let newHeaders = onBeforeSendHeaders.callback({ + || onBeforeSendHeaders.types.has(type)) { + let requestHeaders = HTTPRequestHeaders.factory(channel); + let newHeaders = onBeforeSendHeaders.callback({ parentFrameId: type === 'main_frame' ? -1 : 0, requestHeaders: requestHeaders.headers, tabId: tabId, type: type, url: URI.asciiSpec, method: channel.requestMethod - }); + }); - if (newHeaders) { + if (newHeaders) { requestHeaders.update(); - } - requestHeaders.dispose(); + } + requestHeaders.dispose(); } return false; - }, - channelDataFromChannel: function (channel) { + }, + channelDataFromChannel: function (channel) { if (channel instanceof Ci.nsIWritablePropertyBag) { - try { + try { return channel.getProperty(this.REQDATAKEY) || null; - } catch (ex) { - // Ignore - } + } catch (ex) { + // Ignore + } } return null; - }, - // https://github.com/gorhill/uMatrix/issues/165 - // https://developer.mozilla.org/en-US/Firefox/Releases/3.5/Updating_extensions#Getting_a_load_context_from_a_request - // Not sure `ematrix:shouldLoad` is still needed, eMatrix does - // not care about embedded frames topography. - // Also: - // https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Limitations_of_chrome_scripts - tabIdFromChannel: function (channel) { + }, + // https://github.com/gorhill/uMatrix/issues/165 + // https://developer.mozilla.org/en-US/Firefox/Releases/3.5/Updating_extensions#Getting_a_load_context_from_a_request + // Not sure `ematrix:shouldLoad` is still needed, eMatrix does + // not care about embedded frames topography. + // Also: + // https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Limitations_of_chrome_scripts + tabIdFromChannel: function (channel) { let lc; try { - lc = channel.notificationCallbacks.getInterface(Ci.nsILoadContext); + lc = channel.notificationCallbacks.getInterface(Ci.nsILoadContext); } catch(ex) { - // Ignore + // Ignore } if (!lc) { - try { + try { lc = channel.loadGroup.notificationCallbacks - .getInterface(Ci.nsILoadContext); - } catch(ex) { - // Ignore - } + .getInterface(Ci.nsILoadContext); + } catch(ex) { + // Ignore + } - if (!lc) { + if (!lc) { return vAPI.noTabId; - } + } } if (lc.topFrameElement) { - return vAPI.tabs.manager.tabIdFromTarget(lc.topFrameElement); + return vAPI.tabs.manager.tabIdFromTarget(lc.topFrameElement); } let win; try { - win = lc.associatedWindow; + win = lc.associatedWindow; } catch (ex) { - // Ignore - } + // Ignore + } if (!win) { - return vAPI.noTabId; + return vAPI.noTabId; } if (win.top) { - win = win.top; + win = win.top; } let tabBrowser; try { - tabBrowser = - vAPI.browser.getTabBrowser - (win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell).rootTreeItem - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow)); + tabBrowser = + vAPI.browser.getTabBrowser + (win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell).rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow)); } catch (ex) { - // Ignore - } + // Ignore + } if (!tabBrowser) { - return vAPI.noTabId; + return vAPI.noTabId; } if (tabBrowser.getBrowserForContentWindow) { - return vAPI.tabs.manager - .tabIdFromTarget(tabBrowser.getBrowserForContentWindow(win)); + return vAPI.tabs.manager + .tabIdFromTarget(tabBrowser.getBrowserForContentWindow(win)); } // Falling back onto _getTabForContentWindow to ensure older // versions of Firefox work well. return tabBrowser._getTabForContentWindow - ? vAPI.tabs.manager - .tabIdFromTarget(tabBrowser._getTabForContentWindow(win)) - : vAPI.noTabId; - }, - rawtypeFromContentType: function (channel) { + ? vAPI.tabs.manager + .tabIdFromTarget(tabBrowser._getTabForContentWindow(win)) + : vAPI.noTabId; + }, + rawtypeFromContentType: function (channel) { let mime = channel.contentType; if (!mime) { - return 0; + return 0; } let pos = mime.indexOf('/'); if (pos === -1) { - pos = mime.length; + pos = mime.length; } return this.mimeTypeMap[mime.slice(0, pos)] || 0; - }, - operate: function (channel, URI, topic) { - let channelData = this.channelDataFromChannel(channel); + }, + operate: function (channel, URI, topic) { + let channelData = this.channelDataFromChannel(channel); - if (topic.lastIndexOf('http-on-examine-', 0) === 0) { - if (channelData === null) { + if (topic.lastIndexOf('http-on-examine-', 0) === 0) { + if (channelData === null) { return; - } + } - let type = this.frameTypeMap[channelData[1]]; - if (!type) { + let type = this.frameTypeMap[channelData[1]]; + if (!type) { return; - } - - // topic = ['Content-Security-Policy', - // 'Content-Security-Policy-Report-Only']; - // - // Can send empty responseHeaders as these headers are - // only added to and then merged. - // - // TODO: Find better place for this, needs to be set - // before onHeadersReceived.callback. Web workers not - // blocked in Pale Moon as child-src currently - // unavailable, see: - // - // https://github.com/MoonchildProductions/Pale-Moon/issues/949 - // - // eMatrix: as of Pale Moon 28 it seems child-src is - // available and depracated(?) - if (ηMatrix.cspNoWorker === undefined) { + } + + // topic = ['Content-Security-Policy', + // 'Content-Security-Policy-Report-Only']; + // + // Can send empty responseHeaders as these headers are + // only added to and then merged. + // + // TODO: Find better place for this, needs to be set + // before onHeadersReceived.callback. Web workers not + // blocked in Pale Moon as child-src currently + // unavailable, see: + // + // https://github.com/MoonchildProductions/Pale-Moon/issues/949 + // + // eMatrix: as of Pale Moon 28 it seems child-src is + // available and depracated(?) + if (ηMatrix.cspNoWorker === undefined) { // ηMatrix.cspNoWorker = "child-src 'none'; " - // +"frame-src data: blob: *; " - // +"report-uri about:blank"; - ηMatrix.cspNoWorker = "worker-src 'none'; " - +"frame-src data: blob: *; " - +"report-uri about:blank"; - } - - let result = vAPI.net.onHeadersReceived.callback({ + // +"frame-src data: blob: *; " + // +"report-uri about:blank"; + ηMatrix.cspNoWorker = "worker-src 'none'; " + +"frame-src data: blob: *; " + +"report-uri about:blank"; + } + + let result = vAPI.net.onHeadersReceived.callback({ parentFrameId: type === 'main_frame' ? -1 : 0, responseHeaders: [], tabId: channelData[0], type: type, url: URI.asciiSpec - }); + }); - if (result) { + if (result) { for (let header of result.responseHeaders) { - channel.setResponseHeader(header.name, - header.value, - true); + channel.setResponseHeader(header.name, + header.value, + true); } - } + } - return; + return; } - // http-on-modify-request + // http-on-modify-request // The channel was previously serviced. if (channelData !== null) { - this.handleRequest(channel, URI, - channelData[0], channelData[1]); - return; + this.handleRequest(channel, URI, + channelData[0], channelData[1]); + return; } // The channel was never serviced. let tabId; let pendingRequest = - PendingRequestBuffer.lookupRequest(URI.asciiSpec); + PendingRequestBuffer.lookupRequest(URI.asciiSpec); let rawType = 1; let loadInfo = channel.loadInfo; // https://github.com/gorhill/uMatrix/issues/390#issuecomment-155717004 if (loadInfo) { - rawType = (loadInfo.externalContentPolicyType !== undefined) - ? loadInfo.externalContentPolicyType - : loadInfo.contentPolicyType; - if (!rawType) { + rawType = (loadInfo.externalContentPolicyType !== undefined) + ? loadInfo.externalContentPolicyType + : loadInfo.contentPolicyType; + if (!rawType) { rawType = 1; - } + } } if (pendingRequest !== null) { - tabId = pendingRequest.tabId; - // https://github.com/gorhill/uBlock/issues/654 - // Use the request type from the HTTP observer point of view. - if (rawType !== 1) { + tabId = pendingRequest.tabId; + // https://github.com/gorhill/uBlock/issues/654 + // Use the request type from the HTTP observer point of view. + if (rawType !== 1) { pendingRequest.rawType = rawType; - } else { + } else { rawType = pendingRequest.rawType; - } + } } else { - tabId = this.tabIdFromChannel(channel); + tabId = this.tabIdFromChannel(channel); } if (this.handleRequest(channel, URI, tabId, rawType)) { - return; + return; } if (channel instanceof Ci.nsIWritablePropertyBag === false) { - return; + return; } // Carry data for behind-the-scene redirects channel.setProperty(this.REQDATAKEY, [tabId, rawType]); - }, - observe: function (channel, topic) { + }, + observe: function (channel, topic) { if (channel instanceof Ci.nsIHttpChannel === false) { - return; + return; } let URI = channel.URI; let channelData = this.channelDataFromChannel(channel); - if (ηMatrix.userSettings.resolveCname === true) { - let key = URI.scheme + '://' + URI.host; - if (HostMap.get(key)) { - this.operate(channel, HostMap.get(key), topic); - return; - } - - let CC = Components.classes; - let CI = Components.interfaces; - - let tab = this.tabIdFromChannel(channel); - - let dns = CC['@mozilla.org/network/dns-service;1'] - .createInstance(CI.nsIDNSService); - - let listener = { - onLookupComplete: function (req, rec, stat) { - if (!Components.isSuccessCode(stat)) { - console.error("can't resolve canonical name"); - return; - } - let addr = rec.canonicalName; - - ηMatrix.logger.writeOne(tab, 'info', - URI.host + ' => ' + addr); - - let ios = CC['@mozilla.org/network/io-service;1'] - .createInstance(CI.nsIIOService); - - let uri = ios.newURI(URI.scheme+'://'+addr, null, null); - - HostMap.put(key, uri); - - vAPI.httpObserver.operate(channel, uri, topic); - }, - }; - - dns.asyncResolve(URI.host, - CI.nsIDNSService.RESOLVE_CANONICAL_NAME, - listener, - null); - } else { - this.operate(channel, URI, topic); - } - }, - asyncOnChannelRedirect: function (oldChannel, newChannel, - flags, callback) { - // contentPolicy.shouldLoad doesn't detect redirects, this - // needs to be used + if (ηMatrix.userSettings.resolveCname === true) { + let key = URI.scheme + '://' + URI.host; + if (HostMap.get(key)) { + this.operate(channel, HostMap.get(key), topic); + return; + } + + let CC = Components.classes; + let CI = Components.interfaces; + + let tab = this.tabIdFromChannel(channel); + + let dns = CC['@mozilla.org/network/dns-service;1'] + .createInstance(CI.nsIDNSService); + + let listener = { + onLookupComplete: function (req, rec, stat) { + if (!Components.isSuccessCode(stat)) { + console.error("can't resolve canonical name"); + return; + } + let addr = rec.canonicalName; + + ηMatrix.logger.writeOne(tab, 'info', + URI.host + ' => ' + addr); + + let ios = CC['@mozilla.org/network/io-service;1'] + .createInstance(CI.nsIIOService); + + let uri = ios.newURI(URI.scheme+'://'+addr, null, null); + + HostMap.put(key, uri); + + vAPI.httpObserver.operate(channel, uri, topic); + }, + }; + + dns.asyncResolve(URI.host, + CI.nsIDNSService.RESOLVE_CANONICAL_NAME, + listener, + null); + } else { + this.operate(channel, URI, topic); + } + }, + asyncOnChannelRedirect: function (oldChannel, newChannel, + flags, callback) { + // contentPolicy.shouldLoad doesn't detect redirects, this + // needs to be used // If error thrown, the redirect will fail try { - let URI = newChannel.URI; - if (!URI.schemeIs('http') && !URI.schemeIs('https')) { + let URI = newChannel.URI; + if (!URI.schemeIs('http') && !URI.schemeIs('https')) { return; - } + } - if (newChannel instanceof Ci.nsIWritablePropertyBag === false) { + if (newChannel instanceof Ci.nsIWritablePropertyBag === false) { return; - } + } - let channelData = this.channelDataFromChannel(oldChannel); - if (channelData === null) { + let channelData = this.channelDataFromChannel(oldChannel); + if (channelData === null) { return; - } + } - // Carry the data on in case of multiple redirects - newChannel.setProperty(this.REQDATAKEY, channelData); + // Carry the data on in case of multiple redirects + newChannel.setProperty(this.REQDATAKEY, channelData); } catch (ex) { - // console.error(ex); - // Ignore + // console.error(ex); + // Ignore } finally { - callback.onRedirectVerifyCallback(this.ACCEPT); + callback.onRedirectVerifyCallback(this.ACCEPT); } - } + } }; vAPI.toolbarButton = { - id: location.host + '-button', - type: 'view', - viewId: location.host + '-panel', - label: vAPI.app.name, - tooltiptext: vAPI.app.name, - tabs: {/*tabId: {badge: 0, img: boolean}*/}, - init: null, - codePath: '' + id: location.host + '-button', + type: 'view', + viewId: location.host + '-panel', + label: vAPI.app.name, + tooltiptext: vAPI.app.name, + tabs: {/*tabId: {badge: 0, img: boolean}*/}, + init: null, + codePath: '' }; (function () { - let tbb = vAPI.toolbarButton; - let popupCommittedWidth = 0; - let popupCommittedHeight = 0; + let tbb = vAPI.toolbarButton; + let popupCommittedWidth = 0; + let popupCommittedHeight = 0; - tbb.onViewShowing = function ({target}) { + tbb.onViewShowing = function ({target}) { popupCommittedWidth = popupCommittedHeight = 0; target.firstChild.setAttribute('src', vAPI.getURL('popup.html')); - }; + }; - tbb.onViewHiding = function ({target}) { + tbb.onViewHiding = function ({target}) { target.parentNode.style.maxWidth = ''; target.firstChild.setAttribute('src', 'about:blank'); - }; + }; - tbb.updateState = function (win, tabId) { + tbb.updateState = function (win, tabId) { let button = win.document.getElementById(this.id); if (!button) { - return; + return; } let icon = this.tabs[tabId]; @@ -541,19 +541,19 @@ button.classList.toggle('off', !icon || !icon.img); let iconId = (ηMatrix.userSettings.disableUpdateIcon) ? - icon && icon.img ? '19' : 'off' : - icon && icon.img ? icon.img : 'off'; + icon && icon.img ? '19' : 'off' : + icon && icon.img ? icon.img : 'off'; icon = 'url(' - + vAPI.getURL('img/browsericons/icon19-' - + iconId - + '.png') - + ')'; + + vAPI.getURL('img/browsericons/icon19-' + + iconId + + '.png') + + ')'; - button.style.listStyleImage = icon; - }; + button.style.listStyleImage = icon; + }; - tbb.populatePanel = function (doc, panel) { + tbb.populatePanel = function (doc, panel) { panel.setAttribute('id', this.viewId); let iframe = doc.createElement('iframe'); @@ -562,135 +562,130 @@ panel.appendChild(iframe); let toPx = function (pixels) { - return pixels.toString() + 'px'; + return pixels.toString() + 'px'; }; let scrollBarWidth = 0; let resizeTimer = null; let resizePopupDelayed = function (attempts) { - if (resizeTimer !== null) { + if (resizeTimer !== null) { return false; - } + } - // Sanity check - attempts = (attempts || 0) + 1; - if ( attempts > 1/*000*/ ) { + // Sanity check + attempts = (attempts || 0) + 1; + if ( attempts > 1/*000*/ ) { //console.error('eMatrix> resizePopupDelayed: giving up after too many attempts'); return false; - } + } - resizeTimer = vAPI.setTimeout(resizePopup, 10, attempts); - return true; + resizeTimer = vAPI.setTimeout(resizePopup, 10, attempts); + return true; }; let resizePopup = function (attempts) { - resizeTimer = null; + resizeTimer = null; - panel.parentNode.style.maxWidth = 'none'; - let body = iframe.contentDocument.body; + panel.parentNode.style.maxWidth = 'none'; + let body = iframe.contentDocument.body; - // https://github.com/gorhill/uMatrix/issues/301 - // Don't resize if committed size did not change. - if (popupCommittedWidth === body.clientWidth - && popupCommittedHeight === body.clientHeight) { + // https://github.com/gorhill/uMatrix/issues/301 + // Don't resize if committed size did not change. + if (popupCommittedWidth === body.clientWidth + && popupCommittedHeight === body.clientHeight) { return; - } + } - // We set a limit for height - let height = Math.min(body.clientHeight, 600); + // We set a limit for height + let height = Math.min(body.clientHeight, 600); - // https://github.com/chrisaljoudi/uBlock/issues/730 - // Voodoo programming: this recipe works - panel.style.setProperty('height', toPx(height)); - iframe.style.setProperty('height', toPx(height)); + // https://github.com/chrisaljoudi/uBlock/issues/730 + // Voodoo programming: this recipe works + panel.style.setProperty('height', toPx(height)); + iframe.style.setProperty('height', toPx(height)); - // Adjust width for presence/absence of vertical scroll bar which may - // have appeared as a result of last operation. - let contentWindow = iframe.contentWindow; - let width = body.clientWidth; - if (contentWindow.scrollMaxY !== 0) { + // Adjust width for presence/absence of vertical scroll bar which may + // have appeared as a result of last operation. + let contentWindow = iframe.contentWindow; + let width = body.clientWidth; + if (contentWindow.scrollMaxY !== 0) { width += scrollBarWidth; - } - panel.style.setProperty('width', toPx(width)); + } + panel.style.setProperty('width', toPx(width)); - // scrollMaxX should always be zero once we know the scrollbar width - if (contentWindow.scrollMaxX !== 0) { + // scrollMaxX should always be zero once we know the scrollbar width + if (contentWindow.scrollMaxX !== 0) { scrollBarWidth = contentWindow.scrollMaxX; width += scrollBarWidth; panel.style.setProperty('width', toPx(width)); - } + } - if (iframe.clientHeight !== height - || panel.clientWidth !== width) { + if (iframe.clientHeight !== height + || panel.clientWidth !== width) { if (resizePopupDelayed(attempts)) { - return; + return; } // resizePopupDelayed won't be called again, so commit // dimentsions. - } + } - popupCommittedWidth = body.clientWidth; - popupCommittedHeight = body.clientHeight; + popupCommittedWidth = body.clientWidth; + popupCommittedHeight = body.clientHeight; }; let onResizeRequested = function () { - let body = iframe.contentDocument.body; - if (body.getAttribute('data-resize-popup') !== 'true') { + let body = iframe.contentDocument.body; + if (body.getAttribute('data-resize-popup') !== 'true') { return; - } - body.removeAttribute('data-resize-popup'); - resizePopupDelayed(); + } + body.removeAttribute('data-resize-popup'); + resizePopupDelayed(); }; let onPopupReady = function () { - let win = this.contentWindow; + let win = this.contentWindow; - if (!win || win.location.host !== location.host) { + if (!win || win.location.host !== location.host) { return; - } + } - if (typeof tbb.onBeforePopupReady === 'function') { + if (typeof tbb.onBeforePopupReady === 'function') { tbb.onBeforePopupReady.call(this); - } + } - resizePopupDelayed(); + resizePopupDelayed(); - let body = win.document.body; - body.removeAttribute('data-resize-popup'); + let body = win.document.body; + body.removeAttribute('data-resize-popup'); - let mutationObserver = - new win.MutationObserver(onResizeRequested); + let mutationObserver = + new win.MutationObserver(onResizeRequested); - mutationObserver.observe(body, { + mutationObserver.observe(body, { attributes: true, attributeFilter: [ 'data-resize-popup' ] - }); + }); }; iframe.addEventListener('load', onPopupReady, true); - }; + }; })(); /******************************************************************************/ (function () { - // Add toolbar button for not-Basilisk - if (Services.appinfo.ID === "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}") { + let tbb = vAPI.toolbarButton; + if (tbb.init !== null) { return; - } + } - let tbb = vAPI.toolbarButton; - if (tbb.init !== null) { - return; - } + tbb.codePath = 'legacy'; + tbb.viewId = tbb.id + '-panel'; - tbb.codePath = 'legacy'; - tbb.viewId = tbb.id + '-panel'; + let styleSheetUri = null; - let styleSheetUri = null; - - let createToolbarButton = function (window) { + let createToolbarButton = function (window) { let document = window.document; let toolbarButton = document.createElement('toolbarbutton'); @@ -699,40 +694,40 @@ toolbarButton.setAttribute('type', 'menu'); toolbarButton.setAttribute('removable', 'true'); toolbarButton.setAttribute('class', 'toolbarbutton-1 ' - +'chromeclass-toolbar-additional'); + +'chromeclass-toolbar-additional'); toolbarButton.setAttribute('label', tbb.label); - toolbarButton.setAttribute('tooltiptext', tbb.tooltiptext); + toolbarButton.setAttribute('tooltiptext', tbb.tooltiptext); let toolbarButtonPanel = document.createElement('panel'); // NOTE: Setting level to parent breaks the popup for PaleMoon under // linux (mouse pointer misaligned with content). For some reason. - // eMatrix: TODO check if it's still true + // eMatrix: TODO check if it's still true // toolbarButtonPanel.setAttribute('level', 'parent'); tbb.populatePanel(document, toolbarButtonPanel); toolbarButtonPanel.addEventListener('popupshowing', - tbb.onViewShowing); + tbb.onViewShowing); toolbarButtonPanel.addEventListener('popuphiding', - tbb.onViewHiding); + tbb.onViewHiding); toolbarButton.appendChild(toolbarButtonPanel); - toolbarButtonPanel.setAttribute('tooltiptext', ''); + toolbarButtonPanel.setAttribute('tooltiptext', ''); return toolbarButton; - }; + }; - let addLegacyToolbarButton = function (window) { + let addLegacyToolbarButton = function (window) { // eMatrix's stylesheet lazily added. if (styleSheetUri === null) { - var sss = Cc["@mozilla.org/content/style-sheet-service;1"] + var sss = Cc["@mozilla.org/content/style-sheet-service;1"] .getService(Ci.nsIStyleSheetService); - styleSheetUri = Services.io - .newURI(vAPI.getURL("css/legacy-toolbar-button.css"), - null, null); + styleSheetUri = Services.io + .newURI(vAPI.getURL("css/legacy-toolbar-button.css"), + null, null); - // Register global so it works in all windows, including palette - if (!sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET)) { + // Register global so it works in all windows, including palette + if (!sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET)) { sss.loadAndRegisterSheet(styleSheetUri, sss.AUTHOR_SHEET); - } + } } let document = window.document; @@ -740,21 +735,21 @@ // https://github.com/gorhill/uMatrix/issues/357 // Already installed? if (document.getElementById(tbb.id) !== null) { - return; + return; } let toolbox = document.getElementById('navigator-toolbox') - || document.getElementById('mail-toolbox'); + || document.getElementById('mail-toolbox'); if (toolbox === null) { - return; + return; } let toolbarButton = createToolbarButton(window); let palette = toolbox.palette; if (palette && palette.querySelector('#' + tbb.id) === null) { - palette.appendChild(toolbarButton); + palette.appendChild(toolbarButton); } // Find the place to put the button. @@ -762,75 +757,75 @@ // undefined. Seen while testing popup test number 3: // http://raymondhill.net/ublock/popup.html let toolbars = toolbox.externalToolbars - ? toolbox.externalToolbars.slice() - : []; + ? toolbox.externalToolbars.slice() + : []; for (let child of toolbox.children) { - if (child.localName === 'toolbar') { + if (child.localName === 'toolbar') { toolbars.push(child); - } + } } for (let toolbar of toolbars) { - let currentsetString = toolbar.getAttribute('currentset'); - if (!currentsetString) { + let currentsetString = toolbar.getAttribute('currentset'); + if (!currentsetString) { continue; - } + } - let currentset = currentsetString.split(/\s*,\s*/); - let index = currentset.indexOf(tbb.id); - if (index === -1) { + let currentset = currentsetString.split(/\s*,\s*/); + let index = currentset.indexOf(tbb.id); + if (index === -1) { continue; - } + } - // This can occur with Pale Moon: - // "TypeError: toolbar.insertItem is not a function" - if (typeof toolbar.insertItem !== 'function') { + // This can occur with Pale Moon: + // "TypeError: toolbar.insertItem is not a function" + if (typeof toolbar.insertItem !== 'function') { continue; - } - - // Found our button on this toolbar - but where on it? - let before = null; - for (let i=index+1; i<currentset.length; ++i) { - // The [id=...] notation doesn't work on - // space elements as they get a random ID each session - // (or something like that) - // https://gitlab.com/vannilla/ematrix/issues/5 - // https://gitlab.com/vannilla/ematrix/issues/6 - - // Based on JustOff's snippet from the Pale Moon - // forum. It was reorganized because I find it - // more readable like this, but he did most of the - // work. - let space = /^(spring|spacer|separator)$/.exec(currentset[i]); - if (space !== null) { - let elems = toolbar.querySelectorAll('toolbar'+space[1]); - - let count = currentset.slice(i-currentset.length) - .filter(function (x) {return x == space[1];}) - .length; - - before = - toolbar.querySelector('[id="' - + elems[elems.length-count].id - + '"]'); - } else { - before = toolbar.querySelector('[id="'+currentset[i]+'"]'); - } + } + + // Found our button on this toolbar - but where on it? + let before = null; + for (let i=index+1; i<currentset.length; ++i) { + // The [id=...] notation doesn't work on + // space elements as they get a random ID each session + // (or something like that) + // https://gitlab.com/vannilla/ematrix/issues/5 + // https://gitlab.com/vannilla/ematrix/issues/6 + + // Based on JustOff's snippet from the Pale Moon + // forum. It was reorganized because I find it + // more readable like this, but he did most of the + // work. + let space = /^(spring|spacer|separator)$/.exec(currentset[i]); + if (space !== null) { + let elems = toolbar.querySelectorAll('toolbar'+space[1]); + + let count = currentset.slice(i-currentset.length) + .filter(function (x) {return x == space[1];}) + .length; + + before = + toolbar.querySelector('[id="' + + elems[elems.length-count].id + + '"]'); + } else { + before = toolbar.querySelector('[id="'+currentset[i]+'"]'); + } if ( before !== null ) { - break; + break; } - } + } - toolbar.insertItem(tbb.id, before); - break; + toolbar.insertItem(tbb.id, before); + break; } // https://github.com/gorhill/uBlock/issues/763 // We are done if our toolbar button is already installed // in one of the toolbar. if (palette !== null && toolbarButton.parentElement !== palette) { - return; + return; } // No button yet so give it a default location. If forcing @@ -839,386 +834,200 @@ // available or visible!) let navbar = document.getElementById('nav-bar'); if (navbar !== null - && !vAPI.localStorage.getBool('legacyToolbarButtonAdded')) { - // https://github.com/gorhill/uBlock/issues/264 - // Find a child customizable palette, if any. - navbar = navbar.querySelector('.customization-target') || navbar; - navbar.appendChild(toolbarButton); - navbar.setAttribute('currentset', navbar.currentSet); - document.persist(navbar.id, 'currentset'); - vAPI.localStorage.setBool('legacyToolbarButtonAdded', 'true'); + && !vAPI.localStorage.getBool('legacyToolbarButtonAdded')) { + // https://github.com/gorhill/uBlock/issues/264 + // Find a child customizable palette, if any. + navbar = navbar.querySelector('.customization-target') || navbar; + navbar.appendChild(toolbarButton); + navbar.setAttribute('currentset', navbar.currentSet); + document.persist(navbar.id, 'currentset'); + vAPI.localStorage.setBool('legacyToolbarButtonAdded', 'true'); } - }; + }; - let canAddLegacyToolbarButton = function (window) { + let canAddLegacyToolbarButton = function (window) { let document = window.document; if (!document - || document.readyState !== 'complete' - || document.getElementById('nav-bar') === null) { - return false; + || document.readyState !== 'complete' + || document.getElementById('nav-bar') === null) { + return false; } let toolbox = document.getElementById('navigator-toolbox') - || document.getElementById('mail-toolbox'); + || document.getElementById('mail-toolbox'); return toolbox !== null && !!toolbox.palette; - }; + }; - let onPopupCloseRequested = function ({target}) { + let onPopupCloseRequested = function ({target}) { let document = target.ownerDocument; if (!document) { - return; + return; } let toolbarButtonPanel = document.getElementById(tbb.viewId); if (toolbarButtonPanel === null) { - return; + return; } // `hidePopup` reported as not existing while testing // legacy button on FF 41.0.2. // https://bugzilla.mozilla.org/show_bug.cgi?id=1151796 if (typeof toolbarButtonPanel.hidePopup === 'function') { - toolbarButtonPanel.hidePopup(); + toolbarButtonPanel.hidePopup(); } - }; + }; - let shutdown = function () { + let shutdown = function () { for (let win of vAPI.window.getWindows()) { - let toolbarButton = win.document.getElementById(tbb.id); - if (toolbarButton) { + let toolbarButton = win.document.getElementById(tbb.id); + if (toolbarButton) { toolbarButton.parentNode.removeChild(toolbarButton); - } + } } if (styleSheetUri !== null) { - var sss = Cc["@mozilla.org/content/style-sheet-service;1"] + var sss = Cc["@mozilla.org/content/style-sheet-service;1"] .getService(Ci.nsIStyleSheetService); - if (sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET)) { + if (sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET)) { sss.unregisterSheet(styleSheetUri, sss.AUTHOR_SHEET); - } - styleSheetUri = null; + } + styleSheetUri = null; } vAPI.messaging.globalMessageManager - .removeMessageListener(location.host + ':closePopup', - onPopupCloseRequested); - }; + .removeMessageListener(location.host + ':closePopup', + onPopupCloseRequested); + }; - tbb.attachToNewWindow = function (win) { + tbb.attachToNewWindow = function (win) { vAPI.deferUntil(canAddLegacyToolbarButton.bind(null, win), - addLegacyToolbarButton.bind(null, win)); - }; - - tbb.init = function () { - vAPI.messaging.globalMessageManager - .addMessageListener(location.host + ':closePopup', - onPopupCloseRequested); - - vAPI.addCleanUpTask(shutdown); - }; - })(); - - (function() { - // Add toolbar button for Basilisk - if (Services.appinfo.ID !== "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}") { - return; - } - - let tbb = vAPI.toolbarButton; - if (tbb.init !== null) { - return; - } - // if ( Services.vc.compare(Services.appinfo.version, '36.0') < 0 ) { - // return null; - // } - let CustomizableUI = null; - try { - CustomizableUI = - Cu.import('resource:///modules/CustomizableUI.jsm', null) - .CustomizableUI; - } catch (ex) { - // Ignore - } - if (CustomizableUI === null) { - return null; - } - tbb.codePath = 'australis'; - tbb.CustomizableUI = CustomizableUI; - tbb.defaultArea = CustomizableUI.AREA_NAVBAR; - - let CUIEvents = {}; - - let badgeCSSRules = 'background: #000;color: #fff'; - - let updateBadgeStyle = function () { - for (let win of vAPI.window.getWindows()) { - let button = win.document.getElementById(tbb.id); - if (button === null) { - continue; - } - let badge = button.ownerDocument - .getAnonymousElementByAttribute(button, - 'class', - 'toolbarbutton-badge'); - if (!badge) { - continue; - } - - badge.style.cssText = badgeCSSRules; - } - }; - - let updateBadge = function () { - let wId = tbb.id; - let buttonInPanel = - CustomizableUI.getWidget(wId).areaType - === CustomizableUI.TYPE_MENU_PANEL; - - for (let win of vAPI.window.getWindows()) { - let button = win.document.getElementById(wId); - if (button === null) { - continue; - } - - if (buttonInPanel) { - button.classList.remove('badged-button'); - continue; - } - - button.classList.add('badged-button'); - } - - if (buttonInPanel) { - return; - } - - // Anonymous elements need some time to be reachable - vAPI.setTimeout(updateBadgeStyle, 250); - }.bind(CUIEvents); - - CUIEvents.onCustomizeEnd = updateBadge; - CUIEvents.onWidgetAdded = updateBadge; - CUIEvents.onWidgetUnderflow = updateBadge; - - let onPopupCloseRequested = function ({target}) { - if (typeof tbb.closePopup === 'function') { - tbb.closePopup(target); - } - }; - - let shutdown = function () { - for (let win of vAPI.window.getWindows()) { - let panel = win.document.getElementById(tbb.viewId); - if (panel !== null && panel.parentNode !== null) { - panel.parentNode.removeChild(panel); - } - - win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils) - .removeSheet(styleURI, 1); - } - - CustomizableUI.removeListener(CUIEvents); - CustomizableUI.destroyWidget(tbb.id); - - vAPI.messaging.globalMessageManager - .removeMessageListener(location.host + ':closePopup', - onPopupCloseRequested); - }; - - let styleURI = null; - - tbb.onBeforeCreated = function (doc) { - let panel = doc.createElement('panelview'); - - this.populatePanel(doc, panel); - - doc.getElementById('PanelUI-multiView').appendChild(panel); - - doc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils) - .loadSheet(styleURI, 1); - }; - - tbb.onCreated = function (button) { - button.setAttribute('badge', ''); - vAPI.setTimeout(updateBadge, 250); - }; - - tbb.onBeforePopupReady = function () { - // https://github.com/gorhill/uBlock/issues/83 - // Add `portrait` class if width is constrained. - try { - this.contentDocument.body - .classList.toggle('portrait', - CustomizableUI.getWidget(tbb.id).areaType - === CustomizableUI.TYPE_MENU_PANEL); - } catch (ex) { - // Ignore - } - }; - - tbb.closePopup = function (tabBrowser) { - CustomizableUI.hidePanelForNode(tabBrowser - .ownerDocument - .getElementById(tbb.viewId)); - }; + addLegacyToolbarButton.bind(null, win)); + }; - tbb.init = function () { + tbb.init = function () { vAPI.messaging.globalMessageManager - .addMessageListener(location.host + ':closePopup', - onPopupCloseRequested); - - CustomizableUI.addListener(CUIEvents); - - var style = [ - '#' + this.id + '.off {', - 'list-style-image: url(', - vAPI.getURL('img/browsericons/icon19-off.png'), - ');', - '}', - '#' + this.id + ' {', - 'list-style-image: url(', - vAPI.getURL('img/browsericons/icon19-19.png'), - ');', - '}', - '#' + this.viewId + ', #' + this.viewId + ' > iframe {', - 'height: 290px;', - 'max-width: none !important;', - 'min-width: 0 !important;', - 'overflow: hidden !important;', - 'padding: 0 !important;', - 'width: 160px;', - '}' - ]; - - styleURI = - Services.io.newURI('data:text/css,' - +encodeURIComponent(style.join('')), - null, - null); - - CustomizableUI.createWidget(this); + .addMessageListener(location.host + ':closePopup', + onPopupCloseRequested); vAPI.addCleanUpTask(shutdown); - }; + }; })(); // No toolbar button. (function () { - // Just to ensure the number of cleanup tasks is as expected: toolbar - // button code is one single cleanup task regardless of platform. - // eMatrix: might not be needed anymore - if (vAPI.toolbarButton.init === null) { + // Just to ensure the number of cleanup tasks is as expected: toolbar + // button code is one single cleanup task regardless of platform. + // eMatrix: might not be needed anymore + if (vAPI.toolbarButton.init === null) { vAPI.addCleanUpTask(function(){}); - } + } })(); if (vAPI.toolbarButton.init !== null) { - vAPI.toolbarButton.init(); + vAPI.toolbarButton.init(); } let optionsObserver = (function () { - let addonId = 'eMatrix@vannilla.org'; + let addonId = 'eMatrix@vannilla.org'; - let commandHandler = function () { + let commandHandler = function () { switch (this.id) { case 'showDashboardButton': - vAPI.tabs.open({ - url: 'dashboard.html', - index: -1, - }); - break; + vAPI.tabs.open({ + url: 'dashboard.html', + index: -1, + }); + break; case 'showLoggerButton': - vAPI.tabs.open({ - url: 'logger-ui.html', - index: -1, - }); - break; + vAPI.tabs.open({ + url: 'logger-ui.html', + index: -1, + }); + break; default: - break; + break; } - }; + }; - let setupOptionsButton = function (doc, id) { + let setupOptionsButton = function (doc, id) { let button = doc.getElementById(id); if (button === null) { - return; + return; } button.addEventListener('command', commandHandler); button.label = vAPI.i18n(id); - }; + }; - let setupOptionsButtons = function (doc) { + let setupOptionsButtons = function (doc) { setupOptionsButton(doc, 'showDashboardButton'); setupOptionsButton(doc, 'showLoggerButton'); - }; + }; - let observer = { + let observer = { observe: function (doc, topic, id) { - if (id !== addonId) { + if (id !== addonId) { return; - } + } - setupOptionsButtons(doc); + setupOptionsButtons(doc); } - }; + }; - var canInit = function() { - // https://github.com/gorhill/uBlock/issues/948 - // Older versions of Firefox can throw here when looking - // up `currentURI`. + var canInit = function() { + // https://github.com/gorhill/uBlock/issues/948 + // Older versions of Firefox can throw here when looking + // up `currentURI`. try { - let tabBrowser = vAPI.tabs.manager.currentBrowser(); - return tabBrowser - && tabBrowser.currentURI - && tabBrowser.currentURI.spec === 'about:addons' - && tabBrowser.contentDocument - && tabBrowser.contentDocument.readyState === 'complete'; + let tabBrowser = vAPI.tabs.manager.currentBrowser(); + return tabBrowser + && tabBrowser.currentURI + && tabBrowser.currentURI.spec === 'about:addons' + && tabBrowser.contentDocument + && tabBrowser.contentDocument.readyState === 'complete'; } catch (ex) { - // Ignore + // Ignore } - }; + }; - // Manually add the buttons if the `about:addons` page is - // already opened. - let init = function () { + // Manually add the buttons if the `about:addons` page is + // already opened. + let init = function () { if (canInit()) { - setupOptionsButtons(vAPI.tabs.manager - .currentBrowser().contentDocument); + setupOptionsButtons(vAPI.tabs.manager + .currentBrowser().contentDocument); } - }; + }; - let unregister = function () { + let unregister = function () { Services.obs.removeObserver(observer, 'addon-options-displayed'); - }; + }; - let register = function () { + let register = function () { Services.obs.addObserver(observer, - 'addon-options-displayed', - false); + 'addon-options-displayed', + false); vAPI.addCleanUpTask(unregister); vAPI.deferUntil(canInit, init, { next: 463 }); - }; + }; - return { + return { register: register, unregister: unregister - }; + }; })(); optionsObserver.register(); vAPI.onLoadAllCompleted = function() { - // This is called only once, when everything has been loaded - // in memory after the extension was launched. It can be used - // to inject content scripts in already opened web pages, to - // remove whatever nuisance could make it to the web pages - // before uBlock was ready. - for (let browser of vAPI.tabs.manager.browsers()) { + // This is called only once, when everything has been loaded + // in memory after the extension was launched. It can be used + // to inject content scripts in already opened web pages, to + // remove whatever nuisance could make it to the web pages + // before uBlock was ready. + for (let browser of vAPI.tabs.manager.browsers()) { browser.messageManager - .sendAsyncMessage(location.host + '-load-completed'); - } + .sendAsyncMessage(location.host + '-load-completed'); + } }; // Likelihood is that we do not have to punycode: given punycode overhead, @@ -1227,16 +1036,16 @@ var isNotASCII = /[^\x21-\x7F]/; vAPI.punycodeHostname = function (hostname) { - return isNotASCII.test(hostname) - ? punycodeHostname(hostname) - : hostname; + return isNotASCII.test(hostname) + ? punycodeHostname(hostname) + : hostname; }; vAPI.punycodeURL = function (url) { - if (isNotASCII.test(url)) { + if (isNotASCII.test(url)) { return Services.io.newURI(url, null, null).asciiSpec; - } + } - return url; + return url; }; })(); |