suite/components/bindings/notification.xml (2,188 lines of code) (raw):

<?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"> <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) { window.openDialog(AppConstants.BROWSER_CHROME_URL, "_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 {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: ChromeUtils.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>