summaryrefslogtreecommitdiffstats
path: root/comm/suite/components/bindings/notification.xml
diff options
context:
space:
mode:
Diffstat (limited to 'comm/suite/components/bindings/notification.xml')
-rw-r--r--comm/suite/components/bindings/notification.xml2423
1 files changed, 2423 insertions, 0 deletions
diff --git a/comm/suite/components/bindings/notification.xml b/comm/suite/components/bindings/notification.xml
new file mode 100644
index 0000000000..8965df67cb
--- /dev/null
+++ b/comm/suite/components/bindings/notification.xml
@@ -0,0 +1,2423 @@
+<?xml version="1.0"?>
+<!-- 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/. -->
+
+
+<!DOCTYPE bindings [
+<!ENTITY % commNotificationDTD SYSTEM "chrome://communicator/locale/notification.dtd">
+ %commNotificationDTD;
+<!ENTITY % globalNotificationDTD SYSTEM "chrome://global/locale/notification.dtd">
+ %globalNotificationDTD;
+]>
+
+<bindings id="browserNotificationBindings"
+ xmlns="http://www.mozilla.org/xbl"
+ xmlns:xbl="http://www.mozilla.org/xbl"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <binding id="browser-notificationbox"
+ extends="chrome://global/content/bindings/notification.xml#notificationbox">
+ <implementation implements="nsIObserver, nsIFormSubmitObserver, nsIWebProgressListener, nsIWebProgressListener2, nsIDOMEventListener">
+ <field name="_stringBundle" readonly="true">
+ <![CDATA[
+ Services.strings.createBundle("chrome://communicator/locale/notification.properties");
+ ]]>
+ </field>
+
+ <field name="_brandStringBundle" readonly="true">
+ <![CDATA[
+ Services.strings.createBundle("chrome://branding/locale/brand.properties");
+ ]]>
+ </field>
+
+ <field name="_placesBundle" readonly="true">
+ <![CDATA[
+ Services.strings.createBundle("chrome://communicator/locale/places/places.properties");
+ ]]>
+ </field>
+
+ <field name="wrappedJSObject">this</field>
+
+ <field name="_activeBrowser">null</field>
+
+ <property name="activeBrowser" readonly="true">
+ <getter>
+ <![CDATA[
+ if (!this._activeBrowser) {
+ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ var browsers = this.getElementsByTagNameNS(XUL_NS, "browser");
+ for (var i = 0; this._activeBrowser = browsers.item(i); i++)
+ if (!this._activeBrowser.hidden)
+ break;
+ }
+ return this._activeBrowser;
+ ]]>
+ </getter>
+ </property>
+
+ <field name="_cwu">null</field>
+
+ <property name="contentWindowUtils" readonly="true">
+ <getter>
+ <![CDATA[
+ if (!this._cwu)
+ this._cwu = this.activeBrowser.contentWindow
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ return this._cwu;
+ ]]>
+ </getter>
+ </property>
+
+ <field name="usePrivateBrowsing" readonly="true">
+ window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsILoadContext)
+ .usePrivateBrowsing
+ </field>
+
+ <method name="onDocumentChange">
+ <body>
+ <![CDATA[
+ this.crashNotified = false;
+ if (this.popupCount) {
+ this.popupCount = 0;
+ this.notifyPopupCountChanged();
+ }
+ this.removeTransientNotifications();
+ ]]>
+ </body>
+ </method>
+
+ <method name="addProgressListener">
+ <body>
+ <![CDATA[
+ if (this.activeBrowser && !this._addedProgressListener) {
+ this.activeBrowser.webProgress
+ .addProgressListener(this, Ci.nsIWebProgress.NOTIFY_SECURITY |
+ Ci.nsIWebProgress.NOTIFY_LOCATION |
+ Ci.nsIWebProgress.NOTIFY_REFRESH);
+ this._addedProgressListener = true;
+ }
+ ]]>
+ </body>
+ </method>
+
+ <field name="lastMessage">"EnterInsecureMessage"</field>
+ <field name="lastState">0</field>
+
+ <method name="onSecurityChange">
+ <parameter name="aWebProgress"/>
+ <parameter name="aRequest"/>
+ <parameter name="aState"/>
+ <body>
+ <![CDATA[
+ if (aState < 0)
+ aState = this.lastState;
+ const nsIWebProgressListener = Ci.nsIWebProgressListener;
+ var pref = "security.warn_leaving_secure";
+ var message = "EnterInsecureMessage";
+ var priority = this.PRIORITY_WARNING_LOW;
+ var pane = "ssl_pane";
+ var buttons = [];
+ if (aState & nsIWebProgressListener.STATE_IS_SECURE) {
+ pref = "security.warn_entering_secure";
+ message = "EnterSecureMessage";
+ priority = this.PRIORITY_INFO_LOW;
+ } else if (aState & nsIWebProgressListener.STATE_IS_BROKEN) {
+ pref = "security.warn_viewing_mixed";
+ message = "MixedContentMessage";
+ priority = this.PRIORITY_CRITICAL_LOW;
+ }
+
+ if (aState & nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT &&
+ Services.prefs.getBoolPref("security.warn_mixed_active_content")) {
+ pref = "security.warn_mixed_active_content";
+ message = "MixedActiveContentMessage";
+ priority = this.PRIORITY_CRITICAL_LOW;
+ } else if (aState & nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT &&
+ Services.prefs.getBoolPref("security.warn_mixed_active_content")) {
+ pref = "security.warn_mixed_active_content";
+ message = "BlockedActiveContentMessage";
+ priority = this.PRIORITY_INFO_LOW;
+ this.lastState = aState & ~nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT;
+ const nsIWebNavigation = Ci.nsIWebNavigation;
+ buttons = [{
+ label: this._stringBundle.GetStringFromName("SecurityKeepBlocking.label"),
+ accessKey: this._stringBundle.GetStringFromName("SecurityKeepBlocking.accesskey"),
+ callback: this.onSecurityChange.bind(this, null, null, -1)
+ }, {
+ label: this._stringBundle.GetStringFromName("SecurityUnblock.label"),
+ accessKey: this._stringBundle.GetStringFromName("SecurityUnblock.accesskey"),
+ callback: this.reloadPage.bind(this,
+ nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT |
+ nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE)
+ }];
+ } else if (aState & nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT &&
+ Services.prefs.getBoolPref("privacy.warn_tracking_content")) {
+ pref = "privacy.warn_tracking_content";
+ message = "TrackingContentMessage";
+ priority = this.PRIORITY_WARNING_LOW;
+ pane = "security_pane";
+ } else if (aState & nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT &&
+ Services.prefs.getBoolPref("privacy.warn_tracking_content")) {
+ pref = "privacy.warn_tracking_content";
+ message = "BlockedTrackingContentMessage";
+ priority = this.PRIORITY_INFO_LOW;
+ pane = "security_pane";
+ if (!this.usePrivateBrowsing) {
+ this.lastState = aState & ~nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT;
+ buttons = [{
+ label: this._stringBundle.GetStringFromName("SecurityKeepBlocking.label"),
+ accessKey: this._stringBundle.GetStringFromName("SecurityKeepBlocking.accesskey"),
+ callback: this.onSecurityChange.bind(this, null, null, -1)
+ }, {
+ label: this._stringBundle.GetStringFromName("SecurityUnblock.label"),
+ accessKey: this._stringBundle.GetStringFromName("SecurityUnblock.accesskey"),
+ callback: () => {
+ Services.perms.add(this.activeBrowser.currentURI,
+ "trackingprotection",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+ this.reloadPage();
+ }
+ }];
+ }
+ } else if (aState & nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT &&
+ Services.prefs.getBoolPref("security.warn_mixed_display_content")) {
+ pref = "security.warn_mixed_display_content";
+ message = "MixedDisplayContentMessage";
+ priority = this.PRIORITY_WARNING_LOW;
+ } else if (aState & nsIWebProgressListener.STATE_BLOCKED_MIXED_DISPLAY_CONTENT &&
+ Services.prefs.getBoolPref("security.warn_mixed_display_content")) {
+ pref = "security.warn_mixed_display_content";
+ message = "BlockedDisplayContentMessage";
+ priority = this.PRIORITY_INFO_LOW;
+ }
+
+ if (this.lastMessage == message)
+ return false;
+
+ var box = this.getNotificationWithValue(this.lastMessage);
+ if (box)
+ box.close();
+
+ this.lastMessage = message;
+
+ if (!Services.prefs.getBoolPref(pref))
+ return true;
+
+ if ("goPreferences" in window) {
+ buttons.push({
+ label: this._stringBundle.GetStringFromName("SecurityPreferences.label"),
+ accessKey: this._stringBundle.GetStringFromName("SecurityPreferences.accesskey"),
+ callback: function() {
+ goPreferences(pane);
+ return true;
+ }
+ });
+ }
+ var text = this._stringBundle.GetStringFromName(message);
+ box = this.appendNotification(text, message, null, priority, buttons);
+ box.persistence = 1;
+ box.timeout = Date.now() + 20000; // 20 seconds
+ return true;
+ ]]>
+ </body>
+ </method>
+
+ <method name="onLocationChange">
+ <parameter name="aWebProgress" />
+ <parameter name="aRequest" />
+ <parameter name="aLocation" />
+ <parameter name="aFlags" />
+ <body>
+ <![CDATA[
+ const nsIWebProgressListener = Ci.nsIWebProgressListener;
+ if (aWebProgress.DOMWindow == this.activeBrowser.contentWindow &&
+ !(aFlags & nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT))
+ this.onDocumentChange();
+ ]]>
+ </body>
+ </method>
+
+ <method name="onRefreshAttempted">
+ <parameter name="aWebProgress" />
+ <parameter name="aURI" />
+ <parameter name="aDelay" />
+ <parameter name="aSameURI" />
+ <body>
+ <![CDATA[
+ if (Services.prefs.getBoolPref("accessibility.blockautorefresh")) {
+ let brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ let refreshButtonText =
+ this._stringBundle.GetStringFromName("refreshBlocked.goButton");
+ let refreshButtonAccesskey =
+ this._stringBundle.GetStringFromName("refreshBlocked.goButton.accesskey");
+ let message =
+ this._stringBundle.formatStringFromName(aSameURI ? "refreshBlocked.refreshLabel"
+ : "refreshBlocked.redirectLabel",
+ [brandShortName], 1);
+ let notification = this.getNotificationWithValue("refresh-blocked");
+ if (notification) {
+ notification.label = message;
+ } else {
+ let buttons = [{
+ label: refreshButtonText,
+ accessKey: refreshButtonAccesskey,
+ callback: function (aNotification, aButton) {
+ var refreshURI = aNotification.webProgress
+ .QueryInterface(Ci.nsIRefreshURI);
+ refreshURI.forceRefreshURI(aNotification.uri, null,
+ aNotification.delay, true);
+ }
+ }];
+ notification =
+ this.appendNotification(message, "refresh-blocked", null,
+ this.PRIORITY_INFO_MEDIUM, buttons);
+ }
+ // In the case of a meta refresh, the location has already
+ // changed. But in the case of an HTTP header refresh, the
+ // location changes synchronously after this call returns.
+ // Set the persistence to 1 temporarily to stop this from
+ // immediately clobbering the location bar (bug 516441),
+ // but set the persistence back to 0 as soon as possible.
+ setTimeout(function() { notification.persistence = 0; }, 0);
+ notification.persistence = 1;
+ notification.webProgress = aWebProgress;
+ notification.uri = aURI;
+ notification.delay = aDelay;
+ return false;
+ }
+ return true;
+ ]]>
+ </body>
+ </method>
+
+ <method name="notify">
+ <parameter name="aFormElement"/>
+ <parameter name="aWindow"/>
+ <parameter name="aActionURI"/>
+ <parameter name="aCancel"/>
+ <body>
+ <![CDATA[
+ aCancel.value = false;
+ if (!aFormElement || !aWindow || !aActionURI)
+ return;
+
+ var browser = this.activeBrowser;
+
+ // inactive sidebar panel:
+ if (!browser || !browser.docShell || !browser.docShell.securityUI)
+ return;
+
+ // not our window:
+ if (aWindow.top != browser.contentWindow)
+ return;
+
+ // pref disabled:
+ if (!Services.prefs.getBoolPref("security.warn_submit_insecure"))
+ return;
+
+ // HTTPS uninteresting:
+ if (aActionURI.schemeIs("https"))
+ return;
+
+ // javascript doesn't hit the network:
+ if (aActionURI.schemeIs("javascript"))
+ return;
+
+ // PSM handles HTTPS source:
+ var uri;
+ try {
+ uri = aFormElement.nodePrincipal.URI;
+ } catch (e) {}
+ if (!uri)
+ uri = aFormElement.ownerDocument.documentURIObject;
+ if (uri.schemeIs("https"))
+ return;
+
+ var warn = { value: true };
+ var prompt = Services.prompt;
+ aCancel.value = prompt.confirmEx(
+ aWindow,
+ this._stringBundle.GetStringFromName("SecurityTitle"),
+ this._stringBundle.GetStringFromName("PostToInsecureFromInsecureMessage"),
+ prompt.BUTTON_TITLE_IS_STRING * prompt.BUTTON_POS_0 +
+ prompt.BUTTON_TITLE_CANCEL * prompt.BUTTON_POS_1,
+ this._stringBundle.GetStringFromName("PostToInsecureContinue"),
+ null, null,
+ this._stringBundle.GetStringFromName("PostToInsecureFromInsecureShowAgain"),
+ warn) != 0;
+ if (!aCancel.value)
+ Services.prefs.setBoolPref("security.warn_submit_insecure", warn.value);
+ ]]>
+ </body>
+ </method>
+
+ <method name="observe">
+ <parameter name="aSubject" />
+ <parameter name="aTopic" />
+ <parameter name="aData" />
+ <body>
+ <![CDATA[
+ var browser = this.activeBrowser;
+
+ // inactive sidebar panel:
+ if (!browser || !browser.docShell)
+ return;
+
+ switch (aTopic) {
+ case "indexedDB-permissions-prompt":
+ var requestor = aSubject.QueryInterface(Ci.nsIInterfaceRequestor);
+ var contentWindow = requestor.getInterface(Ci.nsIDOMWindow);
+ if (contentWindow.top == browser.contentWindow)
+ this.promptIndexedDB(requestor, contentWindow, "permissions");
+ break;
+
+ case "indexedDB-quota-prompt":
+ var requestor = aSubject.QueryInterface(Ci.nsIInterfaceRequestor);
+ var contentWindow = requestor.getInterface(Ci.nsIDOMWindow);
+ if (contentWindow.top == browser.contentWindow)
+ this.promptIndexedDB(requestor, contentWindow, "quota", aData);
+ break;
+
+ case "indexedDB-quota-cancel":
+ var requestor = aSubject.QueryInterface(Ci.nsIInterfaceRequestor);
+ var contentWindow = requestor.getInterface(Ci.nsIDOMWindow);
+ if (contentWindow.top == browser.contentWindow)
+ this.cancelIndexedDB(requestor, contentWindow, "quota", aData);
+ break;
+
+ case "addon-install-blocked":
+ var installInfo = aSubject.wrappedJSObject;
+ if (installInfo.browser == browser)
+ this.addonInstallBlocked(installInfo);
+ break;
+
+ case "addon-install-complete":
+ var installInfo = aSubject.wrappedJSObject;
+ if (installInfo.browser == browser)
+ this.addonInstallComplete(installInfo);
+ break;
+
+ case "addon-install-disabled":
+ var installInfo = aSubject.wrappedJSObject;
+ if (installInfo.browser == browser)
+ this.addonInstallDisabled(installInfo);
+ break;
+
+ case "addon-install-failed":
+ var installInfo = aSubject.wrappedJSObject;
+ if (installInfo.browser == browser)
+ this.addonInstallFailed(installInfo);
+ break;
+
+ case "addon-install-started":
+ var installInfo = aSubject.wrappedJSObject;
+ if (installInfo.browser == browser)
+ this.addonInstallStarted(installInfo);
+ break;
+
+ case "offline-cache-update-completed":
+ var doc = browser.contentDocument;
+ if (!doc.documentElement)
+ break;
+
+ var manifest = doc.documentElement.getAttribute("manifest");
+ if (!manifest)
+ break;
+
+ try {
+ var manifestURI = Services.io.newURI(manifest,
+ doc.characterSet,
+ doc.documentURIObject);
+ var cacheUpdate =
+ aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate);
+ if (manifestURI.equals(cacheUpdate.manifestURI))
+ this.checkUsage(manifestURI);
+ } catch (e) {
+ alert(e);
+ }
+ break;
+
+ case "nsPref:changed":
+ if (aData == "privacy.popups.showBrowserMessage") {
+ if (Services.prefs.getBoolPref(aData))
+ return;
+
+ var popupNotification = this.getNotificationWithValue("popup-blocked");
+ if (popupNotification)
+ this.removeNotification(popupNotification);
+ }
+
+ if (aData == "dom.disable_open_during_load") {
+ // remove notifications when popup blocking has been turned off
+ if (Services.prefs.getBoolPref(aData) || !this.popupCount)
+ return;
+
+ var popupNotification = this.getNotificationWithValue("popup-blocked");
+ if (popupNotification)
+ this.removeNotification(popupNotification);
+ this.popupCount = 0;
+ this.notifyPopupCountChanged();
+ }
+ break;
+
+ case "perm-changed":
+ // If all permissions are cleared aSubject is null.
+ if (!aSubject)
+ return;
+
+ var permission = aSubject.QueryInterface(Ci.nsIPermission);
+ if (permission.type != "popup" || aData != "added" || !this.popupCount)
+ return;
+
+ if (permission.matchesURI(this.activeBrowser.currentURI, false)) {
+ var popupNotification = this.getNotificationWithValue("popup-blocked");
+ if (popupNotification)
+ this.removeNotification(popupNotification);
+ this.popupCount = 0;
+ this.notifyPopupCountChanged();
+ }
+ break;
+ }
+ ]]>
+ </body>
+ </method>
+
+ <field name="CrashSubmit">null</field>
+
+ <field name="crashNotified">false</field>
+
+ <method name="openURLPref">
+ <parameter name="aPref"/>
+ <body>
+ <![CDATA[
+ var url = Services.urlFormatter.formatURLPref(aPref);
+ var nsIBrowserDOMWindow = Ci.nsIBrowserDOMWindow;
+
+ var browserWin;
+ var whereToOpen = Services.prefs.getIntPref("browser.link.open_external");
+
+ if (whereToOpen != nsIBrowserDOMWindow.OPEN_NEWWINDOW) {
+ browserWin = Services.wm.getMostRecentWindow("navigator:browser");
+ }
+
+ if (!browserWin) {
+ var browserURL = "chrome://navigator/content/navigator.xul";
+ try {
+ browserURL = Services.prefs.getCharPref("browser.chromeURL");
+ } catch (ex) {}
+
+ window.openDialog(browserURL, "_blank", "chrome,all,dialog=no", url);
+ } else {
+ if (whereToOpen == nsIBrowserDOMWindow.OPEN_CURRENTWINDOW)
+ browserWin.loadURI(url);
+ else {
+ // new tab
+ var browser = browserWin.getBrowser();
+ var newTab = browser.addTab(url);
+ browser.selectedTab = newTab;
+ }
+ browserWin.content.focus();
+ }
+ return true;
+ ]]>
+ </body>
+ </method>
+
+ <method name="makeNicePluginName">
+ <parameter name="aName"/>
+ <body>
+ <![CDATA[
+ // Clean up the plugin name by stripping off any trailing version
+ // numbers or "plugin". EG, "Foo Bar Plugin 1.23_02" --> "Foo Bar"
+ // Do this by first stripping the numbers, etc. off the end, and
+ // then removing "Plugin" (and then trimming to get rid of any
+ // whitespace). Otherwise, something like "Java(TM) Plug-in
+ // 1.7.0_07" gets mangled.
+ var newName = aName.replace(/[\s\d\.\-\_\(\)]+$/, "").replace(/\bplug-?in\b/i, "").trim();
+ return newName;
+ ]]>
+ </body>
+ </method>
+
+ <method name="getPluginUI">
+ <parameter name="aPlugin"/>
+ <parameter name="aAnonId"/>
+ <body>
+ <![CDATA[
+ return aPlugin.ownerDocument.getAnonymousElementByAttribute(aPlugin, "anonid", aAnonId);
+ ]]>
+ </body>
+ </method>
+
+ <method name="addLinkClickCallback">
+ <parameter name="linkNode"/>
+ <parameter name="callback"/>
+ <body>
+ <![CDATA[
+ // XXX just doing (callback)(arg) was giving a same-origin error. bug?
+
+ // We use event bubbling for the event listeners.
+ let callbackArgs = Array.from(arguments).slice(2);
+ linkNode.addEventListener("click",
+ function(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+ if (aEvent.button != 0)
+ return;
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
+ if (callbackArgs.length == 0)
+ callbackArgs = [ aEvent ];
+ callback.apply(this, callbackArgs);
+ }.bind(this));
+
+ linkNode.addEventListener("keydown",
+ function(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+ if (aEvent.keyCode != aEvent.DOM_VK_RETURN)
+ return;
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
+ if (callbackArgs.length == 0)
+ callbackArgs = [ aEvent ];
+ callback.apply(this, callbackArgs);
+ }.bind(this));
+ ]]>
+ </body>
+ </method>
+
+ <!-- Callback for user clicking "submit a report" link -->
+ <method name="submitReport">
+ <parameter name="pluginDumpID"/>
+ <parameter name="plugin"/>
+ <body>
+ <![CDATA[
+ var keyVals = {};
+ if (plugin) {
+ let userComment = this.getPluginUI(plugin, "submitComment").value.trim();
+ if (userComment)
+ keyVals.PluginUserComment = userComment;
+ if (this.getPluginUI(plugin, "submitURLOptIn").checked)
+ keyVals.PluginContentURL = plugin.ownerDocument.URL;
+ }
+ this.CrashSubmit.submit(pluginDumpID, { extraExtraKeyVals: keyVals,
+ recordSubmission: true });
+ ]]>
+ </body>
+ </method>
+
+ <!-- Callback for user clicking a "reload page" link -->
+ <method name="reloadPage">
+ <parameter name="flags"/>
+ <body>
+ <![CDATA[
+ this.activeBrowser.reloadWithFlags(flags);
+ ]]>
+ </body>
+ </method>
+
+ <!-- Callback for user clicking the help icon -->
+ <method name="openHelpPage">
+ <body>
+ <![CDATA[
+ //XXX Ratty need in app help here.
+ openHelp("plugin-crashed", "chrome://communicator/locale/help/suitehelp.rdf");
+ ]]>
+ </body>
+ </method>
+
+ <method name="showPluginCrashedNotification">
+ <parameter name="pluginDumpID"/>
+ <parameter name="messageString"/>
+ <body>
+ <![CDATA[
+ // If there's already an existing notification bar, don't do anything.
+ var notification = this.getNotificationWithValue("plugin-crashed");
+ if (notification)
+ return;
+
+ // Configure the notification bar
+ var priority = this.PRIORITY_WARNING_MEDIUM;
+ var reloadLabel = this._stringBundle.GetStringFromName("crashedpluginsMessage.reloadButton.label");
+ var reloadKey = this._stringBundle.GetStringFromName("crashedpluginsMessage.reloadButton.accesskey");
+ var submitLabel = this._stringBundle.GetStringFromName("crashedpluginsMessage.submitButton.label");
+ var submitKey = this._stringBundle.GetStringFromName("crashedpluginsMessage.submitButton.accesskey");
+
+ var buttons = [{
+ label: reloadLabel,
+ accessKey: reloadKey,
+ popup: null,
+ callback: this.reloadPage.bind(this)
+ }];
+
+ if (this.CrashSubmit && pluginDumpID) {
+ let submitButton = {
+ label: submitLabel,
+ accessKey: submitKey,
+ popup: null,
+ callback: this.submitReport.bind(this, pluginDumpID)
+ };
+ buttons.push(submitButton);
+ }
+
+ var notification = this.appendNotification(messageString, "plugin-crashed",
+ null, priority, buttons);
+
+ // Add the "learn more" link.
+ var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ var link = notification.ownerDocument.createElementNS(XULNS, "label");
+ link.className = "text-link";
+ link.setAttribute("value", this._stringBundle.GetStringFromName("crashedpluginsMessage.learnMore"));
+ this.addLinkClickCallback(link, this.openHelpPage);
+ var description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText");
+ description.appendChild(link);
+ ]]>
+ </body>
+ </method>
+
+ <method name="handleEvent">
+ <parameter name="aEvent"/>
+ <body>
+ <![CDATA[
+ if (!aEvent.isTrusted)
+ return;
+ ]]>
+ </body>
+ </method>
+
+ <method name="playSoundForBlockedPopup">
+ <body>
+ <![CDATA[
+ const kCustomSound = 1;
+ var playSound = Services.prefs.getBoolPref("privacy.popups.sound_enabled");
+
+ if (playSound) {
+ var sound = Cc["@mozilla.org/sound;1"]
+ .createInstance(Ci.nsISound);
+
+ var soundType = Services.prefs.getIntPref("privacy.popups.sound_type");
+ if (soundType == kCustomSound) {
+ var soundUrlSpec = Services.prefs.getCharPref("privacy.popups.sound_url");
+ var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"]
+ .getService(Ci.nsIFileProtocolHandler);
+ var file = fileHandler.getFileFromURLSpec(soundUrlSpec);
+ if (file.exists()) {
+ var soundUrl = fileHandler.newFileURI(file);
+ sound.play(soundUrl);
+ return;
+ }
+ }
+
+ // Either a custom sound is selected which does not exist
+ // or the system beep was selected, so make the system beep.
+ sound.beep();
+ }
+ ]]>
+ </body>
+ </method>
+
+ <field name="popupCount">0</field>
+
+ <method name="notifyPopupCountChanged">
+ <body>
+ <![CDATA[
+ this.dispatchEvent(new Event("PopupCountChanged",
+ { bubbles: true, cancelable: true }));
+ ]]>
+ </body>
+ </method>
+
+ <method name="allowPopupsForSite">
+ <parameter name="aEvent"/>
+ <body>
+ <![CDATA[
+ Services.perms.add(this.activeBrowser.currentURI, "popup",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+
+ this.removeCurrentNotification();
+ ]]>
+ </body>
+ </method>
+
+ <method name="offlineAppRequested">
+ <parameter name="aDocument"/>
+ <body>
+ <![CDATA[
+ var documentURI = aDocument.documentURIObject;
+ var pm = Services.perms;
+ if (pm.testExactPermission(documentURI, "offline-app") !=
+ Ci.nsIPermissionManager.UNKNOWN_ACTION)
+ return;
+
+ var host = documentURI.asciiHost;
+ var notificationName = "offline-app-requested-" + host;
+ var notification = this.getNotificationWithValue(notificationName);
+ if (notification)
+ notification.documents.push(aDocument);
+ else {
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("offlineApps.always"),
+ accessKey: this._stringBundle.GetStringFromName("offlineApps.always.accesskey"),
+ callback: function() {
+ pm.add(documentURI, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
+ var updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
+ .getService(Ci.nsIOfflineCacheUpdateService);
+ notification.documents.forEach(function(aDocument) {
+ if (!aDocument.documentElement)
+ return;
+ var manifest = aDocument.documentElement.getAttribute("manifest");
+ if (!manifest)
+ return;
+
+ try {
+ var manifestURI =
+ Services.io.newURI(manifest,
+ aDocument.characterSet,
+ aDocument.documentURIObject);
+ updateService.scheduleUpdate(manifestURI,
+ aDocument.documentURIObject,
+ window);
+ } catch (e) {
+ }
+ });
+ }
+ }, {
+ label: this._stringBundle.GetStringFromName("offlineApps.never"),
+ accessKey: this._stringBundle.GetStringFromName("offlineApps.never.accesskey"),
+ callback: function() {
+ pm.add(documentURI, "offline-app", Ci.nsIPermissionManager.DENY_ACTION);
+ }
+ }, {
+ label: this._stringBundle.GetStringFromName("offlineApps.later"),
+ accessKey: this._stringBundle.GetStringFromName("offlineApps.later.accesskey"),
+ callback: function() { /* no-op */ }
+ }];
+
+ var messageString = this._stringBundle.formatStringFromName(this.usePrivateBrowsing ?
+ "offlineApps.private" : "offlineApps.permissions", [host], 1);
+ var priority = this.PRIORITY_INFO_LOW;
+ notification = this.appendNotification(messageString, notificationName,
+ null, priority,
+ this.usePrivateBrowsing ?
+ null : buttons);
+ notification.documents = [aDocument];
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="checkUsage">
+ <parameter name="aURI"/>
+ <body>
+ <![CDATA[
+ if (Services.perms.testExactPermission(aURI, "offline-app") ==
+ Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN)
+ return;
+
+ var host = aURI.asciiHost;
+ var usage = 0;
+
+ var cacheService = Cc["@mozilla.org/network/application-cache-service;1"]
+ .getService(Ci.nsIApplicationCacheService);
+ cacheService.getGroups().forEach(function(aGroup) {
+ var uri = Services.io.newURI(aGroup);
+ if (uri.asciiHost == host)
+ usage += cacheService.getActiveCache(aGroup).usage;
+ });
+ var warnQuota = Services.prefs.getIntPref("offline-apps.quota.warn");
+ if (usage < warnQuota * 1024)
+ return;
+
+ var message = this._stringBundle.formatStringFromName("offlineApps.quota", [host, warnQuota / 1024], 2);
+ var priority = this.PRIORITY_WARNING_MEDIUM;
+ this.appendNotification(message, "offline-app-usage", null,
+ priority, null);
+ Services.perms.add(aURI, "offline-app",
+ Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
+ ]]>
+ </body>
+ </method>
+
+ <method name="showRightsNotification">
+ <body>
+ <![CDATA[
+ var rightsBundle = Services.strings.createBundle("chrome://branding/locale/aboutRights.properties");
+ var buttonLabel = rightsBundle.GetStringFromName("buttonLabel");
+ var buttonAccessKey = rightsBundle.GetStringFromName("buttonAccessKey");
+ var productName = this._brandStringBundle.GetStringFromName("brandFullName");
+ var notifyRightsText = rightsBundle.formatStringFromName("notifyRightsText2", [productName], 1);
+
+ var buttons = [{
+ label: buttonLabel,
+ accessKey: buttonAccessKey,
+ popup: null,
+ callback: function (aNotificationBox, aButton) {
+ var browser = document.getBindingParent(aNotificationBox);
+ browser.addTab("about:rights", { focusNewTab: true });
+ }
+ }];
+ var box = this.appendNotification(notifyRightsText, "about-rights",
+ null, this.PRIORITY_INFO_LOW,
+ buttons);
+ box.persistence = 3; // arbitrary number, just so bar sticks around for a bit
+ ]]>
+ </body>
+ </method>
+
+ <method name="showPlacesLockedWarning">
+ <body>
+ <![CDATA[
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ var message = this._placesBundle.formatStringFromName("lockPrompt.text", [brandShortName], 1);
+ var buttons = [{
+ label: this._placesBundle.GetStringFromName("lockPromptInfoButton.label"),
+ accessKey: this._placesBundle.GetStringFromName("lockPromptInfoButton.accesskey"),
+ popup: null,
+ callback: function() {
+ openHelp("places-locked", "chrome://communicator/locale/help/suitehelp.rdf");
+ }
+ }];
+ var box = this.appendNotification(message, "places-locked", null,
+ this.PRIORITY_CRITICAL_MEDIUM,
+ buttons);
+ box.persistence = -1; // until user closes it
+ ]]>
+ </body>
+ </method>
+
+ <method name="showUpdateWarning">
+ <body>
+ <![CDATA[
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ var message = this._stringBundle.formatStringFromName("updatePrompt.text", [brandShortName], 1);
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("updatePromptCheckButton.label"),
+ accessKey: this._stringBundle.GetStringFromName("updatePromptCheckButton.accesskey"),
+ popup: null,
+ callback: function() {
+ Cc["@mozilla.org/updates/update-prompt;1"]
+ .createInstance(Ci.nsIUpdatePrompt)
+ .checkForUpdates();
+ }
+ }];
+ var box = this.appendNotification(message, "update-warning", null,
+ this.PRIORITY_CRITICAL_MEDIUM,
+ buttons);
+ box.persistence = -1; // until user closes it
+ ]]>
+ </body>
+ </method>
+
+ <method name="removeNotifications">
+ <parameter name="aNotifications"/>
+ <body>
+ <![CDATA[
+ aNotifications.forEach(function(value) {
+ var box = this.getNotificationWithValue(value);
+ if (box)
+ this.removeNotification(box);
+ }, this);
+ ]]>
+ </body>
+ </method>
+
+ <method name="lwthemeInstallRequest">
+ <parameter name="aHost"/>
+ <parameter name="aCallback"/>
+ <body>
+ <![CDATA[
+ var message = this._stringBundle.formatStringFromName("lwthemeInstallRequest.message", [aHost], 1);
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("lwthemeInstallRequest.allowButton"),
+ accessKey: this._stringBundle.GetStringFromName("lwthemeInstallRequest.allowButton.accesskey"),
+ popup: null,
+ callback: aCallback
+ }];
+ var box = this.appendNotification(message,
+ "lwtheme-install-request", null,
+ this.PRIORITY_INFO_MEDIUM,
+ buttons);
+ box.persistence = 1;
+ ]]>
+ </body>
+ </method>
+
+ <method name="lwthemeInstallNotification">
+ <parameter name="aCallback"/>
+ <body>
+ <![CDATA[
+ var message = this._stringBundle.GetStringFromName("lwthemeInstallNotification.message");
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("lwthemeInstallNotification.undoButton"),
+ accessKey: this._stringBundle.GetStringFromName("lwthemeInstallNotification.undoButton.accesskey"),
+ callback: aCallback
+ }, {
+ label: this._stringBundle.GetStringFromName("lwthemeInstallNotification.manageButton"),
+ accessKey: this._stringBundle.GetStringFromName("lwthemeInstallNotification.manageButton.accesskey"),
+ callback: function() {
+ window.toEM("addons://list/theme");
+ }
+ }];
+ var box = this.appendNotification(message,
+ "lwtheme-install-notification",
+ null, this.PRIORITY_INFO_MEDIUM,
+ buttons);
+ box.persistence = 1;
+ box.timeout = Date.now() + 20000; // 20 seconds
+ ]]>
+ </body>
+ </method>
+
+ <method name="lwthemeNeedsRestart">
+ <parameter name="aNewThemeName"/>
+ <body>
+ <![CDATA[
+ var message = this._stringBundle.formatStringFromName("lwthemeNeedsRestart.message", [aNewThemeName], 1);
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("lwthemeNeedsRestart.restartButton"),
+ accessKey: this._stringBundle.GetStringFromName("lwthemeNeedsRestart.restartButton.accesskey"),
+ popup: null,
+ callback: function() {
+ BrowserUtils.restartApplication();
+ }
+ }];
+ var box = this.appendNotification(message,
+ "lwtheme-install-notification",
+ null,this.PRIORITY_INFO_MEDIUM,
+ buttons);
+ box.persistence = 1;
+ box.timeout = Date.now() + 20000; // 20 seconds
+ ]]>
+ </body>
+ </method>
+
+ <method name="promptIndexedDB">
+ <parameter name="aRequestor"/>
+ <parameter name="aWindow"/>
+ <parameter name="aTopic"/>
+ <parameter name="aData"/>
+ <body>
+ <![CDATA[
+ var host = aWindow.document.documentURIObject.asciiHost;
+ var property = this.usePrivateBrowsing ? "offlineApps.private" :
+ "offlineApps." + aTopic;
+ var message = this._stringBundle.formatStringFromName(property,
+ [host, aData], 2);
+ var observer = aRequestor.getInterface(Ci.nsIObserver);
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("offlineApps.always"),
+ accessKey: this._stringBundle.GetStringFromName("offlineApps.always.accesskey"),
+ popup: null,
+ callback: function allowIndexedDB() {
+ clearTimeout(box.timeout);
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+ }
+ }, {
+ label: this._stringBundle.GetStringFromName("offlineApps.never"),
+ accessKey: this._stringBundle.GetStringFromName("offlineApps.never.accesskey"),
+ popup: null,
+ callback: function denyIndexedDB() {
+ clearTimeout(box.timeout);
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.DENY_ACTION);
+ }
+ }, {
+ label: this._stringBundle.GetStringFromName("offlineApps.later"),
+ accessKey: this._stringBundle.GetStringFromName("offlineApps.later.accesskey"),
+ popup: null,
+ callback: function laterIndexedDB() {
+ clearTimeout(box.timeout);
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.UNKNOWN_ACTION);
+ }
+ }];
+ var box = this.appendNotification(message,
+ "indexedDB-" + aTopic + "-prompt",
+ null, this.PRIORITY_INFO_LOW,
+ this.usePrivateBrowsing ?
+ null : buttons);
+ box.timeout = setTimeout(function() {
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.UNKNOWN_ACTION);
+ if (box.parentNode)
+ box.parentNode.removeNotification(box);
+ }, 300000); // 5 minutes
+ ]]>
+ </body>
+ </method>
+
+ <method name="cancelIndexedDB">
+ <parameter name="aRequestor"/>
+ <parameter name="aWindow"/>
+ <parameter name="aTopic"/>
+ <parameter name="aData"/>
+ <body>
+ <![CDATA[
+ var popupNotification = this.getNotificationWithValue("indexedDB-" + aTopic + "-prompt");
+ if (popupNotification) {
+ clearTimeout(popupNotification.timeout);
+ this.removeNotification(popupNotification);
+ }
+
+ var observer = aRequestor.getInterface(Ci.nsIObserver);
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.UNKNOWN_ACTION);
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallBlocked">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var host;
+ try {
+ // this fails with nsSimpleURIs like data: URIs
+ host = installInfo.originatingURI.host;
+ } catch (ex) {
+ host = this._stringBundle.GetStringFromName("xpinstallHostNotAvailable");
+ }
+ var notificationName = "addon-install-blocked";
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ var messageString = this._stringBundle.formatStringFromName("xpinstallPromptWarning",
+ [brandShortName, host], 2);
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("xpinstallPromptInstallButton"),
+ accessKey: this._stringBundle.GetStringFromName("xpinstallPromptInstallButton.accesskey"),
+ popup: null,
+ callback: function allowInstall() {
+ installInfo.install();
+ return false;
+ }
+ }];
+
+ if (!this.getNotificationWithValue(notificationName)) {
+ var priority = this.PRIORITY_WARNING_MEDIUM;
+ this.appendNotification(messageString, notificationName,
+ null, priority, buttons);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallCancelled">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/PluralForm.jsm", tmp);
+ var notificationName = "addon-install-cancelled";
+ var messageString = this._stringBundle.GetStringFromName("addonDownloadCancelled");
+ messageString = tmp.PluralForm.get(installInfo.installs.length, messageString);
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("addonDownloadRestartButton"),
+ accessKey: this._stringBundle.GetStringFromName("addonDownloadRestartButton.accesskey"),
+ popup: null,
+ callback: function() {
+ var weblistener = Cc["@mozilla.org/addons/web-install-listener;1"]
+ .getService(Ci.amIWebInstallListener);
+ if (weblistener.onWebInstallRequested(installInfo.browser, installInfo.originatingURI,
+ [aInstall], 1)) {
+ aInstall.install();
+ }
+ }
+ }];
+ var priority = this.PRIORITY_INFO_MEDIUM;
+ this.appendNotification(messageString, notificationName,
+ null, priority, buttons);
+
+ installInfo.installs.every(function(aInstall) {
+ aInstall.cancel();
+ });
+ return true; // the downloading notification closed automatically
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallComplete">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/AddonManager.jsm", tmp);
+ ChromeUtils.import("resource://gre/modules/PluralForm.jsm", tmp);
+
+ var notificationName = "addon-install-complete"
+ var addonNotification = this.getNotificationWithValue(notificationName);
+ if (addonNotification)
+ this.removeNotification(addonNotification);
+
+ var buttons = [];
+ var messageString;
+ if (installInfo.installs.some(install =>
+ install.addon.pendingOperations &
+ tmp.AddonManager.PENDING_INSTALL)) {
+ messageString = this._stringBundle.GetStringFromName("addonsInstalledNeedsRestart");
+ buttons.push({
+ label: this._stringBundle.GetStringFromName("addonInstallRestartButton"),
+ accessKey: this._stringBundle.GetStringFromName("addonInstallRestartButton.accesskey"),
+ callback: function () {
+ BrowserUtils.restartApplication();
+ }
+ });
+ } else {
+ messageString = this._stringBundle.GetStringFromName("addonsInstalled");
+ }
+
+ if ("toEM" in window) {
+ buttons.push({
+ label: this._stringBundle.GetStringFromName("addonInstallManageButton"),
+ accessKey: this._stringBundle.GetStringFromName("addonInstallManageButton.accesskey"),
+ callback: function() {
+ window.toEM("addons://list/extension");
+ }
+ });
+ }
+
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ messageString = tmp.PluralForm.get(installInfo.installs.length, messageString)
+ .replace("#1", installInfo.installs[0].name)
+ .replace("#2", installInfo.installs.length)
+ .replace("#3", brandShortName);
+ var priority = this.PRIORITY_WARNING_MEDIUM;
+ this.appendNotification(messageString, notificationName,
+ null, priority, buttons);
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallDisabled">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var messageString;
+ var buttons;
+
+ var notificationName = "addon-install-disabled";
+ if (Services.prefs.prefIsLocked("xpinstall.enabled")) {
+ messageString = this._stringBundle.GetStringFromName("xpinstallDisabledMessageLocked");
+ buttons = [];
+ } else {
+ messageString = this._stringBundle.GetStringFromName("xpinstallDisabledMessage");
+ buttons = [{
+ label: this._stringBundle.GetStringFromName("xpinstallDisabledButton"),
+ accessKey: this._stringBundle.GetStringFromName("xpinstallDisabledButton.accesskey"),
+ popup: null,
+ callback: function editPrefs() {
+ Services.prefs.setBoolPref("xpinstall.enabled", true);
+ return false;
+ }
+ }];
+ }
+
+ if (!this.getNotificationWithValue(notificationName)) {
+ var priority = this.PRIORITY_WARNING_MEDIUM;
+ this.appendNotification(messageString, notificationName,
+ null, priority, buttons);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallFailed">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var notificationName = "addon-install-failed";
+ if (!this.getNotificationWithValue(notificationName)) {
+ var host;
+ try {
+ // this fails with nsSimpleURIs like data: URIs
+ host = installInfo.originatingURI.host;
+ } catch (ex) {
+ host = this._stringBundle.GetStringFromName("xpinstallHostNotAvailable");
+ }
+
+ var error = "addonErrorIncompatible";
+ var name = installInfo.installs[0].name;
+ installInfo.installs.some(function(install) {
+ if (install.error) {
+ name = install.name;
+ error = "addonError" + install.error;
+ return true;
+ }
+ if (install.addon.blocklistState ==
+ Ci.nsIBlocklistService.STATE_BLOCKED) {
+ name = install.name;
+ error = "addonErrorBlocklisted";
+ }
+ return false;
+ });
+
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ var version = Services.appinfo.version;
+ var messageString = this._stringBundle.GetStringFromName(error)
+ .replace("#1", name)
+ .replace("#2", host)
+ .replace("#3", brandShortName)
+ .replace("#4", version);
+
+ var priority = this.PRIORITY_WARNING_MEDIUM;
+ this.appendNotification(messageString, notificationName,
+ null, priority, []);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallStarted">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/AddonManager.jsm", tmp);
+ if (installInfo.installs.every(function(aInstall) {
+ return aInstall.state == tmp.AddonManager.STATE_DOWNLOADED;
+ }))
+ return;
+
+ ChromeUtils.import("resource://gre/modules/PluralForm.jsm", tmp);
+ var notificationName = "addon-install-started";
+ var messageString = this._stringBundle.GetStringFromName("addonDownloading");
+ messageString = tmp.PluralForm.get(installInfo.installs.length, messageString);
+ var buttons = [{
+ label: this._stringBundle.GetStringFromName("addonDownloadCancelButton"),
+ accessKey: this._stringBundle.GetStringFromName("addonDownloadCancelButton.accesskey"),
+ popup: null,
+ callback: this.addonInstallCancelled.bind(this, installInfo)
+ }];
+ var priority = this.PRIORITY_INFO_MEDIUM;
+ var box = this.appendNotification(messageString, notificationName,
+ null, priority, buttons);
+ box.installInfo = installInfo;
+ installInfo.installs.forEach(function(aInstall) {
+ aInstall.addListener(box);
+ });
+ ]]>
+ </body>
+ </method>
+
+ <method name="ignoreSafeBrowsingWarning">
+ <parameter name="aReason"/>
+ <parameter name="aBlockedInfo"/>
+
+ <body>
+ <![CDATA[
+ var uri = this.activeBrowser.currentURI;
+ var flag = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER;
+ this.activeBrowser.loadURIWithFlags(uri.asciiSpec, flag,
+ null, null, null);
+
+ Services.perms.add(uri, "safe-browsing",
+ Ci.nsIPermissionManager.ALLOW_ACTION,
+ Ci.nsIPermissionManager.EXPIRE_SESSION);
+
+ var title, label, accessKey, reportName, buttons;
+
+ switch (aReason) {
+ case "phishing":
+ title = "safebrowsing.deceptiveSite";
+ label = "safebrowsing.notADeceptiveSiteButton.label";
+ accessKey = "safebrowsing.notADeceptiveSiteButton.accessKey";
+ reportName = "PhishMistake";
+ break;
+ case "malware":
+ title = "safebrowsing.reportedAttackSite";
+ label = "safebrowsing.notAnAttackButton.label";
+ accessKey = "safebrowsing.notAnAttackButton.accessKey";
+ reportName = "MalwareMistake";
+ break;
+ case "unwanted":
+ title = "safebrowsing.reportedUnwantedSite";
+ break;
+ // No notifications for unknown reasons.
+ default:
+ return;
+ }
+
+ title = this._stringBundle.GetStringFromName(title);
+
+ buttons = [{
+ label: this._stringBundle.GetStringFromName("safebrowsing.getMeOutOfHereButton.label"),
+ accessKey: this._stringBundle.GetStringFromName("safebrowsing.getMeOutOfHereButton.accessKey"),
+ callback: getMeOutOfHere
+ }]
+
+ if (reportName) {
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/SafeBrowsing.jsm", tmp);
+ var reportUrl = tmp.SafeBrowsing.getReportURL(reportName, aBlockedInfo);
+
+ // There's no button if we can not get report url, for example
+ // if the provider of blockedInfo is not Google.
+ if (reportUrl) {
+ buttons.push({
+ label: this._stringBundle.GetStringFromName(label),
+ accessKey: this._stringBundle.GetStringFromName(accessKey),
+ callback() { openUILinkIn(reportUrl, "tabfocused"); }
+ });
+ }
+ }
+
+ var type = "blocked-badware-page";
+ var notification = this.getNotificationWithValue(type);
+ if (notification)
+ this.removeNotification(notification);
+
+ var box = this.appendNotification(title, type, null,
+ this.PRIORITY_CRITICAL_HIGH,
+ buttons);
+
+ // Persist the notification until the user removes so it
+ // doesn't get removed on redirects.
+ box.persistence = -1;
+ ]]>
+ </body>
+ </method>
+ <constructor>
+ <![CDATA[
+ var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+ var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
+ ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm");
+
+ Services.obs.addObserver(this, "indexedDB-permissions-prompt");
+ Services.obs.addObserver(this, "indexedDB-quota-prompt");
+ Services.obs.addObserver(this, "indexedDB-quota-cancel");
+ Services.obs.addObserver(this, "addon-install-blocked");
+ Services.obs.addObserver(this, "addon-install-complete");
+ Services.obs.addObserver(this, "addon-install-disabled");
+ Services.obs.addObserver(this, "addon-install-failed");
+ Services.obs.addObserver(this, "addon-install-started");
+ Services.obs.addObserver(this, "offline-cache-update-completed");
+ Services.obs.addObserver(this, "perm-changed");
+ Services.obs.addObserver(this, "formsubmit");
+
+ Services.prefs.addObserver("privacy.popups.showBrowserMessage", this);
+ Services.prefs.addObserver("dom.disable_open_during_load", this);
+
+ this.addProgressListener();
+
+ if (AppConstants.MOZ_CRASHREPORTER)
+ ChromeUtils.import("resource://gre/modules/CrashSubmit.jsm", this);
+ ]]>
+ </constructor>
+
+ <destructor>
+ <![CDATA[
+ this.destroy();
+ ]]>
+ </destructor>
+
+ <field name="mDestroyed">false</field>
+
+ <!-- This is necessary because the destructor doesn't always get called when
+ we are removed from a tabbrowser. This will be explicitly called by tabbrowser -->
+ <method name="destroy">
+ <body>
+ <![CDATA[
+ if (this.mDestroyed)
+ return;
+ this.mDestroyed = true;
+
+ if (this._addedProgressListener) {
+ this.activeBrowser.webProgress.removeProgressListener(this);
+ this._addedProgressListener = false;
+ }
+
+ this._activeBrowser = null;
+ try {
+ Services.obs.removeObserver(this, "indexedDB-permissions-prompt");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "indexedDB-quota-prompt");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "indexedDB-quota-cancel");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "addon-install-blocked");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "addon-install-complete");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "addon-install-disabled");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "addon-install-failed");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "addon-install-started");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "offline-cache-update-completed");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "perm-changed");
+ } catch (ex) {}
+ try {
+ Services.obs.removeObserver(this, "formsubmit");
+ } catch (ex) {}
+
+ try {
+ Services.prefs.removeObserver("privacy.popups.showBrowserMessage", this);
+ } catch (ex) {}
+ try {
+ Services.prefs.removeObserver("dom.disable_open_during_load", this);
+ } catch (ex) {}
+ ]]>
+ </body>
+ </method>
+ </implementation>
+
+ <handlers>
+ <handler event="DOMContentLoaded" phase="capturing">
+ <![CDATA[
+ if (/^about:neterror\?e=netOffline/.test(event.target.documentURI))
+ event.target.addEventListener("click", function tryAgain(event) {
+ if (event.target.id == "errorTryAgain")
+ Services.io.offline = false;
+ }, true);
+ ]]>
+ </handler>
+
+ <handler event="DOMUpdatePageReport" phase="capturing">
+ <![CDATA[
+ var browser = this.activeBrowser;
+ if (!browser.blockedPopups || browser.blockedPopups.reported != false)
+ return;
+
+ // this.popupCount can be 0, while browser.blockedPopups has not been cleared.
+ if (!this.popupCount && browser.blockedPopups.length > 1) {
+ this.popupCount = browser.blockedPopups.length;
+ } else {
+ this.popupCount++;
+ }
+ this.playSoundForBlockedPopup();
+ this.notifyPopupCountChanged();
+
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/PluralForm.jsm", tmp);
+ if (Services.prefs.getBoolPref("privacy.popups.showBrowserMessage"))
+ {
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ var message = this._stringBundle.GetStringFromName("popupWarning.message");
+ message = tmp.PluralForm.get(this.popupCount, message)
+ .replace("#1", brandShortName)
+ .replace("#2", this.popupCount);
+
+ var notification = this.getNotificationWithValue("popup-blocked");
+ if (notification) {
+ notification.label = message;
+ } else {
+ var popupButtonText = this._stringBundle.GetStringFromName("popupWarningButton");
+ var popupButtonAccesskey = this._stringBundle.GetStringFromName("popupWarningButton.accesskey");
+ var buttons = [{
+ label: popupButtonText,
+ accessKey: popupButtonAccesskey,
+ popup: "popupNotificationMenu",
+ callback: null
+ }];
+
+ const priority = this.PRIORITY_WARNING_MEDIUM;
+ this.appendNotification(message, "popup-blocked",
+ null, priority, buttons);
+ }
+ }
+ ]]>
+ </handler>
+
+ <handler event="PluginCrashed" phase="capturing">
+ <![CDATA[
+ // Ensure the plugin and event are of the right type.
+ var plugin = event.target;
+ var detail = event.detail;
+ if (!(detail instanceof Ci.nsIPropertyBag2))
+ return;
+
+ var submittedReport = detail.getPropertyAsBool("submittedCrashReport");
+ var doPrompt = true; // XXX followup for .getPropertyAsBool("doPrompt");
+ var submitReports = true; // XXX followup for .getPropertyAsBool("submitReports");
+ var pluginName = detail.getPropertyAsAString("pluginName");
+ var pluginFilename = detail.getPropertyAsAString("pluginFilename");
+ var pluginDumpID = detail.getPropertyAsAString("pluginDumpID");
+
+ // Remap the plugin name to a more user-presentable form.
+ pluginName = this.makeNicePluginName(pluginName);
+
+ // Force a style flush, so that we ensure our binding is attached.
+ plugin.clientTop;
+
+ // Configure the crashed-plugin placeholder.
+ var overlay = this.getPluginUI(plugin, "main");
+
+ var status;
+ var statusDiv = this.getPluginUI(plugin, "submitStatus");
+
+ if (this.CrashSubmit) {
+ // Determine which message to show regarding crash reports.
+ if (submittedReport) { // submitReports && !doPrompt, handled in observer
+ status = "submitted";
+ }
+ else if (!submitReports && !doPrompt) {
+ status = "noSubmit";
+ }
+ else { // doPrompt
+ status = "please";
+ this.getPluginUI(plugin, "submitButton").addEventListener("click",
+ function (event) {
+ if (event.button != 0 || !event.isTrusted)
+ return;
+ this.submitReport(pluginDumpID, plugin);
+ Services.prefs.setBoolPref("dom.ipc.plugins.reportCrashURL", optInCB.checked);
+ }.bind(this));
+ let optInCB = this.getPluginUI(plugin, "submitURLOptIn");
+ optInCB.checked = Services.prefs.getBoolPref("dom.ipc.plugins.reportCrashURL");
+ }
+
+ // If we're showing the link to manually trigger report submission, we'll
+ // want to be able to update all the instances of the UI for this crash to
+ // show an updated message when a report is submitted.
+ if (doPrompt) {
+ let observer = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+ Ci.nsISupportsWeakReference]),
+ observe: function(subject, topic, data) {
+ let propertyBag = subject;
+ if (!(propertyBag instanceof Ci.nsIPropertyBag2))
+ return;
+ // Ignore notifications for other crashes.
+ if (propertyBag.get("minidumpID") != pluginDumpID)
+ return;
+ statusDiv.setAttribute("status", data);
+ },
+
+ handleEvent : function(event) {
+ // Not expected to be called, just here for the closure.
+ }
+ }
+
+ // Use a weak reference, so we don't have to remove it...
+ Services.obs.addObserver(observer, "crash-report-status", true);
+ // ...alas, now we need something to hold a strong reference to prevent
+ // it from being GC. But I don't want to manually manage the reference's
+ // lifetime (which should be no greater than the page).
+ // Clever solution? Use a closure with an event listener on the statusDiv.
+ // When it goes away, so do the listener references and the closure.
+ statusDiv.addEventListener("mozCleverClosureHack", observer);
+ }
+ }
+
+ // If we don't have a minidumpID, we can't (or didn't) submit anything.
+ // This can happen if the plugin is killed from the task manager.
+ if (!pluginDumpID) {
+ status = "noReport";
+ }
+
+ statusDiv.setAttribute("status", status);
+
+ var helpIcon = this.getPluginUI(plugin, "helpIcon");
+ this.addLinkClickCallback(helpIcon, this.openHelpPage);
+
+ var messageString = this._stringBundle.formatStringFromName("crashedpluginsMessage.title", [pluginName], 1);
+ var crashText = this.getPluginUI(plugin, "crashedText");
+ crashText.textContent = messageString;
+
+ var link = this.getPluginUI(plugin, "reloadLink");
+ this.addLinkClickCallback(link, this.reloadPage);
+
+ overlay.classList.add("visible");
+ // If a previous plugin on the page was too small and resulted in
+ // adding a notification bar, then remove it because this plugin
+ // instance it big enough to serve as in-content notification.
+ var notification = this.getNotificationWithValue("plugin-crashed");
+ if (notification)
+ this.removeNotification(notification, true);
+ this.crashNotified = true;
+ ]]>
+ </handler>
+
+ <handler event="MozApplicationManifest" phase="capturing">
+ <![CDATA[
+ if (!Services.prefs.getBoolPref("browser.offline-apps.notify"))
+ return;
+
+ try {
+ if (Services.prefs.getBoolPref("offline-apps.allow_by_default"))
+ return;
+ } catch (e) {
+ }
+
+ this.offlineAppRequested(event.originalTarget);
+ ]]>
+ </handler>
+
+ <handler event="pageshow" phase="capturing">
+ <![CDATA[
+ // |event.persisted| is true when the page is loaded from the
+ // BF cache, so this code reshows the notification if necessary.
+ if (!event.persisted)
+ return;
+ ]]>
+ </handler>
+ </handlers>
+ </binding>
+
+ <binding id="popup-notification"
+ extends="chrome://communicator/content/bindings/notification.xml#browser-notificationbox">
+ <implementation>
+ <method name="onLocationChange">
+ <parameter name="aWebProgress" />
+ <parameter name="aRequest" />
+ <parameter name="aLocation" />
+ <parameter name="aFlags" />
+ <body>
+ <![CDATA[
+ const nsIWebProgressListener = Ci.nsIWebProgressListener;
+ if (aWebProgress.DOMWindow == this.activeBrowser.contentWindow &&
+ !(aFlags & nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) {
+ this.onDocumentChange();
+ PopupNotifications.locationChange(this.activeBrowser);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="removeNotifications">
+ <parameter name="aNotifications"/>
+ <body>
+ <![CDATA[
+ aNotifications.forEach(function(value) {
+ var notification = PopupNotifications.getNotification(value);
+ if (notification)
+ PopupNotifications.remove(notification);
+ });
+ ]]>
+ </body>
+ </method>
+
+ <method name="lwthemeInstallRequest">
+ <parameter name="aHost"/>
+ <parameter name="aCallback"/>
+ <body>
+ <![CDATA[
+ var message = this._stringBundle.formatStringFromName("lwthemeInstallRequest.message", [aHost], 1);
+ var action = {
+ label: this._stringBundle.GetStringFromName("lwthemeInstallRequest.allowButton"),
+ accessKey: this._stringBundle.GetStringFromName("lwthemeInstallRequest.allowButton.accesskey"),
+ callback: aCallback
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "lwtheme-install-request", message,
+ "addons-notification-icon", action);
+ ]]>
+ </body>
+ </method>
+
+ <method name="lwthemeInstallNotification">
+ <parameter name="aCallback"/>
+ <body>
+ <![CDATA[
+ var message = this._stringBundle.GetStringFromName("lwthemeInstallNotification.message");
+ var mainAction = {
+ label: this._stringBundle.GetStringFromName("lwthemeInstallNotification.undoButton"),
+ accessKey: this._stringBundle.GetStringFromName("lwthemeInstallNotification.undoButton.accesskey"),
+ callback: aCallback
+ };
+ var secondaryActions = [{
+ label: this._stringBundle.GetStringFromName("lwthemeInstallNotification.manageButton"),
+ accessKey: this._stringBundle.GetStringFromName("lwthemeInstallNotification.manageButton.accesskey"),
+ callback: function() {
+ window.toEM("addons://list/theme");
+ }
+ }];
+ var options = {
+ timeout: Date.now() + 20000 // 20 seconds
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "lwtheme-install-notification", message,
+ "addons-notification-icon", mainAction,
+ secondaryActions, options);
+ ]]>
+ </body>
+ </method>
+
+ <method name="lwthemeNeedsRestart">
+ <parameter name="aNewThemeName"/>
+ <body>
+ <![CDATA[
+ var message = this._stringBundle.formatStringFromName("lwthemeNeedsRestart.message", [aNewThemeName], 1);
+ var action = {
+ label: this._stringBundle.GetStringFromName("lwthemeNeedsRestart.restartButton"),
+ accessKey: this._stringBundle.GetStringFromName("lwthemeNeedsRestart.restartButton.accesskey"),
+ callback: function() {
+ BrowserUtils.restartApplication();
+ }
+ };
+ var options = {
+ timeout: Date.now() + 20000 // 20 seconds
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "lwtheme-install-notification", message,
+ "addons-notification-icon", action, null,
+ options);
+ ]]>
+ </body>
+ </method>
+
+ <method name="promptIndexedDB">
+ <parameter name="aRequestor"/>
+ <parameter name="aWindow"/>
+ <parameter name="aTopic"/>
+ <parameter name="aData"/>
+ <body>
+ <![CDATA[
+ var host = aWindow.document.documentURIObject.asciiHost;
+ var property = this.usePrivateBrowsing ? "offlineApps.private" :
+ "offlineApps." + aTopic;
+ var message = this._stringBundle.formatStringFromName(property,
+ [host, aData], 2);
+ var observer = aRequestor.getInterface(Ci.nsIObserver);
+ var mainAction = {
+ label: this._stringBundle.GetStringFromName("offlineApps.always"),
+ accessKey: this._stringBundle.GetStringFromName("offlineApps.always.accesskey"),
+ callback: function allowIndexedDB() {
+ clearTimeout(notification.timeout);
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+ }
+ };
+ var secondaryActions = [{
+ label: this._stringBundle.GetStringFromName("offlineApps.never"),
+ accessKey: this._stringBundle.GetStringFromName("offlineApps.never.accesskey"),
+ callback: function denyIndexedDB() {
+ clearTimeout(notification.timeout);
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.DENY_ACTION);
+ }
+ }];
+ function notificationTimedOut() {
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.UNKNOWN_ACTION);
+ notification.remove();
+ }
+ var options = {
+ eventCallback: function(state) {
+ if (notification) {
+ // Always clear the timeout up front. If the doorhanger was
+ // temporarily dismissed, we'll set a new 30 second timeout
+ // to automatically cancel the request. If the doorhanger
+ // gets redisplayed we don't want it to time out unless it
+ // gets dismissed again. And if the doorhanger gets removed
+ // then we aren't interested in it any more.
+ clearTimeout(timeout);
+ if (state == "dismissed")
+ timeout = setTimeout(notificationTimedOut, 30000);
+ }
+ }
+ };
+ var notification =
+ PopupNotifications.show(this.activeBrowser,
+ "indexedDB-" + aTopic + "-prompt",
+ message, "indexedDB-notification-icon",
+ this.usePrivateBrowsing ? null : mainAction,
+ secondaryActions, options);
+ var timeout = setTimeout(notificationTimedOut, 300000); // 5 minutes
+ ]]>
+ </body>
+ </method>
+
+ <method name="cancelIndexedDB">
+ <parameter name="aRequestor"/>
+ <parameter name="aWindow"/>
+ <parameter name="aTopic"/>
+ <parameter name="aData"/>
+ <body>
+ <![CDATA[
+ var popupNotification = PopupNotifications.getNotification("indexedDB-" + aTopic + "-prompt", this.activeBrowser);
+ if (popupNotification)
+ popupNotification.remove(); // eventCallback clears the timeout
+
+ var observer = aRequestor.getInterface(Ci.nsIObserver);
+ observer.observe(null, "indexedDB-" + aTopic + "-response",
+ Ci.nsIPermissionManager.UNKNOWN_ACTION);
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallBlocked">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var host;
+ try {
+ // this fails with nsSimpleURIs like data: URIs
+ host = installInfo.originatingURI.host;
+ } catch (ex) {
+ host = this._stringBundle.GetStringFromName("xpinstallHostNotAvailable");
+ }
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ var messageString = this._stringBundle.formatStringFromName("xpinstallPromptWarning",
+ [brandShortName, host], 2);
+ var action = {
+ label: this._stringBundle.GetStringFromName("xpinstallPromptInstallButton"),
+ accessKey: this._stringBundle.GetStringFromName("xpinstallPromptInstallButton.accesskey"),
+ callback: function allowInstall() {
+ installInfo.install();
+ return false;
+ }
+ };
+
+ // Make notifications persist a minimum of 30 seconds
+ var options = {
+ timeout: Date.now() + 30000
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "addon-install-blocked", messageString,
+ "addons-notification-icon", action,
+ null, options);
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallCancelled">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/PluralForm.jsm", tmp);
+ var messageString = this._stringBundle.GetStringFromName("addonDownloadCancelled");
+ messageString = tmp.PluralForm.get(installInfo.installs.length, messageString);
+ var action = {
+ label: this._stringBundle.GetStringFromName("addonDownloadRestartButton"),
+ accessKey: this._stringBundle.GetStringFromName("addonDownloadRestartButton.accesskey"),
+ popup: null,
+ callback: function() {
+ var weblistener = Cc["@mozilla.org/addons/web-install-listener;1"]
+ .getService(Ci.amIWebInstallListener);
+ if (weblistener.onWebInstallRequested(installInfo.browser, installInfo.originatingURI,
+ [aInstall], 1)) {
+ aInstall.install();
+ }
+ }
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "addon-install-cancelled", messageString,
+ "addons-notification-icon", action);
+
+ installInfo.installs.every(function(aInstall) {
+ aInstall.cancel();
+ });
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallComplete">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/AddonManager.jsm", tmp);
+ ChromeUtils.import("resource://gre/modules/PluralForm.jsm", tmp);
+
+ var messageString;
+ var mainAction = null;
+ var secondaryActions = null;
+
+ if ("toEM" in window) {
+ mainAction = {
+ label: this._stringBundle.GetStringFromName("addonInstallManageButton"),
+ accessKey: this._stringBundle.GetStringFromName("addonInstallManageButton.accesskey"),
+ callback: function() {
+ window.toEM("addons://list/extension");
+ }
+ };
+ }
+
+ if (installInfo.installs.some(install =>
+ install.addon.pendingOperations &
+ tmp.AddonManager.PENDING_INSTALL)) {
+ messageString = this._stringBundle.GetStringFromName("addonsInstalledNeedsRestart");
+ if (mainAction)
+ secondaryActions = [mainAction];
+ mainAction = {
+ label: this._stringBundle.GetStringFromName("addonInstallRestartButton"),
+ accessKey: this._stringBundle.GetStringFromName("addonInstallRestartButton.accesskey"),
+ callback: function () {
+ BrowserUtils.restartApplication();
+ }
+ };
+ } else {
+ messageString = this._stringBundle.GetStringFromName("addonsInstalled");
+ }
+
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ messageString = tmp.PluralForm.get(installInfo.installs.length, messageString)
+ .replace("#1", installInfo.installs[0].name)
+ .replace("#2", installInfo.installs.length)
+ .replace("#3", brandShortName);
+
+ // Make notifications persist a minimum of 30 seconds
+ var options = {
+ timeout: Date.now() + 30000
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "addon-install-complete", messageString,
+ "addons-notification-icon", mainAction,
+ secondaryActions, options);
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallDisabled">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var messageString;
+ var action = null;
+
+ if (Services.prefs.prefIsLocked("xpinstall.enabled"))
+ messageString = this._stringBundle.GetStringFromName("xpinstallDisabledMessageLocked");
+ else {
+ messageString = this._stringBundle.GetStringFromName("xpinstallDisabledMessage");
+ action = {
+ label: this._stringBundle.GetStringFromName("xpinstallDisabledButton"),
+ accessKey: this._stringBundle.GetStringFromName("xpinstallDisabledButton.accesskey"),
+ callback: function editPrefs() {
+ Services.prefs.setBoolPref("xpinstall.enabled", true);
+ }
+ };
+ }
+
+ // Make notifications persist a minimum of 30 seconds
+ var options = {
+ timeout: Date.now() + 30000
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "addon-install-disabled", messageString,
+ "addons-notification-icon", action,
+ null, options);
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallFailed">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var host;
+ try {
+ // this fails with nsSimpleURIs like data: URIs
+ host = installInfo.originatingURI.host;
+ } catch (ex) {
+ host = this._stringBundle.GetStringFromName("xpinstallHostNotAvailable");
+ }
+
+ var error = "addonErrorIncompatible";
+ var name = installInfo.installs[0].name;
+ installInfo.installs.some(function(install) {
+ if (install.error) {
+ name = install.name;
+ error = "addonError" + install.error;
+ return true;
+ }
+ if (install.addon.blocklistState ==
+ Ci.nsIBlocklistService.STATE_BLOCKED) {
+ name = install.name;
+ error = "addonErrorBlocklisted";
+ }
+ return false;
+ });
+
+ var brandShortName = this._brandStringBundle.GetStringFromName("brandShortName");
+ var version = Services.appinfo.version;
+ var messageString = this._stringBundle.GetStringFromName(error)
+ .replace("#1", name)
+ .replace("#2", host)
+ .replace("#3", brandShortName)
+ .replace("#4", version);
+
+ // Make notifications persist a minimum of 30 seconds
+ var options = {
+ timeout: Date.now() + 30000
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "addon-install-failed", messageString,
+ "addons-notification-icon", null,
+ null, options);
+ ]]>
+ </body>
+ </method>
+
+ <method name="addonInstallStarted">
+ <parameter name="installInfo"/>
+ <body>
+ <![CDATA[
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/AddonManager.jsm", tmp);
+ if (installInfo.installs.every(function(aInstall) {
+ return aInstall.state == tmp.AddonManager.STATE_DOWNLOADED;
+ }))
+ return;
+
+ ChromeUtils.import("resource://gre/modules/PluralForm.jsm", tmp);
+ var messageString = this._stringBundle.GetStringFromName("addonDownloading");
+ messageString = tmp.PluralForm.get(installInfo.installs.length, messageString);
+ var action = {
+ label: this._stringBundle.GetStringFromName("addonDownloadCancelButton"),
+ accessKey: this._stringBundle.GetStringFromName("addonDownloadCancelButton.accesskey"),
+ callback: this.addonInstallCancelled.bind(this, installInfo)
+ };
+ var options = {
+ installInfo: installInfo
+ };
+ PopupNotifications.show(this.activeBrowser,
+ "addon-install-started", messageString,
+ "addons-notification-icon", action,
+ null, options);
+ ]]>
+ </body>
+ </method>
+ <constructor>
+ <![CDATA[
+ ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm");
+ ]]>
+ </constructor>
+ </implementation>
+ </binding>
+
+ <binding id="addon-progress-notification"
+ extends="chrome://global/content/bindings/notification.xml#notification">
+ <content>
+ <xul:hbox class="notification-inner outset" flex="1" xbl:inherits="type">
+ <xul:hbox anonid="details" align="center" flex="1"
+ oncommand="this.parentNode.parentNode._doButtonCommand(event);">
+ <xul:image anonid="messageImage" class="messageImage" xbl:inherits="src=image,type,value"/>
+ <xul:description anonid="messageText" class="messageText" xbl:inherits="xbl:text=label"/>
+ <xul:progressmeter mode="undetermined" xbl:inherits="mode,value=progress"/>
+ <xul:label flex="1" xbl:inherits="value=status"/>
+ <children/>
+ </xul:hbox>
+ <xul:toolbarbutton ondblclick="event.stopPropagation();"
+ class="messageCloseButton tabbable"
+ xbl:inherits="hidden=hideclose"
+ tooltiptext="&closeNotification.tooltip;"
+ oncommand="document.getBindingParent(this).close();"/>
+ </xul:hbox>
+ </content>
+
+ <implementation>
+ <destructor>
+ <![CDATA[
+ this.installInfo.installs.forEach(function(aInstall) {
+ aInstall.removeListener(this);
+ }, this);
+ ]]>
+ </destructor>
+
+ <method name="updateProgress">
+ <body>
+ <![CDATA[
+ var count = 0;
+ var progress = 0;
+ var max = 0;
+
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/AddonManager.jsm", tmp);
+ this.installInfo.installs.forEach(function(aInstall) {
+ if (aInstall.maxProgress < 0)
+ max = -1;
+ else if (max >= 0)
+ max += aInstall.maxProgress;
+ progress += aInstall.progress;
+ if (aInstall.state < tmp.AddonManager.STATE_DOWNLOADED)
+ count++;
+ });
+
+ if (max < 0)
+ this.setAttribute("mode", "undetermined");
+ else {
+ this.setAttribute("mode", "determined");
+ this.setAttribute("progress", progress * 100 / max);
+ }
+
+ var now = Date.now();
+ if (!this.startTime) {
+ this.startTime = now;
+ this.lastUpdate = now - 750;
+ this.lastSeconds = null;
+ }
+
+ if (progress == max || now - this.lastUpdate >= 750) {
+ this.lastUpdate = now;
+ var elapsed = (now - this.startTime) / 1000;
+ var rate = elapsed && progress / elapsed;
+ ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm", tmp);
+ var status;
+ [status, this.lastSeconds] = tmp.DownloadUtils.getDownloadStatus(progress, max, rate, this.lastSeconds);
+ this.setAttribute("status", status);
+ }
+
+ if (!count)
+ this.close();
+ ]]>
+ </body>
+ </method>
+
+ <method name="onDownloadProgress">
+ <body>
+ <![CDATA[
+ this.updateProgress();
+ ]]>
+ </body>
+ </method>
+
+ <method name="onDownloadFailed">
+ <body>
+ <![CDATA[
+ this.updateProgress();
+ ]]>
+ </body>
+ </method>
+
+ <method name="onDownloadCancelled">
+ <body>
+ <![CDATA[
+ this.updateProgress();
+ ]]>
+ </body>
+ </method>
+
+ <method name="onDownloadEnded">
+ <body>
+ <![CDATA[
+ this.updateProgress();
+ ]]>
+ </body>
+ </method>
+ </implementation>
+ </binding>
+
+ <binding id="sidebar-notification"
+ extends="chrome://global/content/bindings/notification.xml#notification">
+ <content>
+ <xul:vbox class="notification-inner outset" flex="1" xbl:inherits="type">
+ <xul:hbox align="center">
+ <xul:image anonid="messageImage" class="messageImage" xbl:inherits="src=image,type,value"/>
+ <xul:arrowscrollbox orient="horizontal" flex="1" pack="end"
+ oncommand="document.getBindingParent(this)._doButtonCommand(event);">
+ <children/>
+ </xul:arrowscrollbox>
+ <xul:toolbarbutton ondblclick="event.stopPropagation();"
+ class="messageCloseButton tabbable"
+ xbl:inherits="hidden=hideclose"
+ tooltiptext="&closeNotification.tooltip;"
+ oncommand="document.getBindingParent(this).close();"/>
+ </xul:hbox>
+ <xul:description anonid="messageText" class="messageText" flex="1" xbl:inherits="xbl:text=label"/>
+ </xul:vbox>
+ </content>
+ </binding>
+
+ <binding id="sidebar-addon-progress-notification"
+ extends="chrome://communicator/content/bindings/notification.xml#addon-progress-notification">
+ <content>
+ <xul:vbox class="notification-inner outset" flex="1" xbl:inherits="type">
+ <xul:hbox align="center">
+ <xul:image anonid="messageImage" class="messageImage" xbl:inherits="src=image,type,value"/>
+ <xul:arrowscrollbox orient="horizontal" flex="1" pack="end"
+ oncommand="document.getBindingParent(this)._doButtonCommand(event);">
+ <children/>
+ </xul:arrowscrollbox>
+ <xul:toolbarbutton ondblclick="event.stopPropagation();"
+ class="messageCloseButton tabbable"
+ xbl:inherits="hidden=hideclose"
+ tooltiptext="&closeNotification.tooltip;"
+ oncommand="document.getBindingParent(this).close();"/>
+ </xul:hbox>
+ <xul:description anonid="messageText" class="messageText" flex="1" xbl:inherits="xbl:text=label"/>
+ <xul:progressmeter mode="undetermined" xbl:inherits="mode,value=progress"/>
+ <xul:label xbl:inherits="value=status"/>
+ </xul:vbox>
+ </content>
+ </binding>
+
+ <binding id="addon-progress-popup-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
+ <content align="start">
+ <xul:image class="popup-notification-icon" xbl:inherits="popupid"/>
+ <xul:vbox flex="1">
+ <xul:description class="popup-notification-description addon-progress-description"
+ xbl:inherits="xbl:text=label"/>
+ <xul:hbox class="popup-notification-button-container" align="center">
+ <xul:progressmeter mode="undetermined"
+ xbl:inherits="mode,value=progress"/>
+ <xul:spacer flex="1"/>
+ <xul:button anonid="button"
+ class="popup-notification-menubutton"
+ type="menu-button"
+ xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
+ <xul:menupopup anonid="menupopup"
+ xbl:inherits="oncommand=menucommand">
+ <children/>
+ <xul:menuitem class="menuitem-iconic popup-notification-closeitem"
+ label="&closeNotificationItem.label;"
+ xbl:inherits="oncommand=closeitemcommand"/>
+ </xul:menupopup>
+ </xul:button>
+ </xul:hbox>
+ <xul:label xbl:inherits="xbl:text=status"/>
+ </xul:vbox>
+ <xul:vbox pack="start">
+ <xul:toolbarbutton anonid="closebutton"
+ class="messageCloseButton close-icon popup-notification-closebutton tabbable"
+ xbl:inherits="oncommand=closebuttoncommand"
+ tooltiptext="&closeNotification.tooltip;"/>
+ </xul:vbox>
+ </content>
+
+ <implementation>
+ <constructor>
+ <![CDATA[
+ this.installInfo = this.notification.options.installInfo;
+ this.installInfo.installs.forEach(function(aInstall) {
+ aInstall.addListener(this);
+ }, this);
+ ]]>
+ </constructor>
+
+ <destructor>
+ <![CDATA[
+ this.installInfo.installs.forEach(function(aInstall) {
+ aInstall.removeListener(this);
+ }, this);
+ ]]>
+ </destructor>
+
+ <method name="updateProgress">
+ <body>
+ <![CDATA[
+ var count = 0;
+ var progress = 0;
+ var max = 0;
+
+ var tmp = {};
+ ChromeUtils.import("resource://gre/modules/AddonManager.jsm", tmp);
+ this.installInfo.installs.forEach(function(aInstall) {
+ if (aInstall.maxProgress < 0)
+ max = -1;
+ else if (max >= 0)
+ max += aInstall.maxProgress;
+ progress += aInstall.progress;
+ if (aInstall.state < tmp.AddonManager.STATE_DOWNLOADED)
+ count++;
+ });
+
+ if (max < 0)
+ this.setAttribute("mode", "undetermined");
+ else {
+ this.setAttribute("mode", "determined");
+ this.setAttribute("progress", progress * 100 / max);
+ }
+
+ var now = Date.now();
+ if (!this.startTime) {
+ this.startTime = now;
+ this.lastUpdate = now - 750;
+ this.lastSeconds = null;
+ }
+
+ if (progress == max || now - this.lastUpdate >= 750) {
+ this.lastUpdate = now;
+ var elapsed = (now - this.startTime) / 1000;
+ var rate = elapsed && progress / elapsed;
+ ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm", tmp);
+ var status;
+ [status, this.lastSeconds] = tmp.DownloadUtils.getDownloadStatus(progress, max, rate, this.lastSeconds);
+ this.setAttribute("status", status);
+ }
+
+ if (!count)
+ PopupNotifications.remove(this.notification);
+ ]]>
+ </body>
+ </method>
+
+ <method name="onDownloadProgress">
+ <body>
+ <![CDATA[
+ this.updateProgress();
+ ]]>
+ </body>
+ </method>
+
+ <method name="onDownloadFailed">
+ <body>
+ <![CDATA[
+ this.updateProgress();
+ ]]>
+ </body>
+ </method>
+
+ <method name="onDownloadCancelled">
+ <body>
+ <![CDATA[
+ this.updateProgress();
+ ]]>
+ </body>
+ </method>
+
+ <method name="onDownloadEnded">
+ <body>
+ <![CDATA[
+ this.updateProgress();
+ ]]>
+ </body>
+ </method>
+ </implementation>
+ </binding>
+
+ <binding id="center-item">
+ <content>
+ <xul:vbox flex="1" class="center-item-box"
+ xbl:inherits="warn,showseparator,padbottom">
+ <xul:hbox align="center">
+ <xul:image class="center-item-icon"
+ xbl:inherits="src=itemicon"/>
+ <xul:description class="center-item-label"
+ xbl:inherits="xbl:text=itemtext"/>
+ <xul:spacer flex="1"/>
+ <xul:button class="popup-notification-menubutton center-item-button"
+ oncommand="document.getBindingParent(this).runCallback();"
+ xbl:inherits="label=buttonlabel"/>
+ </xul:hbox>
+ <xul:hbox align="center" class="center-item-warning">
+ <xul:image class="center-item-warning-icon"/>
+ <xul:label class="center-item-warning-description" xbl:inherits="xbl:text=warningText"/>
+ <xul:label xbl:inherits="href=updateLink" value="&checkForUpdates;" class="text-link"/>
+ </xul:hbox>
+ </xul:vbox>
+ </content>
+ <resources>
+ <stylesheet src="chrome://global/skin/notification.css"/>
+ </resources>
+ <implementation>
+ <field name="action"></field>
+ <method name="runCallback">
+ <body><![CDATA[
+ let action = this.action;
+ action.callback();
+ let cas = action.popupnotification.notification.options.centerActions;
+ cas.splice(cas.indexOf(action), 1);
+ PopupNotifications._dismiss();
+ ]]></body>
+ </method>
+ </implementation>
+ </binding>
+
+</bindings>