diff options
author | Ruben Rodriguez <ruben@gnu.org> | 2017-09-01 16:35:50 -0400 |
---|---|---|
committer | Ruben Rodriguez <ruben@gnu.org> | 2017-09-01 16:35:50 -0400 |
commit | e8730f68798f173bd4d1c2f9b7ce02985e3fd771 (patch) | |
tree | 711132ed84ef8ae9e0621de5436a6818a5fa1e12 /data/extensions/spyblock@gnu.org/lib/ui.js | |
parent | edde38bbb0e0afb9b8a78c002996c758fb6023b6 (diff) |
SpyBlock updated to 2.9.1
Diffstat (limited to 'data/extensions/spyblock@gnu.org/lib/ui.js')
-rw-r--r-- | data/extensions/spyblock@gnu.org/lib/ui.js | 494 |
1 files changed, 210 insertions, 284 deletions
diff --git a/data/extensions/spyblock@gnu.org/lib/ui.js b/data/extensions/spyblock@gnu.org/lib/ui.js index 6009f9e..1941a97 100644 --- a/data/extensions/spyblock@gnu.org/lib/ui.js +++ b/data/extensions/spyblock@gnu.org/lib/ui.js @@ -1,6 +1,6 @@ /* * This file is part of Adblock Plus <https://adblockplus.org/>, - * Copyright (C) 2006-2015 Eyeo GmbH + * Copyright (C) 2006-2017 eyeo GmbH * * Adblock Plus is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -19,6 +19,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); let {Utils} = require("utils"); +let {port} = require("messaging"); let {Prefs} = require("prefs"); let {Policy} = require("contentPolicy"); let {FilterStorage} = require("filterStorage"); @@ -125,6 +126,14 @@ let optionsObserver = this.value = Prefs.savestats; }); + hideElement("adblockplus-shownotifications", !Prefs.notifications_showui); + setChecked("adblockplus-shownotifications", Prefs.notifications_ignoredcategories.indexOf("*") == -1); + addCommandHandler("adblockplus-shownotifications", function() + { + Notification.toggleIgnoreCategory("*"); + this.value = (Prefs.notifications_ignoredcategories.indexOf("*") == -1); + }); + let hasAcceptableAds = FilterStorage.subscriptions.some((subscription) => subscription instanceof DownloadableSubscription && subscription.url == Prefs.subscriptions_exceptionsurl); setChecked("adblockplus-acceptableAds", hasAcceptableAds); @@ -268,64 +277,57 @@ let UI = exports.UI = */ init: function() { - // We should call initDone once both overlay and filters are loaded - let overlayLoaded = false; - let filtersLoaded = false; - let sessionRestored = false; + // We have to wait for multiple events before running start-up actions + let prerequisites = []; // Start loading overlay - let request = new XMLHttpRequest(); - request.mozBackgroundRequest = true; - request.open("GET", "chrome://adblockplus/content/ui/overlay.xul"); - request.addEventListener("load", function(event) + prerequisites.push(new Promise((resolve, reject) => { - if (onShutdown.done) - return; + let request = new XMLHttpRequest(); + request.mozBackgroundRequest = true; + request.open("GET", "chrome://adblockplus/content/ui/overlay.xul"); + request.channel.owner = Utils.systemPrincipal; + request.addEventListener("load", event => + { + if (onShutdown.done) + return; - this.processOverlay(request.responseXML.documentElement); + this.processOverlay(request.responseXML.documentElement); - // Don't wait for the rest of the startup sequence, add icon already - this.addToolbarButton(); + // Don't wait for the rest of the startup sequence, add icon already + this.addToolbarButton(); - overlayLoaded = true; - if (overlayLoaded && filtersLoaded && sessionRestored) - this.initDone(); - }.bind(this), false); - request.send(null); + resolve(); + }, false); - // Wait for filters to load - if (FilterStorage._loading) - { - let listener = function(action) + request.addEventListener("error", event => { - if (action != "load") - return; + reject(new Error("Unexpected: Failed to load overlay.xul")); + }); - FilterNotifier.removeListener(listener); - filtersLoaded = true; - if (overlayLoaded && filtersLoaded && sessionRestored) - this.initDone(); - }.bind(this); - FilterNotifier.addListener(listener); - } - else - filtersLoaded = true; + request.send(null); + })); + + // Wait for filters to load + if (!FilterStorage.initialized) + prerequisites.push(FilterNotifier.once("load")); - // Initialize UI after the session is restored - let window = this.currentWindow; - if (!window && "nsISessionStore" in Ci) + // Wait for session to be restored + prerequisites.push(new Promise((resolve, reject) => { - // No application windows yet, the application must be starting up. Wait - // for session to be restored before initializing our UI. - new SessionRestoreObserver(function() + let window = this.currentWindow; + if (!window && "nsISessionStore" in Ci) { - sessionRestored = true; - if (overlayLoaded && filtersLoaded && sessionRestored) - this.initDone(); - }.bind(this)); - } - else - sessionRestored = true; + // No application windows yet, the application must be starting up. Wait + // for session to be restored before initializing our UI. + new SessionRestoreObserver(resolve); + } + else + resolve(); + })); + + Promise.all(prerequisites).then(() => this.initDone()) + .catch(e => Cu.reportError(e)); }, /** @@ -403,44 +405,45 @@ let UI = exports.UI = this.updateState(); // Listen for pref and filters changes - Prefs.addListener(function(name) + Prefs.addListener(name => { if (name == "enabled" || name == "defaulttoolbaraction" || name == "defaultstatusbaraction") this.updateState(); else if (name == "showinstatusbar") { - for (let window in this.applicationWindows) + for (let window of this.applicationWindows) this.updateStatusbarIcon(window); } - }.bind(this)); - FilterNotifier.addListener(function(action) + }); + + for (let eventName of [ + "filter.added", "filter.removed", "filter.disabled", + "subscription.added", "subscription.removed", "subscription.disabled", + "subscription.updated", "load" + ]) { - if (/^(filter|subscription)\.(added|removed|disabled|updated)$/.test(action) || action == "load") - this.updateState(); - }.bind(this)); + FilterNotifier.on(eventName, () => this.updateState()); + } + + Notification.addShowListener(notification => + { + let window = this.currentWindow; + if (!window) + return; + + let button = window.document.getElementById("abp-toolbarbutton") + || window.document.getElementById("abp-status"); + if (!button) + return; - notificationTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - notificationTimer.initWithCallback(this.showNextNotification.bind(this), - 3 * 60 * 1000, Ci.nsITimer.TYPE_ONE_SHOT); - onShutdown.add(() => notificationTimer.cancel()); + this._showNotification(window, button, notification); + }); // Add "anti-adblock messages" notification initAntiAdblockNotification(); - let documentCreationObserver = { - observe: function(subject, topic, data) - { - if (!(subject instanceof Ci.nsIDOMWindow)) - return; - - this.showNextNotification(subject.location.href); - }.bind(UI) - }; - Services.obs.addObserver(documentCreationObserver, "content-document-global-created", false); - onShutdown.add(function() - { - Services.obs.removeObserver(documentCreationObserver, "content-document-global-created", false); - }); + // Initialize subscribe link handling + port.on("subscribeLinkClick", data => this.subscribeLinkClicked(data)); // Execute first-run actions if a window is open already, otherwise it // will happen in applyToWindow() when a window is opened. @@ -494,7 +497,7 @@ let UI = exports.UI = firstRunActions: function(window) { - if (this.firstRunDone || !window || FilterStorage._loading) + if (this.firstRunDone || !window || !FilterStorage.initialized) return; this.firstRunDone = true; @@ -525,7 +528,7 @@ let UI = exports.UI = */ applyToWindow: function(/**Window*/ window, /**Boolean*/ noDelay) { - let {delayInitialization, isKnownWindow, getBrowser, addBrowserLocationListener, addBrowserClickListener} = require("appSupport"); + let {delayInitialization, isKnownWindow, getBrowser, addBrowserLocationListener} = require("appSupport"); if (window.document.documentElement.id == "CustomizeToolbarWindow" || isKnownWindow(window)) { // Add style processing instruction @@ -575,12 +578,25 @@ let UI = exports.UI = { this.updateIconState(window, window.document.getElementById("abp-status")); this.updateIconState(window, window.document.getElementById("abp-toolbarbutton")); + + Notification.showNext(this.getCurrentLocation(window).spec); }.bind(this)); - addBrowserClickListener(window, this.onBrowserClick.bind(this, window)); - window.document.getElementById("abp-notification-close").addEventListener("command", function(event) + let notificationPanel = window.document.getElementById("abp-notification"); + notificationPanel.addEventListener("command", function(event) { - window.document.getElementById("abp-notification").hidePopup(); + switch (event.target.id) + { + case "abp-notification-close": + notificationPanel.classList.add("abp-closing"); + break; + case "abp-notification-optout": + Notification.toggleIgnoreCategory("*", true); + /* FALL THROUGH */ + case "abp-notification-hide": + notificationPanel.hidePopup(); + break; + } }, false); // First-run actions? @@ -599,7 +615,7 @@ let UI = exports.UI = */ removeFromWindow: function(/**Window*/ window) { - let {isKnownWindow, removeBrowserLocationListeners, removeBrowserClickListeners} = require("appSupport"); + let {isKnownWindow, removeBrowserLocationListeners} = require("appSupport"); if (window.document.documentElement.id == "CustomizeToolbarWindow" || isKnownWindow(window)) { // Remove style processing instruction @@ -634,7 +650,6 @@ let UI = exports.UI = window.removeEventListener("popupshowing", this.onPopupShowing, false); window.removeEventListener("keypress", this.onKeyPress, false); removeBrowserLocationListeners(window); - removeBrowserClickListeners(window); }, /** @@ -716,14 +731,17 @@ let UI = exports.UI = /** - * Brings up the filter composer dialog to block an item. + * Brings up the filter composer dialog to block an item. The optional nodesID + * parameter must be a unique ID returned by + * RequestNotifier.storeNodesForEntry() or similar. */ - blockItem: function(/**Window*/ window, /**Node*/ node, /**RequestEntry*/ item) + blockItem: function(/**Window*/ window, /**string*/ nodesID, /**RequestEntry*/ item) { if (!item) return; - window.openDialog("chrome://adblockplus/content/ui/composer.xul", "_blank", "chrome,centerscreen,resizable,dialog=no,dependent", [node], item); + window.openDialog("chrome://adblockplus/content/ui/composer.xul", "_blank", + "chrome,centerscreen,resizable,dialog=no,dependent", nodesID, item); }, /** @@ -762,7 +780,10 @@ let UI = exports.UI = if (uri) { let {getBrowser} = require("appSupport"); - window.openDialog("chrome://adblockplus/content/ui/sendReport.xul", "_blank", "chrome,centerscreen,resizable=no", getBrowser(window).contentWindow, uri); + let browser = getBrowser(window); + if ("selectedBrowser" in browser) + browser = browser.selectedBrowser; + window.openDialog("chrome://adblockplus/content/ui/sendReport.xul", "_blank", "chrome,centerscreen,resizable=no", browser.outerWindowID, uri, browser); } } }, @@ -852,6 +873,7 @@ let UI = exports.UI = function notifyUser() {return; + let {addTab} = require("appSupport"); if (addTab) { @@ -902,64 +924,12 @@ let UI = exports.UI = }, /** - * Handles clicks inside the browser's content area, will intercept clicks on - * abp: links. This can be called either with an event object or with the link - * target (if it is the former then link target will be retrieved from event - * target). + * Called whenever child/subscribeLinks module intercepts clicks on abp: links + * as well as links to subscribe.adblockplus.org. */ - onBrowserClick: function (/**Window*/ window, /**Event*/ event, /**String*/ linkTarget) + subscribeLinkClicked: function({title, url, + mainSubscriptionTitle, mainSubscriptionURL}) { - if (event) - { - // Ignore right-clicks - if (event.button == 2) - return; - - // Search the link associated with the click - let link = event.target; - while (link && !(link instanceof Ci.nsIDOMHTMLAnchorElement)) - link = link.parentNode; - - if (!link || link.protocol != "abp:") - return; - - // This is our link - make sure the browser doesn't handle it - event.preventDefault(); - event.stopPropagation(); - - linkTarget = link.href; - } - - let match = /^abp:\/*subscribe\/*\?(.*)/i.exec(linkTarget); - if (!match) - return; - - // Decode URL parameters - let title = null; - let url = null; - let mainSubscriptionTitle = null; - let mainSubscriptionURL = null; - for (let param of match[1].split('&')) - { - let parts = param.split("=", 2); - if (parts.length != 2 || !/\S/.test(parts[1])) - continue; - switch (parts[0]) - { - case "title": - title = decodeURIComponent(parts[1]); - break; - case "location": - url = decodeURIComponent(parts[1]); - break; - case "requiresTitle": - mainSubscriptionTitle = decodeURIComponent(parts[1]); - break; - case "requiresLocation": - mainSubscriptionURL = decodeURIComponent(parts[1]); - break; - } - } if (!url) return; @@ -997,7 +967,7 @@ let UI = exports.UI = mainSubscriptionURL = mainSubscriptionURL.spec; } - this.openSubscriptionDialog(window, url, title, mainSubscriptionURL, mainSubscriptionTitle); + this.openSubscriptionDialog(this.currentWindow, url, title, mainSubscriptionURL, mainSubscriptionTitle); }, /** @@ -1093,7 +1063,7 @@ let UI = exports.UI = */ updateState: function() { - for (let window in this.applicationWindows) + for (let window of this.applicationWindows) { this.updateIconState(window, window.document.getElementById("abp-status")); this.updateIconState(window, window.document.getElementById("abp-toolbarbutton")); @@ -1197,7 +1167,10 @@ let UI = exports.UI = FilterStorage.removeFilter(filter); } else + { + filter.disabled = false; FilterStorage.addFilter(filter); + } }, @@ -1419,54 +1392,66 @@ let UI = exports.UI = } statusDescr.setAttribute("value", statusStr); - let activeFilters = []; - E("abp-tooltip-blocked-label").hidden = (state != "active"); - E("abp-tooltip-blocked").hidden = (state != "active"); + E("abp-tooltip-blocked-label").hidden = true; + E("abp-tooltip-blocked").hidden = true; + E("abp-tooltip-filters-label").hidden = true; + E("abp-tooltip-filters").hidden = true; + E("abp-tooltip-more-filters").hidden = true; + if (state == "active") { let {getBrowser} = require("appSupport"); - let stats = RequestNotifier.getWindowStatistics(getBrowser(window).contentWindow); - - let blockedStr = Utils.getString("blocked_count_tooltip"); - blockedStr = blockedStr.replace(/\?1\?/, stats ? stats.blocked : 0).replace(/\?2\?/, stats ? stats.items : 0); - - if (stats && stats.whitelisted + stats.hidden) + let browser = getBrowser(window); + if ("selectedBrowser" in browser) + browser = browser.selectedBrowser; + let outerWindowID = browser.outerWindowID; + RequestNotifier.getWindowStatistics(outerWindowID, (stats) => { - blockedStr += " " + Utils.getString("blocked_count_addendum"); - blockedStr = blockedStr.replace(/\?1\?/, stats.whitelisted).replace(/\?2\?/, stats.hidden); - } + E("abp-tooltip-blocked-label").hidden = false; + E("abp-tooltip-blocked").hidden = false; - E("abp-tooltip-blocked").setAttribute("value", blockedStr); + let blockedStr = Utils.getString("blocked_count_tooltip"); + blockedStr = blockedStr.replace(/\?1\?/, stats ? stats.blocked : 0).replace(/\?2\?/, stats ? stats.items : 0); - if (stats) - { - let filterSort = function(a, b) + if (stats && stats.whitelisted + stats.hidden) { - return stats.filters[b] - stats.filters[a]; - }; - for (let filter in stats.filters) - activeFilters.push(filter); - activeFilters = activeFilters.sort(filterSort); - } + blockedStr += " " + Utils.getString("blocked_count_addendum"); + blockedStr = blockedStr.replace(/\?1\?/, stats.whitelisted).replace(/\?2\?/, stats.hidden); + } - if (activeFilters.length > 0) - { - let filtersContainer = E("abp-tooltip-filters"); - while (filtersContainer.firstChild) - filtersContainer.removeChild(filtersContainer.firstChild); + E("abp-tooltip-blocked").setAttribute("value", blockedStr); - for (let i = 0; i < activeFilters.length && i < 3; i++) + let activeFilters = []; + if (stats) { - let descr = filtersContainer.ownerDocument.createElement("description"); - descr.setAttribute("value", activeFilters[i] + " (" + stats.filters[activeFilters[i]] + ")"); - filtersContainer.appendChild(descr); + let filterSort = function(a, b) + { + return stats.filters[b] - stats.filters[a]; + }; + for (let filter in stats.filters) + activeFilters.push(filter); + activeFilters = activeFilters.sort(filterSort); } - } - } - E("abp-tooltip-filters-label").hidden = (activeFilters.length == 0); - E("abp-tooltip-filters").hidden = (activeFilters.length == 0); - E("abp-tooltip-more-filters").hidden = (activeFilters.length <= 3); + if (activeFilters.length > 0) + { + let filtersContainer = E("abp-tooltip-filters"); + while (filtersContainer.firstChild) + filtersContainer.removeChild(filtersContainer.firstChild); + + for (let i = 0; i < activeFilters.length && i < 3; i++) + { + let descr = filtersContainer.ownerDocument.createElement("description"); + descr.setAttribute("value", activeFilters[i] + " (" + stats.filters[activeFilters[i]] + ")"); + filtersContainer.appendChild(descr); + } + } + + E("abp-tooltip-filters-label").hidden = (activeFilters.length == 0); + E("abp-tooltip-filters").hidden = (activeFilters.length == 0); + E("abp-tooltip-more-filters").hidden = (activeFilters.length <= 3); + }); + } }, /** @@ -1562,10 +1547,12 @@ let UI = exports.UI = let hasStatusBar = statusbarPosition; hideElement(prefix + "showintoolbar", !hasToolbar || prefix == "abp-toolbar-"); hideElement(prefix + "showinstatusbar", !hasStatusBar); + hideElement(prefix + "shownotifications", !Prefs.notifications_showui); hideElement(prefix + "iconSettingsSeparator", (prefix == "abp-toolbar-" || !hasToolbar) && !hasStatusBar); setChecked(prefix + "showintoolbar", this.isToolbarIconVisible()); setChecked(prefix + "showinstatusbar", Prefs.showinstatusbar); + setChecked(prefix + "shownotifications", Prefs.notifications_ignoredcategories.indexOf("*") == -1); let {Sync} = require("sync"); let syncEngine = Sync.getEngine(); @@ -1611,29 +1598,36 @@ let UI = exports.UI = */ fillContentContextMenu: function(/**Element*/ popup) { - let target = popup.triggerNode; - if (target instanceof Ci.nsIDOMHTMLMapElement || target instanceof Ci.nsIDOMHTMLAreaElement) - { - // HTML image maps will usually receive events when the mouse pointer is - // over a different element, get the real event target. - let rect = target.getClientRects()[0]; - target = target.ownerDocument.elementFromPoint(Math.max(rect.left, 0), Math.max(rect.top, 0)); + let window = popup.ownerDocument.defaultView; + let data = window.gContextMenuContentData; + if (!data) + { + // This is SeaMonkey Mail or Thunderbird, they won't get context menu data + // for us. Send the notification ourselves. + data = { + event: {target: popup.triggerNode}, + addonInfo: {}, + get wrappedJSObject() {return this;} + }; + Services.obs.notifyObservers(data, "AdblockPlus:content-contextmenu", null); } - if (!target) + if (typeof data.addonInfo != "object" || typeof data.addonInfo.adblockplus != "object") return; - let window = popup.ownerDocument.defaultView; + let items = data.addonInfo.adblockplus; + let clicked = null; let menuItems = []; - let addMenuItem = function([node, nodeData]) + + function menuItemTriggered(id, nodeData) { - let type = nodeData.typeDescr.toLowerCase(); - if (type == "background") - { - type = "image"; - node = null; - } + clicked = id; + this.blockItem(window, id, nodeData); + } + for (let [id, nodeData] of items) + { + let type = nodeData.type.toLowerCase(); let label = this.overlay.attributes[type + "contextlabel"]; if (!label) return; @@ -1641,66 +1635,10 @@ let UI = exports.UI = let item = popup.ownerDocument.createElement("menuitem"); item.setAttribute("label", label); item.setAttribute("class", "abp-contextmenuitem"); - item.addEventListener("command", this.blockItem.bind(this, window, node, nodeData), false); + item.addEventListener("command", menuItemTriggered.bind(this, id, nodeData), false); popup.appendChild(item); menuItems.push(item); - }.bind(this); - - // Look up data that we have for the node - let data = RequestNotifier.getDataForNode(target); - let hadImage = false; - if (data && !data[1].filter) - { - addMenuItem(data); - hadImage = (data[1].typeDescr == "IMAGE"); - } - - // Look for frame data - let wnd = Utils.getWindow(target); - if (wnd.frameElement) - { - let data = RequestNotifier.getDataForNode(wnd.frameElement, true); - if (data && !data[1].filter) - addMenuItem(data); - } - - // Look for a background image - if (!hadImage) - { - let extractImageURL = function(computedStyle, property) - { - let value = computedStyle.getPropertyCSSValue(property); - // CSSValueList - if ("length" in value && value.length >= 1) - value = value[0]; - // CSSValuePrimitiveType - if ("primitiveType" in value && value.primitiveType == value.CSS_URI) - return Utils.unwrapURL(value.getStringValue()).spec; - - return null; - }; - - let node = target; - while (node) - { - if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) - { - let style = wnd.getComputedStyle(node, ""); - let bgImage = extractImageURL(style, "background-image") || extractImageURL(style, "list-style-image"); - if (bgImage) - { - let data = RequestNotifier.getDataForNode(wnd.document, true, Policy.type.IMAGE, bgImage); - if (data && !data[1].filter) - { - addMenuItem(data); - break; - } - } - } - - node = node.parentNode; - } } // Add "Remove exception" menu item if necessary @@ -1722,20 +1660,21 @@ let UI = exports.UI = } // Make sure to clean up everything once the context menu is closed - if (menuItems.length) + let cleanUp = function(event) { - let cleanUp = function(event) - { - if (event.eventPhase != event.AT_TARGET) - return; + if (event.eventPhase != event.AT_TARGET) + return; - popup.removeEventListener("popuphidden", cleanUp, false); - for (let i = 0; i < menuItems.length; i++) - if (menuItems[i].parentNode) - menuItems[i].parentNode.removeChild(menuItems[i]); - }.bind(this); - popup.addEventListener("popuphidden", cleanUp, false); - } + popup.removeEventListener("popuphidden", cleanUp, false); + for (let menuItem of menuItems) + if (menuItem.parentNode) + menuItem.parentNode.removeChild(menuItem); + + for (let [id, nodeData] of items) + if (id && id != clicked) + Policy.deleteNodes(id); + }.bind(this); + popup.addEventListener("popuphidden", cleanUp, false); }, /** @@ -1815,8 +1754,10 @@ let UI = exports.UI = removeBottomBar(window); let browser = (getBrowser ? getBrowser(window) : null); + if (browser && "selectedBrowser" in browser) + browser = browser.selectedBrowser; if (browser) - browser.contentWindow.focus(); + browser.focus(); } else if (!detach) { @@ -1857,24 +1798,6 @@ let UI = exports.UI = } }, - showNextNotification: function(url) - { - let window = this.currentWindow; - if (!window) - return; - - let button = window.document.getElementById("abp-toolbarbutton") - || window.document.getElementById("abp-status"); - if (!button) - return; - - let notification = Notification.getNextToShow(url); - if (!notification) - return; - - this._showNotification(window, button, notification); - }, - _showNotification: function(window, button, notification) { let panel = window.document.getElementById("abp-notification"); @@ -1940,9 +1863,11 @@ let UI = exports.UI = window.document.getElementById("abp-notification-yes").onclick = buttonHandler.bind(null, true); window.document.getElementById("abp-notification-no").onclick = buttonHandler.bind(null, false); } + else + Notification.markAsShown(notification.id); panel.setAttribute("class", "abp-" + notification.type); - panel.setAttribute("noautohide", notification.type === "question"); + panel.setAttribute("noautohide", true); panel.openPopup(button, "bottomcenter topcenter", 0, 0, false, false, null); } }; @@ -1969,12 +1894,13 @@ let eventHandlers = [ ["abp-command-toggleshowinstatusbar", "command", UI.togglePref.bind(UI, "showinstatusbar")], ["abp-command-enable", "command", UI.togglePref.bind(UI, "enabled")], ["abp-command-contribute", "command", UI.openContributePage.bind(UI)], - ["abp-command-contribute-hide", "command", UI.hideContributeButton.bind(UI)] + ["abp-command-contribute-hide", "command", UI.hideContributeButton.bind(UI)], + ["abp-command-toggleshownotifications", "command", Notification.toggleIgnoreCategory.bind(Notification, "*", null)] ]; onShutdown.add(function() { - for (let window in UI.applicationWindows) + for (let window of UI.applicationWindows) if (UI.isBottombarOpen(window)) UI.toggleBottombar(window); }); |