diff options
Diffstat (limited to 'browser/base/content/browser-addons.js')
-rw-r--r-- | browser/base/content/browser-addons.js | 742 |
1 files changed, 0 insertions, 742 deletions
diff --git a/browser/base/content/browser-addons.js b/browser/base/content/browser-addons.js deleted file mode 100644 index 1d881536a..000000000 --- a/browser/base/content/browser-addons.js +++ /dev/null @@ -1,742 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Removes a doorhanger notification if all of the installs it was notifying -// about have ended in some way. -function removeNotificationOnEnd(notification, installs) { - let count = installs.length; - - function maybeRemove(install) { - install.removeListener(this); - - if (--count == 0) { - // Check that the notification is still showing - let current = PopupNotifications.getNotification(notification.id, notification.browser); - if (current === notification) - notification.remove(); - } - } - - for (let install of installs) { - install.addListener({ - onDownloadCancelled: maybeRemove, - onDownloadFailed: maybeRemove, - onInstallFailed: maybeRemove, - onInstallEnded: maybeRemove - }); - } -} - -const gXPInstallObserver = { - _findChildShell: function (aDocShell, aSoughtShell) - { - if (aDocShell == aSoughtShell) - return aDocShell; - - var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeItem); - for (var i = 0; i < node.childCount; ++i) { - var docShell = node.getChildAt(i); - docShell = this._findChildShell(docShell, aSoughtShell); - if (docShell == aSoughtShell) - return docShell; - } - return null; - }, - - _getBrowser: function (aDocShell) - { - for (let browser of gBrowser.browsers) { - if (this._findChildShell(browser.docShell, aDocShell)) - return browser; - } - return null; - }, - - pendingInstalls: new WeakMap(), - - showInstallConfirmation: function(browser, installInfo, height = undefined) { - // If the confirmation notification is already open cache the installInfo - // and the new confirmation will be shown later - if (PopupNotifications.getNotification("addon-install-confirmation", browser)) { - let pending = this.pendingInstalls.get(browser); - if (pending) { - pending.push(installInfo); - } else { - this.pendingInstalls.set(browser, [installInfo]); - } - return; - } - - let showNextConfirmation = () => { - // Make sure the browser is still alive. - if (gBrowser.browsers.indexOf(browser) == -1) - return; - - let pending = this.pendingInstalls.get(browser); - if (pending && pending.length) - this.showInstallConfirmation(browser, pending.shift()); - } - - // If all installs have already been cancelled in some way then just show - // the next confirmation - if (installInfo.installs.every(i => i.state != AddonManager.STATE_DOWNLOADED)) { - showNextConfirmation(); - return; - } - - const anchorID = "addons-notification-icon"; - - // Make notifications persist a minimum of 30 seconds - var options = { - displayURI: installInfo.originatingURI, - timeout: Date.now() + 30000, - }; - - let cancelInstallation = () => { - if (installInfo) { - for (let install of installInfo.installs) { - // The notification may have been closed because the add-ons got - // cancelled elsewhere, only try to cancel those that are still - // pending install. - if (install.state != AddonManager.STATE_CANCELLED) - install.cancel(); - } - } - - this.acceptInstallation = null; - - showNextConfirmation(); - }; - - let unsigned = installInfo.installs.filter(i => i.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING); - let someUnsigned = unsigned.length > 0 && unsigned.length < installInfo.installs.length; - - options.eventCallback = (aEvent) => { - switch (aEvent) { - case "removed": - cancelInstallation(); - break; - case "shown": - let addonList = document.getElementById("addon-install-confirmation-content"); - while (addonList.firstChild) - addonList.firstChild.remove(); - - for (let install of installInfo.installs) { - let container = document.createElement("hbox"); - - let name = document.createElement("label"); - name.setAttribute("value", install.addon.name); - name.setAttribute("class", "addon-install-confirmation-name"); - container.appendChild(name); - - if (someUnsigned && install.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) { - let unsigned = document.createElement("label"); - unsigned.setAttribute("value", gNavigatorBundle.getString("addonInstall.unsigned")); - unsigned.setAttribute("class", "addon-install-confirmation-unsigned"); - container.appendChild(unsigned); - } - - addonList.appendChild(container); - } - - this.acceptInstallation = () => { - for (let install of installInfo.installs) - install.install(); - installInfo = null; - - Services.telemetry - .getHistogramById("SECURITY_UI") - .add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL_CLICK_THROUGH); - }; - break; - } - }; - - options.learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); - - let messageString; - let notification = document.getElementById("addon-install-confirmation-notification"); - if (unsigned.length == installInfo.installs.length) { - // None of the add-ons are verified - messageString = gNavigatorBundle.getString("addonConfirmInstallUnsigned.message"); - notification.setAttribute("warning", "true"); - options.learnMoreURL += "unsigned-addons"; - } - else if (unsigned.length == 0) { - // All add-ons are verified or don't need to be verified - messageString = gNavigatorBundle.getString("addonConfirmInstall.message"); - notification.removeAttribute("warning"); - options.learnMoreURL += "find-and-install-add-ons"; - } - else { - // Some of the add-ons are unverified, the list of names will indicate - // which - messageString = gNavigatorBundle.getString("addonConfirmInstallSomeUnsigned.message"); - notification.setAttribute("warning", "true"); - options.learnMoreURL += "unsigned-addons"; - } - - let brandBundle = document.getElementById("bundle_brand"); - let brandShortName = brandBundle.getString("brandShortName"); - - messageString = PluralForm.get(installInfo.installs.length, messageString); - messageString = messageString.replace("#1", brandShortName); - messageString = messageString.replace("#2", installInfo.installs.length); - - let cancelButton = document.getElementById("addon-install-confirmation-cancel"); - cancelButton.label = gNavigatorBundle.getString("addonInstall.cancelButton.label"); - cancelButton.accessKey = gNavigatorBundle.getString("addonInstall.cancelButton.accesskey"); - - let acceptButton = document.getElementById("addon-install-confirmation-accept"); - acceptButton.label = gNavigatorBundle.getString("addonInstall.acceptButton.label"); - acceptButton.accessKey = gNavigatorBundle.getString("addonInstall.acceptButton.accesskey"); - - if (height) { - let notification = document.getElementById("addon-install-confirmation-notification"); - notification.style.minHeight = height + "px"; - } - - let tab = gBrowser.getTabForBrowser(browser); - if (tab) { - gBrowser.selectedTab = tab; - } - - let popup = PopupNotifications.show(browser, "addon-install-confirmation", - messageString, anchorID, null, null, - options); - - removeNotificationOnEnd(popup, installInfo.installs); - - Services.telemetry - .getHistogramById("SECURITY_UI") - .add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL); - }, - - observe: function (aSubject, aTopic, aData) - { - var brandBundle = document.getElementById("bundle_brand"); - var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo); - var browser = installInfo.browser; - - // Make sure the browser is still alive. - if (!browser || gBrowser.browsers.indexOf(browser) == -1) - return; - - const anchorID = "addons-notification-icon"; - var messageString, action; - var brandShortName = brandBundle.getString("brandShortName"); - - var notificationID = aTopic; - // Make notifications persist a minimum of 30 seconds - var options = { - displayURI: installInfo.originatingURI, - timeout: Date.now() + 30000, - }; - - switch (aTopic) { - case "addon-install-disabled": { - notificationID = "xpinstall-disabled"; - - if (gPrefService.prefIsLocked("xpinstall.enabled")) { - messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked"); - buttons = []; - } - else { - messageString = gNavigatorBundle.getString("xpinstallDisabledMessage"); - - action = { - label: gNavigatorBundle.getString("xpinstallDisabledButton"), - accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"), - callback: function editPrefs() { - gPrefService.setBoolPref("xpinstall.enabled", true); - } - }; - } - - PopupNotifications.show(browser, notificationID, messageString, anchorID, - action, null, options); - break; } - case "addon-install-origin-blocked": { - messageString = gNavigatorBundle.getFormattedString("xpinstallPromptMessage", - [brandShortName]); - - let secHistogram = Components.classes["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry).getHistogramById("SECURITY_UI"); - secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED); - let popup = PopupNotifications.show(browser, notificationID, - messageString, anchorID, - null, null, options); - removeNotificationOnEnd(popup, installInfo.installs); - break; } - case "addon-install-blocked": { - messageString = gNavigatorBundle.getFormattedString("xpinstallPromptMessage", - [brandShortName]); - - let secHistogram = Components.classes["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry).getHistogramById("SECURITY_UI"); - action = { - label: gNavigatorBundle.getString("xpinstallPromptAllowButton"), - accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"), - callback: function() { - secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED_CLICK_THROUGH); - installInfo.install(); - } - }; - - secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED); - let popup = PopupNotifications.show(browser, notificationID, - messageString, anchorID, - action, null, options); - removeNotificationOnEnd(popup, installInfo.installs); - break; } - case "addon-install-started": { - let needsDownload = function needsDownload(aInstall) { - return aInstall.state != AddonManager.STATE_DOWNLOADED; - } - // If all installs have already been downloaded then there is no need to - // show the download progress - if (!installInfo.installs.some(needsDownload)) - return; - notificationID = "addon-progress"; - messageString = gNavigatorBundle.getString("addonDownloadingAndVerifying"); - messageString = PluralForm.get(installInfo.installs.length, messageString); - messageString = messageString.replace("#1", installInfo.installs.length); - options.installs = installInfo.installs; - options.contentWindow = browser.contentWindow; - options.sourceURI = browser.currentURI; - options.eventCallback = (aEvent) => { - switch (aEvent) { - case "removed": - options.contentWindow = null; - options.sourceURI = null; - break; - } - }; - let notification = PopupNotifications.show(browser, notificationID, messageString, - anchorID, null, null, options); - notification._startTime = Date.now(); - - let cancelButton = document.getElementById("addon-progress-cancel"); - cancelButton.label = gNavigatorBundle.getString("addonInstall.cancelButton.label"); - cancelButton.accessKey = gNavigatorBundle.getString("addonInstall.cancelButton.accesskey"); - - let acceptButton = document.getElementById("addon-progress-accept"); - if (Preferences.get("xpinstall.customConfirmationUI", false)) { - acceptButton.label = gNavigatorBundle.getString("addonInstall.acceptButton.label"); - acceptButton.accessKey = gNavigatorBundle.getString("addonInstall.acceptButton.accesskey"); - } else { - acceptButton.hidden = true; - } - break; } - case "addon-install-failed": { - // TODO This isn't terribly ideal for the multiple failure case - for (let install of installInfo.installs) { - let host; - try { - host = options.displayURI.host; - } catch (e) { - // displayURI might be missing or 'host' might throw for non-nsStandardURL nsIURIs. - } - - if (!host) - host = (install.sourceURI instanceof Ci.nsIStandardURL) && - install.sourceURI.host; - - let error = (host || install.error == 0) ? "addonInstallError" : "addonLocalInstallError"; - let args; - if (install.error < 0) { - error += install.error; - args = [brandShortName, install.name]; - } else if (install.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) { - error += "Blocklisted"; - args = [install.name]; - } else { - error += "Incompatible"; - args = [brandShortName, Services.appinfo.version, install.name]; - } - - // Add Learn More link when refusing to install an unsigned add-on - if (install.error == AddonManager.ERROR_SIGNEDSTATE_REQUIRED) { - options.learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "unsigned-addons"; - } - - messageString = gNavigatorBundle.getFormattedString(error, args); - - PopupNotifications.show(browser, notificationID, messageString, anchorID, - action, null, options); - - // Can't have multiple notifications with the same ID, so stop here. - break; - } - this._removeProgressNotification(browser); - break; } - case "addon-install-confirmation": { - let showNotification = () => { - let height = undefined; - - if (PopupNotifications.isPanelOpen) { - let rect = document.getElementById("addon-progress-notification").getBoundingClientRect(); - height = rect.height; - } - - this._removeProgressNotification(browser); - this.showInstallConfirmation(browser, installInfo, height); - }; - - let progressNotification = PopupNotifications.getNotification("addon-progress", browser); - if (progressNotification) { - let downloadDuration = Date.now() - progressNotification._startTime; - let securityDelay = Services.prefs.getIntPref("security.dialog_enable_delay") - downloadDuration; - if (securityDelay > 0) { - setTimeout(() => { - // The download may have been cancelled during the security delay - if (PopupNotifications.getNotification("addon-progress", browser)) - showNotification(); - }, securityDelay); - break; - } - } - showNotification(); - break; } - case "addon-install-complete": { - let needsRestart = installInfo.installs.some(function(i) { - return i.addon.pendingOperations != AddonManager.PENDING_NONE; - }); - - if (needsRestart) { - notificationID = "addon-install-restart"; - messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart"); - action = { - label: gNavigatorBundle.getString("addonInstallRestartButton"), - accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"), - callback: function() { - BrowserUtils.restartApplication(); - } - }; - } - else { - messageString = gNavigatorBundle.getString("addonsInstalled"); - action = null; - } - - messageString = PluralForm.get(installInfo.installs.length, messageString); - messageString = messageString.replace("#1", installInfo.installs[0].name); - messageString = messageString.replace("#2", installInfo.installs.length); - messageString = messageString.replace("#3", brandShortName); - - // Remove notificaion on dismissal, since it's possible to cancel the - // install through the addons manager UI, making the "restart" prompt - // irrelevant. - options.removeOnDismissal = true; - - PopupNotifications.show(browser, notificationID, messageString, anchorID, - action, null, options); - break; } - } - }, - _removeProgressNotification(aBrowser) { - let notification = PopupNotifications.getNotification("addon-progress", aBrowser); - if (notification) - notification.remove(); - } -}; - -var LightWeightThemeWebInstaller = { - init: function () { - let mm = window.messageManager; - mm.addMessageListener("LightWeightThemeWebInstaller:Install", this); - mm.addMessageListener("LightWeightThemeWebInstaller:Preview", this); - mm.addMessageListener("LightWeightThemeWebInstaller:ResetPreview", this); - }, - - receiveMessage: function (message) { - // ignore requests from background tabs - if (message.target != gBrowser.selectedBrowser) { - return; - } - - let data = message.data; - - switch (message.name) { - case "LightWeightThemeWebInstaller:Install": { - this._installRequest(data.themeData, data.principal, data.baseURI); - break; - } - case "LightWeightThemeWebInstaller:Preview": { - this._preview(data.themeData, data.principal, data.baseURI); - break; - } - case "LightWeightThemeWebInstaller:ResetPreview": { - this._resetPreview(data && data.principal); - break; - } - } - }, - - handleEvent: function (event) { - switch (event.type) { - case "TabSelect": { - this._resetPreview(); - break; - } - } - }, - - get _manager () { - let temp = {}; - Cu.import("resource://gre/modules/LightweightThemeManager.jsm", temp); - delete this._manager; - return this._manager = temp.LightweightThemeManager; - }, - - _installRequest(dataString, principal, baseURI) { - // Don't allow installing off null principals. - if (!principal.URI) { - return; - } - - let data = this._manager.parseTheme(dataString, baseURI); - - if (!data) { - return; - } - - // A notification bar with the option to undo is normally shown after a - // theme is installed. But the discovery pane served from the url(s) - // below has its own toggle switch for quick undos, so don't show the - // notification in that case. - let notify = this._shouldShowUndoPrompt(principal); - if (this._isAllowed(principal)) { - this._install(data, notify); - return; - } - - let allowButtonText = - gNavigatorBundle.getString("lwthemeInstallRequest.allowButton"); - let allowButtonAccesskey = - gNavigatorBundle.getString("lwthemeInstallRequest.allowButton.accesskey"); - let message = - gNavigatorBundle.getFormattedString("lwthemeInstallRequest.message", - [principal.URI.host]); - let buttons = [{ - label: allowButtonText, - accessKey: allowButtonAccesskey, - callback: function () { - LightWeightThemeWebInstaller._install(data, notify); - } - }]; - - this._removePreviousNotifications(); - - let notificationBox = gBrowser.getNotificationBox(); - let notificationBar = - notificationBox.appendNotification(message, "lwtheme-install-request", "", - notificationBox.PRIORITY_INFO_MEDIUM, - buttons); - notificationBar.persistence = 1; - }, - - _install: function (newLWTheme, notify) { - let previousLWTheme = this._manager.currentTheme; - - let listener = { - onEnabling: function(aAddon, aRequiresRestart) { - if (!aRequiresRestart) { - return; - } - - let messageString = gNavigatorBundle.getFormattedString("lwthemeNeedsRestart.message", - [aAddon.name], 1); - - let action = { - label: gNavigatorBundle.getString("lwthemeNeedsRestart.button"), - accessKey: gNavigatorBundle.getString("lwthemeNeedsRestart.accesskey"), - callback: function () { - BrowserUtils.restartApplication(); - } - }; - - let options = { - timeout: Date.now() + 30000 - }; - - PopupNotifications.show(gBrowser.selectedBrowser, "addon-theme-change", - messageString, "addons-notification-icon", - action, null, options); - }, - - onEnabled: function(aAddon) { - if (notify) { - LightWeightThemeWebInstaller._postInstallNotification(newLWTheme, previousLWTheme); - } - } - }; - - AddonManager.addAddonListener(listener); - this._manager.currentTheme = newLWTheme; - AddonManager.removeAddonListener(listener); - }, - - _postInstallNotification: function (newTheme, previousTheme) { - function text(id) { - return gNavigatorBundle.getString("lwthemePostInstallNotification." + id); - } - - let buttons = [{ - label: text("undoButton"), - accessKey: text("undoButton.accesskey"), - callback: function () { - LightWeightThemeWebInstaller._manager.forgetUsedTheme(newTheme.id); - LightWeightThemeWebInstaller._manager.currentTheme = previousTheme; - } - }, { - label: text("manageButton"), - accessKey: text("manageButton.accesskey"), - callback: function () { - BrowserOpenAddonsMgr("addons://list/theme"); - } - }]; - - this._removePreviousNotifications(); - - let notificationBox = gBrowser.getNotificationBox(); - let notificationBar = - notificationBox.appendNotification(text("message"), - "lwtheme-install-notification", "", - notificationBox.PRIORITY_INFO_MEDIUM, - buttons); - notificationBar.persistence = 1; - notificationBar.timeout = Date.now() + 20000; // 20 seconds - }, - - _removePreviousNotifications: function () { - let box = gBrowser.getNotificationBox(); - - ["lwtheme-install-request", - "lwtheme-install-notification"].forEach(function (value) { - let notification = box.getNotificationWithValue(value); - if (notification) - box.removeNotification(notification); - }); - }, - - _preview(dataString, principal, baseURI) { - if (!this._isAllowed(principal)) - return; - - let data = this._manager.parseTheme(dataString, baseURI); - if (!data) - return; - - this._resetPreview(); - gBrowser.tabContainer.addEventListener("TabSelect", this, false); - this._manager.previewTheme(data); - }, - - _resetPreview(principal) { - if (!this._isAllowed(principal)) - return; - gBrowser.tabContainer.removeEventListener("TabSelect", this, false); - this._manager.resetPreview(); - }, - - _isAllowed(principal) { - if (!principal || !principal.URI || !principal.URI.schemeIs("https")) { - return false; - } - - let pm = Services.perms; - return pm.testPermission(principal.URI, "install") == pm.ALLOW_ACTION; - }, - - _shouldShowUndoPrompt(principal) { - if (!principal || !principal.URI) { - return true; - } - - let prePath = principal.URI.prePath; - if (prePath == "https://addons.palemoon.org") { - return false; - } - - return true; - } -}; - -/* - * Listen for Lightweight Theme styling changes and update the browser's theme accordingly. - */ -var LightweightThemeListener = { - _modifiedStyles: [], - - init: function () { - XPCOMUtils.defineLazyGetter(this, "styleSheet", function() { - for (let i = document.styleSheets.length - 1; i >= 0; i--) { - let sheet = document.styleSheets[i]; - if (sheet.href == "chrome://browser/skin/browser-lightweightTheme.css") - return sheet; - } - return undefined; - }); - - Services.obs.addObserver(this, "lightweight-theme-styling-update", false); - Services.obs.addObserver(this, "lightweight-theme-optimized", false); - if (document.documentElement.hasAttribute("lwtheme")) - this.updateStyleSheet(document.documentElement.style.backgroundImage); - }, - - uninit: function () { - Services.obs.removeObserver(this, "lightweight-theme-styling-update"); - Services.obs.removeObserver(this, "lightweight-theme-optimized"); - }, - - /** - * Append the headerImage to the background-image property of all rulesets in - * browser-lightweightTheme.css. - * - * @param headerImage - a string containing a CSS image for the lightweight theme header. - */ - updateStyleSheet: function(headerImage) { - if (!this.styleSheet) - return; - this.substituteRules(this.styleSheet.cssRules, headerImage); - }, - - substituteRules: function(ruleList, headerImage, existingStyleRulesModified = 0) { - let styleRulesModified = 0; - for (let i = 0; i < ruleList.length; i++) { - let rule = ruleList[i]; - if (rule instanceof Ci.nsIDOMCSSGroupingRule) { - // Add the number of modified sub-rules to the modified count - styleRulesModified += this.substituteRules(rule.cssRules, headerImage, existingStyleRulesModified + styleRulesModified); - } else if (rule instanceof Ci.nsIDOMCSSStyleRule) { - if (!rule.style.backgroundImage) - continue; - let modifiedIndex = existingStyleRulesModified + styleRulesModified; - if (!this._modifiedStyles[modifiedIndex]) - this._modifiedStyles[modifiedIndex] = { backgroundImage: rule.style.backgroundImage }; - - rule.style.backgroundImage = this._modifiedStyles[modifiedIndex].backgroundImage + ", " + headerImage; - styleRulesModified++; - } else { - Cu.reportError("Unsupported rule encountered"); - } - } - return styleRulesModified; - }, - - // nsIObserver - observe: function (aSubject, aTopic, aData) { - if ((aTopic != "lightweight-theme-styling-update" && aTopic != "lightweight-theme-optimized") || - !this.styleSheet) - return; - - if (aTopic == "lightweight-theme-optimized" && aSubject != window) - return; - - let themeData = JSON.parse(aData); - if (!themeData) - return; - this.updateStyleSheet("url(" + themeData.headerURL + ")"); - }, -}; |