diff options
Diffstat (limited to 'application/palemoon/modules')
19 files changed, 0 insertions, 5033 deletions
diff --git a/application/palemoon/modules/AboutHomeUtils.jsm b/application/palemoon/modules/AboutHomeUtils.jsm deleted file mode 100644 index 72712e1f3..000000000 --- a/application/palemoon/modules/AboutHomeUtils.jsm +++ /dev/null @@ -1,67 +0,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/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = [ "AboutHomeUtils" ]; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); - -this.AboutHomeUtils = { - /** - * Returns an object containing the name and searchURL of the original default - * search engine. - */ - get defaultSearchEngine() { - let defaultEngine = Services.search.defaultEngine; - let submission = defaultEngine.getSubmission("_searchTerms_", null, "homepage"); - - return Object.freeze({ - name: defaultEngine.name, - searchURL: submission.uri.spec, - postDataString: submission.postDataString - }); - }, - - /* - * showKnowYourRights - Determines if the user should be shown the - * about:rights notification. The notification should *not* be shown if - * we've already shown the current version, or if the override pref says to - * never show it. The notification *should* be shown if it's never been seen - * before, if a newer version is available, or if the override pref says to - * always show it. - */ - get showKnowYourRights() { - // Look for an unconditional override pref. If set, do what it says. - // (true --> never show, false --> always show) - try { - return !Services.prefs.getBoolPref("browser.rights.override"); - } catch (e) { } - // Ditto, for the legacy EULA pref. - try { - return !Services.prefs.getBoolPref("browser.EULA.override"); - } catch (e) { } - -#ifndef MC_OFFICIAL - // Non-official builds shouldn't show the notification. - return false; -#endif - - // Look to see if the user has seen the current version or not. - var currentVersion = Services.prefs.getIntPref("browser.rights.version"); - try { - return !Services.prefs.getBoolPref("browser.rights." + currentVersion + ".shown"); - } catch (e) { } - - // Legacy: If the user accepted a EULA, we won't annoy them with the - // equivalent about:rights page until the version changes. - try { - return !Services.prefs.getBoolPref("browser.EULA." + currentVersion + ".accepted"); - } catch (e) { } - - // We haven't shown the notification before, so do so now. - return true; - } -}; diff --git a/application/palemoon/modules/AutoCompletePopup.jsm b/application/palemoon/modules/AutoCompletePopup.jsm deleted file mode 100644 index c3698f905..000000000 --- a/application/palemoon/modules/AutoCompletePopup.jsm +++ /dev/null @@ -1,293 +0,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/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -this.EXPORTED_SYMBOLS = [ "AutoCompletePopup" ]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -// nsITreeView implementation that feeds the autocomplete popup -// with the search data. -var AutoCompleteTreeView = { - // nsISupports - QueryInterface: XPCOMUtils.generateQI([Ci.nsITreeView, - Ci.nsIAutoCompleteController]), - - // Private variables - treeBox: null, - results: [], - - // nsITreeView - selection: null, - - get rowCount() { return this.results.length; }, - setTree: function(treeBox) { this.treeBox = treeBox; }, - getCellText: function(idx, column) { return this.results[idx].value }, - isContainer: function(idx) { return false; }, - getCellValue: function(idx, column) { return false }, - isContainerOpen: function(idx) { return false; }, - isContainerEmpty: function(idx) { return false; }, - isSeparator: function(idx) { return false; }, - isSorted: function() { return false; }, - isEditable: function(idx, column) { return false; }, - canDrop: function(idx, orientation, dt) { return false; }, - getLevel: function(idx) { return 0; }, - getParentIndex: function(idx) { return -1; }, - hasNextSibling: function(idx, after) { return idx < this.results.length - 1 }, - toggleOpenState: function(idx) { }, - getCellProperties: function(idx, column) { return this.results[idx].style || ""; }, - getRowProperties: function(idx) { return ""; }, - getImageSrc: function(idx, column) { return null; }, - getProgressMode : function(idx, column) { }, - cycleHeader: function(column) { }, - cycleCell: function(idx, column) { }, - selectionChanged: function() { }, - performAction: function(action) { }, - performActionOnCell: function(action, index, column) { }, - getColumnProperties: function(column) { return ""; }, - - // nsIAutoCompleteController - get matchCount() { - return this.rowCount; - }, - - handleEnter: function(aIsPopupSelection) { - AutoCompletePopup.handleEnter(aIsPopupSelection); - }, - - stopSearch: function() {}, - - // Internal JS-only API - clearResults: function() { - this.results = []; - }, - - setResults: function(results) { - this.results = results; - }, -}; - -this.AutoCompletePopup = { - MESSAGES: [ - "FormAutoComplete:SelectBy", - "FormAutoComplete:GetSelectedIndex", - "FormAutoComplete:SetSelectedIndex", - "FormAutoComplete:MaybeOpenPopup", - "FormAutoComplete:ClosePopup", - "FormAutoComplete:Disconnect", - "FormAutoComplete:RemoveEntry", - "FormAutoComplete:Invalidate", - ], - - init: function() { - for (let msg of this.MESSAGES) { - Services.mm.addMessageListener(msg, this); - } - }, - - uninit: function() { - for (let msg of this.MESSAGES) { - Services.mm.removeMessageListener(msg, this); - } - }, - - handleEvent: function(evt) { - switch (evt.type) { - case "popupshowing": { - this.sendMessageToBrowser("FormAutoComplete:PopupOpened"); - break; - } - - case "popuphidden": { - this.sendMessageToBrowser("FormAutoComplete:PopupClosed"); - this.openedPopup = null; - this.weakBrowser = null; - evt.target.removeEventListener("popuphidden", this); - evt.target.removeEventListener("popupshowing", this); - break; - } - } - }, - - // Along with being called internally by the receiveMessage handler, - // this function is also called directly by the login manager, which - // uses a single message to fill in the autocomplete results. See - // "RemoteLogins:autoCompleteLogins". - showPopupWithResults: function({ browser, rect, dir, results }) { - if (!results.length || this.openedPopup) { - // We shouldn't ever be showing an empty popup, and if we - // already have a popup open, the old one needs to close before - // we consider opening a new one. - return; - } - - let window = browser.ownerDocument.defaultView; - let tabbrowser = window.gBrowser; - if (Services.focus.activeWindow != window || - tabbrowser.selectedBrowser != browser) { - // We were sent a message from a window or tab that went into the - // background, so we'll ignore it for now. - return; - } - - this.weakBrowser = Cu.getWeakReference(browser); - this.openedPopup = browser.autoCompletePopup; - this.openedPopup.hidden = false; - // don't allow the popup to become overly narrow - this.openedPopup.setAttribute("width", Math.max(100, rect.width)); - this.openedPopup.style.direction = dir; - - AutoCompleteTreeView.setResults(results); - this.openedPopup.view = AutoCompleteTreeView; - this.openedPopup.selectedIndex = -1; - this.openedPopup.invalidate(); - - if (results.length) { - // Reset fields that were set from the last time the search popup was open - this.openedPopup.mInput = null; - this.openedPopup.showCommentColumn = false; - this.openedPopup.showImageColumn = false; - this.openedPopup.addEventListener("popuphidden", this); - this.openedPopup.addEventListener("popupshowing", this); - this.openedPopup.openPopupAtScreenRect("after_start", rect.left, rect.top, - rect.width, rect.height, false, - false); - } else { - this.closePopup(); - } - }, - - invalidate(results) { - if (!this.openedPopup) { - return; - } - - if (!results.length) { - this.closePopup(); - } else { - AutoCompleteTreeView.setResults(results); - // We need to re-set the view in order for the - // tree to know the view has changed. - this.openedPopup.view = AutoCompleteTreeView; - this.openedPopup.invalidate(); - } - }, - - closePopup() { - if (this.openedPopup) { - // Note that hidePopup() closes the popup immediately, - // so popuphiding or popuphidden events will be fired - // and handled during this call. - this.openedPopup.hidePopup(); - } - AutoCompleteTreeView.clearResults(); - }, - - removeLogin(login) { - Services.logins.removeLogin(login); - }, - - receiveMessage: function(message) { - if (!message.target.autoCompletePopup) { - // Returning false to pacify ESLint, but this return value is - // ignored by the messaging infrastructure. - return false; - } - - switch (message.name) { - case "FormAutoComplete:SelectBy": { - this.openedPopup.selectBy(message.data.reverse, message.data.page); - break; - } - - case "FormAutoComplete:GetSelectedIndex": { - if (this.openedPopup) { - return this.openedPopup.selectedIndex; - } - // If the popup was closed, then the selection - // has not changed. - return -1; - } - - case "FormAutoComplete:SetSelectedIndex": { - let { index } = message.data; - if (this.openedPopup) { - this.openedPopup.selectedIndex = index; - } - break; - } - - case "FormAutoComplete:MaybeOpenPopup": { - let { results, rect, dir } = message.data; - this.showPopupWithResults({ browser: message.target, rect, dir, - results }); - break; - } - - case "FormAutoComplete:Invalidate": { - let { results } = message.data; - this.invalidate(results); - break; - } - - case "FormAutoComplete:ClosePopup": { - this.closePopup(); - break; - } - - case "FormAutoComplete:Disconnect": { - // The controller stopped controlling the current input, so clear - // any cached data. This is necessary cause otherwise we'd clear data - // only when starting a new search, but the next input could not support - // autocomplete and it would end up inheriting the existing data. - AutoCompleteTreeView.clearResults(); - break; - } - } - // Returning false to pacify ESLint, but this return value is - // ignored by the messaging infrastructure. - return false; - }, - - /** - * Despite its name, this handleEnter is only called when the user clicks on - * one of the items in the popup since the popup is rendered in the parent process. - * The real controller's handleEnter is called directly in the content process - * for other methods of completing a selection (e.g. using the tab or enter - * keys) since the field with focus is in that process. - */ - handleEnter(aIsPopupSelection) { - if (this.openedPopup) { - this.sendMessageToBrowser("FormAutoComplete:HandleEnter", { - selectedIndex: this.openedPopup.selectedIndex, - isPopupSelection: aIsPopupSelection, - }); - } - }, - - /** - * If a browser exists that AutoCompletePopup knows about, - * sends it a message. Otherwise, this is a no-op. - * - * @param {string} msgName - * The name of the message to send. - * @param {object} data - * The optional data to send with the message. - */ - sendMessageToBrowser(msgName, data) { - let browser = this.weakBrowser ? this.weakBrowser.get() - : null; - if (browser) { - browser.messageManager.sendAsyncMessage(msgName, data); - } - }, - - stopSearch: function() {} -} diff --git a/application/palemoon/modules/BrowserNewTabPreloader.jsm b/application/palemoon/modules/BrowserNewTabPreloader.jsm deleted file mode 100644 index 778698fba..000000000 --- a/application/palemoon/modules/BrowserNewTabPreloader.jsm +++ /dev/null @@ -1,436 +0,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/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["BrowserNewTabPreloader"]; - -const Cu = Components.utils; -const Cc = Components.classes; -const Ci = Components.interfaces; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); - -const HTML_NS = "http://www.w3.org/1999/xhtml"; -const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; -const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='win'/>"; -const NEWTAB_URL = "about:newtab"; -const PREF_BRANCH = "browser.newtab."; - -// The interval between swapping in a preload docShell and kicking off the -// next preload in the background. -const PRELOADER_INTERVAL_MS = 600; -// The initial delay before we start preloading our first new tab page. The -// timer is started after the first 'browser-delayed-startup' has been sent. -const PRELOADER_INIT_DELAY_MS = 5000; -// The number of miliseconds we'll wait after we received a notification that -// causes us to update our list of browsers and tabbrowser sizes. This acts as -// kind of a damper when too many events are occuring in quick succession. -const PRELOADER_UPDATE_DELAY_MS = 3000; - -const TOPIC_TIMER_CALLBACK = "timer-callback"; -const TOPIC_DELAYED_STARTUP = "browser-delayed-startup-finished"; -const TOPIC_XUL_WINDOW_CLOSED = "xul-window-destroyed"; - -function createTimer(obj, delay) { - let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - timer.init(obj, delay, Ci.nsITimer.TYPE_ONE_SHOT); - return timer; -} - -function clearTimer(timer) { - if (timer) { - timer.cancel(); - } - return null; -} - -this.BrowserNewTabPreloader = { - init: function Preloader_init() { - Initializer.start(); - }, - - uninit: function Preloader_uninit() { - Initializer.stop(); - HostFrame.destroy(); - Preferences.uninit(); - HiddenBrowsers.uninit(); - }, - - newTab: function Preloader_newTab(aTab) { - let win = aTab.ownerDocument.defaultView; - if (win.gBrowser) { - let utils = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - - let {width, height} = utils.getBoundsWithoutFlushing(win.gBrowser); - let hiddenBrowser = HiddenBrowsers.get(width, height) - if (hiddenBrowser) { - return hiddenBrowser.swapWithNewTab(aTab); - } - } - - return false; - } -}; - -Object.freeze(BrowserNewTabPreloader); - -var Initializer = { - _timer: null, - _observing: false, - - start: function Initializer_start() { - Services.obs.addObserver(this, TOPIC_DELAYED_STARTUP, false); - this._observing = true; - }, - - stop: function Initializer_stop() { - this._timer = clearTimer(this._timer); - - if (this._observing) { - Services.obs.removeObserver(this, TOPIC_DELAYED_STARTUP); - this._observing = false; - } - }, - - observe: function Initializer_observe(aSubject, aTopic, aData) { - if (aTopic == TOPIC_DELAYED_STARTUP) { - Services.obs.removeObserver(this, TOPIC_DELAYED_STARTUP); - this._observing = false; - this._startTimer(); - } else if (aTopic == TOPIC_TIMER_CALLBACK) { - this._timer = null; - this._startPreloader(); - } - }, - - _startTimer: function Initializer_startTimer() { - this._timer = createTimer(this, PRELOADER_INIT_DELAY_MS); - }, - - _startPreloader: function Initializer_startPreloader() { - Preferences.init(); - if (Preferences.enabled) { - HiddenBrowsers.init(); - } - } -}; - -var Preferences = { - _enabled: null, - _branch: null, - - get enabled() { - if (this._enabled === null) { - this._enabled = this._branch.getBoolPref("preload") && - !this._branch.prefHasUserValue("url"); - } - - return this._enabled; - }, - - init: function Preferences_init() { - this._branch = Services.prefs.getBranch(PREF_BRANCH); - this._branch.addObserver("", this, false); - }, - - uninit: function Preferences_uninit() { - if (this._branch) { - this._branch.removeObserver("", this); - this._branch = null; - } - }, - - observe: function Preferences_observe() { - let prevEnabled = this._enabled; - this._enabled = null; - - if (prevEnabled && !this.enabled) { - HiddenBrowsers.uninit(); - } else if (!prevEnabled && this.enabled) { - HiddenBrowsers.init(); - } - }, -}; - -var HiddenBrowsers = { - _browsers: null, - _updateTimer: null, - - _topics: [ - TOPIC_DELAYED_STARTUP, - TOPIC_XUL_WINDOW_CLOSED - ], - - init: function () { - this._browsers = new Map(); - this._updateBrowserSizes(); - this._topics.forEach(t => Services.obs.addObserver(this, t, false)); - }, - - uninit: function () { - if (this._browsers) { - this._topics.forEach(t => Services.obs.removeObserver(this, t, false)); - this._updateTimer = clearTimer(this._updateTimer); - - for (let [key, browser] of this._browsers) { - browser.destroy(); - } - this._browsers = null; - } - }, - - get: function (width, height) { - // We haven't been initialized, yet. - if (!this._browsers) { - return null; - } - - let key = width + "x" + height; - if (!this._browsers.has(key)) { - // Update all browsers' sizes if we can't find a matching one. - this._updateBrowserSizes(); - } - - // We should now have a matching browser. - if (this._browsers.has(key)) { - return this._browsers.get(key); - } - - // We should never be here. Return the first browser we find. - Cu.reportError("NewTabPreloader: no matching browser found after updating"); - for (let [size, browser] of this._browsers) { - return browser; - } - - // We should really never be here. - Cu.reportError("NewTabPreloader: not even a single browser was found?"); - return null; - }, - - observe: function (subject, topic, data) { - if (topic === TOPIC_TIMER_CALLBACK) { - this._updateTimer = null; - this._updateBrowserSizes(); - } else { - this._updateTimer = clearTimer(this._updateTimer); - this._updateTimer = createTimer(this, PRELOADER_UPDATE_DELAY_MS); - } - }, - - _updateBrowserSizes: function () { - let sizes = this._collectTabBrowserSizes(); - let toRemove = []; - - // Iterate all browsers and check that they - // each can be assigned to one of the sizes. - for (let [key, browser] of this._browsers) { - if (sizes.has(key)) { - // We already have a browser for that size, great! - sizes.delete(key); - } else { - // This browser is superfluous or needs to be resized. - toRemove.push(browser); - this._browsers.delete(key); - } - } - - // Iterate all sizes that we couldn't find a browser for. - for (let [key, {width, height}] of sizes) { - let browser; - if (toRemove.length) { - // Let's just resize one of the superfluous - // browsers and put it back into the map. - browser = toRemove.shift(); - browser.resize(width, height); - } else { - // No more browsers to reuse, create a new one. - browser = new HiddenBrowser(width, height); - } - - this._browsers.set(key, browser); - } - - // Finally, remove all browsers we don't need anymore. - toRemove.forEach(b => b.destroy()); - }, - - _collectTabBrowserSizes: function () { - let sizes = new Map(); - - function tabBrowserBounds() { - let wins = Services.ww.getWindowEnumerator("navigator:browser"); - while (wins.hasMoreElements()) { - let win = wins.getNext(); - if (win.gBrowser) { - let utils = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - yield utils.getBoundsWithoutFlushing(win.gBrowser); - } - } - } - - // Collect the sizes of all <tabbrowser>s out there. - for (let {width, height} of tabBrowserBounds()) { - if (width > 0 && height > 0) { - let key = width + "x" + height; - if (!sizes.has(key)) { - sizes.set(key, {width: width, height: height}); - } - } - } - - return sizes; - } -}; - -function HiddenBrowser(width, height) { - this.resize(width, height); - - HostFrame.get().then(aFrame => { - let doc = aFrame.document; - this._browser = doc.createElementNS(XUL_NS, "browser"); - this._browser.setAttribute("type", "content"); - this._browser.setAttribute("src", NEWTAB_URL); - this._applySize(); - doc.getElementById("win").appendChild(this._browser); - }); -} - -HiddenBrowser.prototype = { - _width: null, - _height: null, - _timer: null, - _needsFrameScripts: true, - - get isPreloaded() { - return this._browser && - this._browser.contentDocument && - this._browser.contentDocument.readyState === "complete" && - this._browser.currentURI.spec === NEWTAB_URL; - }, - - swapWithNewTab: function (aTab) { - if (!this.isPreloaded || this._timer) { - return false; - } - - let win = aTab.ownerDocument.defaultView; - let tabbrowser = win.gBrowser; - - if (!tabbrowser) { - return false; - } - - // Swap docShells. - tabbrowser.swapNewTabWithBrowser(aTab, this._browser); - - // Load all default frame scripts. - if (this._needsFrameScripts) { - this._needsFrameScripts = false; - - let mm = aTab.linkedBrowser.messageManager; - mm.loadFrameScript("chrome://browser/content/content.js", true); - mm.loadFrameScript("chrome://browser/content/content-sessionStore.js", true); - - if ("TabView" in win) { - mm.loadFrameScript("chrome://browser/content/tabview-content.js", true); - } - } - - // Start a timer that will kick off preloading the next newtab page. - this._timer = createTimer(this, PRELOADER_INTERVAL_MS); - - // Signal that we swapped docShells. - return true; - }, - - observe: function () { - this._timer = null; - - // Start pre-loading the new tab page. - this._browser.loadURI(NEWTAB_URL); - }, - - resize: function (width, height) { - this._width = width; - this._height = height; - this._applySize(); - }, - - _applySize: function () { - if (this._browser) { - this._browser.style.width = this._width + "px"; - this._browser.style.height = this._height + "px"; - } - }, - - destroy: function () { - if (this._browser) { - this._browser.remove(); - this._browser = null; - } - - this._timer = clearTimer(this._timer); - } -}; - -var HostFrame = { - _frame: null, - _deferred: null, - - get hiddenDOMDocument() { - return Services.appShell.hiddenDOMWindow.document; - }, - - get isReady() { - return this.hiddenDOMDocument.readyState === "complete"; - }, - - get: function () { - if (!this._deferred) { - this._deferred = Promise.defer(); - this._create(); - } - - return this._deferred.promise; - }, - - destroy: function () { - if (this._frame) { - if (!Cu.isDeadWrapper(this._frame)) { - this._frame.removeEventListener("load", this, true); - this._frame.remove(); - } - - this._frame = null; - this._deferred = null; - } - }, - - handleEvent: function () { - let contentWindow = this._frame.contentWindow; - if (contentWindow.location.href === XUL_PAGE) { - this._frame.removeEventListener("load", this, true); - this._deferred.resolve(contentWindow); - } else { - contentWindow.location = XUL_PAGE; - } - }, - - _create: function () { - if (this.isReady) { - let doc = this.hiddenDOMDocument; - this._frame = doc.createElementNS(HTML_NS, "iframe"); - this._frame.addEventListener("load", this, true); - doc.documentElement.appendChild(this._frame); - } else { - let flags = Ci.nsIThread.DISPATCH_NORMAL; - Services.tm.currentThread.dispatch(() => this._create(), flags); - } - } -}; diff --git a/application/palemoon/modules/CharsetMenu.jsm b/application/palemoon/modules/CharsetMenu.jsm deleted file mode 100644 index f973088bc..000000000 --- a/application/palemoon/modules/CharsetMenu.jsm +++ /dev/null @@ -1,160 +0,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/. */ - -this.EXPORTED_SYMBOLS = [ "CharsetMenu" ]; - -const { classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyGetter(this, "gBundle", function() { - const kUrl = "chrome://browser/locale/charsetMenu.properties"; - return Services.strings.createBundle(kUrl); -}); -/** - * This set contains encodings that are in the Encoding Standard, except: - * - XSS-dangerous encodings (except ISO-2022-JP which is assumed to be - * too common not to be included). - * - x-user-defined, which practically never makes sense as an end-user-chosen - * override. - * - Encodings that IE11 doesn't have in its correspoding menu. - */ -const kEncodings = new Set([ - // Globally relevant - "UTF-8", - "windows-1252", - // Arabic - "windows-1256", - "ISO-8859-6", - // Baltic - "windows-1257", - "ISO-8859-4", - // "ISO-8859-13", // Hidden since not in menu in IE11 - // Central European - "windows-1250", - "ISO-8859-2", - // Chinese, Simplified - "gbk", - "gb18030", - // Chinese, Traditional - "Big5", - // Cyrillic - "windows-1251", - "ISO-8859-5", - "KOI8-R", - "KOI8-U", - "IBM866", // Not in menu in Chromium. Maybe drop this? - // "x-mac-cyrillic", // Not in menu in IE11 or Chromium. - // Greek - "windows-1253", - "ISO-8859-7", - // Hebrew - "windows-1255", - "ISO-8859-8-I", - "ISO-8859-8", - // Japanese - "Shift_JIS", - "EUC-JP", - "ISO-2022-JP", - // Korean - "EUC-KR", - // Thai - "windows-874", - // Turkish - "windows-1254", - // Vietnamese - "windows-1258", - // Hiding rare European encodings that aren't in the menu in IE11 and would - // make the menu messy by sorting all over the place - // "ISO-8859-3", - // "ISO-8859-10", - // "ISO-8859-14", - // "ISO-8859-15", - // "ISO-8859-16", - // "macintosh" -]); - -// Always at the start of the menu, in this order, followed by a separator. -const kPinned = [ - "UTF-8", - "windows-1252" -]; - -this.CharsetMenu = Object.freeze({ - build: function BuildCharsetMenu(event) { - let parent = event.target; - if (parent.lastChild.localName != "menuseparator") { - // Detector menu or charset menu already built - return; - } - let doc = parent.ownerDocument; - - function createItem(encoding) { - let menuItem = doc.createElement("menuitem"); - menuItem.setAttribute("type", "radio"); - menuItem.setAttribute("name", "charsetGroup"); - try { - menuItem.setAttribute("label", gBundle.GetStringFromName(encoding)); - } catch (e) { - // Localization error but put *something* in the menu to recover. - menuItem.setAttribute("label", encoding); - } - try { - menuItem.setAttribute("accesskey", - gBundle.GetStringFromName(encoding + ".key")); - } catch (e) { - // Some items intentionally don't have an accesskey - } - menuItem.setAttribute("id", "charset." + encoding); - return menuItem; - } - - // Clone the set in order to be able to remove the pinned encodings from - // the cloned set. - let encodings = new Set(kEncodings); - for (let encoding of kPinned) { - encodings.delete(encoding); - parent.appendChild(createItem(encoding)); - } - parent.appendChild(doc.createElement("menuseparator")); - let list = []; - for (let encoding of encodings) { - list.push(createItem(encoding)); - } - - list.sort(function (a, b) { - let titleA = a.getAttribute("label"); - let titleB = b.getAttribute("label"); - // Normal sorting sorts the part in parenthesis in an order that - // happens to make the less frequently-used items first. - let index; - if ((index = titleA.indexOf("(")) > -1) { - titleA = titleA.substring(0, index); - } - if ((index = titleB.indexOf("(")) > -1) { - titleA = titleB.substring(0, index); - } - let comp = titleA.localeCompare(titleB); - if (comp) { - return comp; - } - // secondarily reverse sort by encoding name to sort "windows" or - // "shift_jis" first. This works regardless of localization, because - // the ids aren't localized. - let idA = a.getAttribute("id"); - let idB = b.getAttribute("id"); - if (idA < idB) { - return 1; - } - if (idB < idA) { - return -1; - } - return 0; - }); - - for (let item of list) { - parent.appendChild(item); - } - }, -});
\ No newline at end of file diff --git a/application/palemoon/modules/FormSubmitObserver.jsm b/application/palemoon/modules/FormSubmitObserver.jsm deleted file mode 100644 index 6b2ea3c84..000000000 --- a/application/palemoon/modules/FormSubmitObserver.jsm +++ /dev/null @@ -1,235 +0,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/. */ - -/* - * Handles the validation callback from nsIFormFillController and - * the display of the help panel on invalid elements. - */ - -"use strict"; - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; - -var HTMLInputElement = Ci.nsIDOMHTMLInputElement; -var HTMLTextAreaElement = Ci.nsIDOMHTMLTextAreaElement; -var HTMLSelectElement = Ci.nsIDOMHTMLSelectElement; -var HTMLButtonElement = Ci.nsIDOMHTMLButtonElement; - -this.EXPORTED_SYMBOLS = [ "FormSubmitObserver" ]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/BrowserUtils.jsm"); - -function FormSubmitObserver(aWindow, aTabChildGlobal) { - this.init(aWindow, aTabChildGlobal); -} - -FormSubmitObserver.prototype = -{ - _validationMessage: "", - _content: null, - _element: null, - - /* - * Public apis - */ - - init: function(aWindow, aTabChildGlobal) - { - this._content = aWindow; - this._tab = aTabChildGlobal; - this._mm = - this._content.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDocShell) - .sameTypeRootTreeItem - .QueryInterface(Ci.nsIDocShell) - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIContentFrameMessageManager); - - // nsIFormSubmitObserver callback about invalid forms. See HTMLFormElement - // for details. - Services.obs.addObserver(this, "invalidformsubmit", false); - this._tab.addEventListener("pageshow", this, false); - this._tab.addEventListener("unload", this, false); - }, - - uninit: function() - { - Services.obs.removeObserver(this, "invalidformsubmit"); - this._content.removeEventListener("pageshow", this, false); - this._content.removeEventListener("unload", this, false); - this._mm = null; - this._element = null; - this._content = null; - this._tab = null; - }, - - /* - * Events - */ - - handleEvent: function (aEvent) { - switch (aEvent.type) { - case "pageshow": - if (this._isRootDocumentEvent(aEvent)) { - this._hidePopup(); - } - break; - case "unload": - this.uninit(); - break; - case "input": - this._onInput(aEvent); - break; - case "blur": - this._onBlur(aEvent); - break; - } - }, - - /* - * nsIFormSubmitObserver - */ - - notifyInvalidSubmit : function (aFormElement, aInvalidElements) - { - // We are going to handle invalid form submission attempt by focusing the - // first invalid element and show the corresponding validation message in a - // panel attached to the element. - if (!aInvalidElements.length) { - return; - } - - // Ensure that this is the FormSubmitObserver associated with the - // element / window this notification is about. - let element = aInvalidElements.queryElementAt(0, Ci.nsISupports); - if (this._content != element.ownerGlobal.top.document.defaultView) { - return; - } - - if (!(element instanceof HTMLInputElement || - element instanceof HTMLTextAreaElement || - element instanceof HTMLSelectElement || - element instanceof HTMLButtonElement)) { - return; - } - - // Update validation message before showing notification - this._validationMessage = element.validationMessage; - - // Don't connect up to the same element more than once. - if (this._element == element) { - this._showPopup(element); - return; - } - this._element = element; - - element.focus(); - - // Watch for input changes which may change the validation message. - element.addEventListener("input", this, false); - - // Watch for focus changes so we can disconnect our listeners and - // hide the popup. - element.addEventListener("blur", this, false); - - this._showPopup(element); - }, - - /* - * Internal - */ - - /* - * Handles input changes on the form element we've associated a popup - * with. Updates the validation message or closes the popup if form data - * becomes valid. - */ - _onInput: function (aEvent) { - let element = aEvent.originalTarget; - - // If the form input is now valid, hide the popup. - if (element.validity.valid) { - this._hidePopup(); - return; - } - - // If the element is still invalid for a new reason, we should update - // the popup error message. - if (this._validationMessage != element.validationMessage) { - this._validationMessage = element.validationMessage; - this._showPopup(element); - } - }, - - /* - * Blur event handler in which we disconnect from the form element and - * hide the popup. - */ - _onBlur: function (aEvent) { - aEvent.originalTarget.removeEventListener("input", this, false); - aEvent.originalTarget.removeEventListener("blur", this, false); - this._element = null; - this._hidePopup(); - }, - - /* - * Send the show popup message to chrome with appropriate position - * information. Can be called repetitively to update the currently - * displayed popup position and text. - */ - _showPopup: function (aElement) { - // Collect positional information and show the popup - let panelData = {}; - - panelData.message = this._validationMessage; - - // Note, this is relative to the browser and needs to be translated - // in chrome. - panelData.contentRect = BrowserUtils.getElementBoundingRect(aElement); - - // We want to show the popup at the middle of checkbox and radio buttons - // and where the content begin for the other elements. - let offset = 0; - - if (aElement.tagName == 'INPUT' && - (aElement.type == 'radio' || aElement.type == 'checkbox')) { - panelData.position = "bottomcenter topleft"; - } else { - let win = aElement.ownerGlobal; - let style = win.getComputedStyle(aElement, null); - if (style.direction == 'rtl') { - offset = parseInt(style.paddingRight) + parseInt(style.borderRightWidth); - } else { - offset = parseInt(style.paddingLeft) + parseInt(style.borderLeftWidth); - } - let zoomFactor = this._getWindowUtils().fullZoom; - panelData.offset = Math.round(offset * zoomFactor); - panelData.position = "after_start"; - } - this._mm.sendAsyncMessage("FormValidation:ShowPopup", panelData); - }, - - _hidePopup: function () { - this._mm.sendAsyncMessage("FormValidation:HidePopup", {}); - }, - - _getWindowUtils: function () { - return this._content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); - }, - - _isRootDocumentEvent: function (aEvent) { - if (this._content == null) { - return true; - } - let target = aEvent.originalTarget; - return (target == this._content.document || - (target.ownerDocument && target.ownerDocument == this._content.document)); - }, - - QueryInterface : XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]) -}; diff --git a/application/palemoon/modules/FormValidationHandler.jsm b/application/palemoon/modules/FormValidationHandler.jsm deleted file mode 100644 index 387c221d7..000000000 --- a/application/palemoon/modules/FormValidationHandler.jsm +++ /dev/null @@ -1,157 +0,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/. */ - -/* - * Chrome side handling of form validation popup. - */ - -"use strict"; - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; - -this.EXPORTED_SYMBOLS = [ "FormValidationHandler" ]; - -Cu.import("resource://gre/modules/Services.jsm"); - -var FormValidationHandler = -{ - _panel: null, - _anchor: null, - - /* - * Public apis - */ - - init: function () { - let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); - mm.addMessageListener("FormValidation:ShowPopup", this); - mm.addMessageListener("FormValidation:HidePopup", this); - }, - - uninit: function () { - let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); - mm.removeMessageListener("FormValidation:ShowPopup", this); - mm.removeMessageListener("FormValidation:HidePopup", this); - this._panel = null; - this._anchor = null; - }, - - hidePopup: function () { - this._hidePopup(); - }, - - /* - * Events - */ - - receiveMessage: function (aMessage) { - let window = aMessage.target.ownerDocument.defaultView; - let json = aMessage.json; - let tabBrowser = window.gBrowser; - switch (aMessage.name) { - case "FormValidation:ShowPopup": - // target is the <browser>, make sure we're receiving a message - // from the foreground tab. - if (tabBrowser && aMessage.target != tabBrowser.selectedBrowser) { - return; - } - this._showPopup(window, json); - break; - case "FormValidation:HidePopup": - this._hidePopup(); - break; - } - }, - - observe: function (aSubject, aTopic, aData) { - this._hidePopup(); - }, - - handleEvent: function (aEvent) { - switch (aEvent.type) { - case "FullZoomChange": - case "TextZoomChange": - case "ZoomChangeUsingMouseWheel": - case "scroll": - this._hidePopup(); - break; - case "popuphiding": - this._onPopupHiding(aEvent); - break; - } - }, - - /* - * Internal - */ - - _onPopupHiding: function (aEvent) { - aEvent.originalTarget.removeEventListener("popuphiding", this, true); - let tabBrowser = aEvent.originalTarget.ownerDocument.getElementById("content"); - tabBrowser.selectedBrowser.removeEventListener("scroll", this, true); - tabBrowser.selectedBrowser.removeEventListener("FullZoomChange", this, false); - tabBrowser.selectedBrowser.removeEventListener("TextZoomChange", this, false); - tabBrowser.selectedBrowser.removeEventListener("ZoomChangeUsingMouseWheel", this, false); - - this._panel.hidden = true; - this._panel = null; - this._anchor.hidden = true; - this._anchor = null; - }, - - /* - * Shows the form validation popup at a specified position or updates the - * messaging and position if the popup is already displayed. - * - * @aWindow - the chrome window - * @aPanelData - Object that contains popup information - * aPanelData stucture detail: - * contentRect - the bounding client rect of the target element. If - * content is remote, this is relative to the browser, otherwise its - * relative to the window. - * position - popup positional string constants. - * message - the form element validation message text. - */ - _showPopup: function (aWindow, aPanelData) { - let previouslyShown = !!this._panel; - this._panel = aWindow.document.getElementById("invalid-form-popup"); - this._panel.firstChild.textContent = aPanelData.message; - this._panel.hidden = false; - - let tabBrowser = aWindow.gBrowser; - this._anchor = tabBrowser.popupAnchor; - this._anchor.left = aPanelData.contentRect.left; - this._anchor.top = aPanelData.contentRect.top; - this._anchor.width = aPanelData.contentRect.width; - this._anchor.height = aPanelData.contentRect.height; - this._anchor.hidden = false; - - // Display the panel if it isn't already visible. - if (!previouslyShown) { - // Cleanup after the popup is hidden - this._panel.addEventListener("popuphiding", this, true); - - // Hide if the user scrolls the page - tabBrowser.selectedBrowser.addEventListener("scroll", this, true); - tabBrowser.selectedBrowser.addEventListener("FullZoomChange", this, false); - tabBrowser.selectedBrowser.addEventListener("TextZoomChange", this, false); - tabBrowser.selectedBrowser.addEventListener("ZoomChangeUsingMouseWheel", this, false); - - // Open the popup - this._panel.openPopup(this._anchor, aPanelData.position, 0, 0, false); - } - }, - - /* - * Hide the popup if currently displayed. Will fire an event to onPopupHiding - * above if visible. - */ - _hidePopup: function () { - if (this._panel) { - this._panel.hidePopup(); - } - } -}; diff --git a/application/palemoon/modules/NetworkPrioritizer.jsm b/application/palemoon/modules/NetworkPrioritizer.jsm deleted file mode 100644 index 23d688a30..000000000 --- a/application/palemoon/modules/NetworkPrioritizer.jsm +++ /dev/null @@ -1,179 +0,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/. */ - -/* - * This module adjusts network priority for tabs in a way that gives 'important' - * tabs a higher priority. There are 3 levels of priority. Each is listed below - * with the priority adjustment used. - * - * Highest (-10): Selected tab in the focused window. - * Medium (0): Background tabs in the focused window. - * Selected tab in background windows. - * Lowest (+10): Background tabs in background windows. - */ - -this.EXPORTED_SYMBOLS = ["trackBrowserWindow"]; - -const Ci = Components.interfaces; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); - - -// Lazy getters -XPCOMUtils.defineLazyServiceGetter(this, "_focusManager", - "@mozilla.org/focus-manager;1", - "nsIFocusManager"); - - -// Constants -const TAB_EVENTS = ["TabOpen", "TabSelect"]; -const WINDOW_EVENTS = ["activate", "unload"]; -// PRIORITY DELTA is -10 because lower priority value is actually a higher priority -const PRIORITY_DELTA = -10; - - -// Variables -var _lastFocusedWindow = null; -var _windows = []; - - -// Exported symbol -this.trackBrowserWindow = function trackBrowserWindow(aWindow) { - WindowHelper.addWindow(aWindow); -} - - -// Global methods -function _handleEvent(aEvent) { - switch (aEvent.type) { - case "TabOpen": - BrowserHelper.onOpen(aEvent.target.linkedBrowser); - break; - case "TabSelect": - BrowserHelper.onSelect(aEvent.target.linkedBrowser); - break; - case "activate": - WindowHelper.onActivate(aEvent.target); - break; - case "unload": - WindowHelper.removeWindow(aEvent.currentTarget); - break; - } -} - - -// Methods that impact a browser. Put into single object for organization. -var BrowserHelper = { - onOpen: function NP_BH_onOpen(aBrowser) { - // If the tab is in the focused window, leave priority as it is - if (aBrowser.ownerDocument.defaultView != _lastFocusedWindow) - this.decreasePriority(aBrowser); - }, - - onSelect: function NP_BH_onSelect(aBrowser) { - let windowEntry = WindowHelper.getEntry(aBrowser.ownerDocument.defaultView); - if (windowEntry.lastSelectedBrowser) - this.decreasePriority(windowEntry.lastSelectedBrowser); - this.increasePriority(aBrowser); - - windowEntry.lastSelectedBrowser = aBrowser; - }, - - increasePriority: function NP_BH_increasePriority(aBrowser) { - aBrowser.adjustPriority(PRIORITY_DELTA); - }, - - decreasePriority: function NP_BH_decreasePriority(aBrowser) { - aBrowser.adjustPriority(PRIORITY_DELTA * -1); - } -}; - - -// Methods that impact a window. Put into single object for organization. -var WindowHelper = { - addWindow: function NP_WH_addWindow(aWindow) { - // Build internal data object - _windows.push({ window: aWindow, lastSelectedBrowser: null }); - - // Add event listeners - TAB_EVENTS.forEach(function(event) { - aWindow.gBrowser.tabContainer.addEventListener(event, _handleEvent, false); - }); - WINDOW_EVENTS.forEach(function(event) { - aWindow.addEventListener(event, _handleEvent, false); - }); - - // This gets called AFTER activate event, so if this is the focused window - // we want to activate it. Otherwise, deprioritize it. - if (aWindow == _focusManager.activeWindow) - this.handleFocusedWindow(aWindow); - else - this.decreasePriority(aWindow); - - // Select the selected tab - BrowserHelper.onSelect(aWindow.gBrowser.selectedBrowser); - }, - - removeWindow: function NP_WH_removeWindow(aWindow) { - if (aWindow == _lastFocusedWindow) - _lastFocusedWindow = null; - - // Delete this window from our tracking - _windows.splice(this.getEntryIndex(aWindow), 1); - - // Remove the event listeners - TAB_EVENTS.forEach(function(event) { - aWindow.gBrowser.tabContainer.removeEventListener(event, _handleEvent, false); - }); - WINDOW_EVENTS.forEach(function(event) { - aWindow.removeEventListener(event, _handleEvent, false); - }); - }, - - onActivate: function NP_WH_onActivate(aWindow, aHasFocus) { - // If this window was the last focused window, we don't need to do anything - if (aWindow == _lastFocusedWindow) - return; - - // handleFocusedWindow will deprioritize the current window - this.handleFocusedWindow(aWindow); - - // Lastly we should increase priority for this window - this.increasePriority(aWindow); - }, - - handleFocusedWindow: function NP_WH_handleFocusedWindow(aWindow) { - // If we have a last focused window, we need to deprioritize it first - if (_lastFocusedWindow) - this.decreasePriority(_lastFocusedWindow); - - // aWindow is now focused - _lastFocusedWindow = aWindow; - }, - - // Auxiliary methods - increasePriority: function NP_WH_increasePriority(aWindow) { - aWindow.gBrowser.browsers.forEach(function(aBrowser) { - BrowserHelper.increasePriority(aBrowser); - }); - }, - - decreasePriority: function NP_WH_decreasePriority(aWindow) { - aWindow.gBrowser.browsers.forEach(function(aBrowser) { - BrowserHelper.decreasePriority(aBrowser); - }); - }, - - getEntry: function NP_WH_getEntry(aWindow) { - return _windows[this.getEntryIndex(aWindow)]; - }, - - getEntryIndex: function NP_WH_getEntryAtIndex(aWindow) { - // Assumes that every object has a unique window & it's in the array - for (let i = 0; i < _windows.length; i++) - if (_windows[i].window == aWindow) - return i; - } -}; - diff --git a/application/palemoon/modules/PageMenu.jsm b/application/palemoon/modules/PageMenu.jsm deleted file mode 100644 index d01f62601..000000000 --- a/application/palemoon/modules/PageMenu.jsm +++ /dev/null @@ -1,238 +0,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/. */ - -this.EXPORTED_SYMBOLS = ["PageMenu"]; - -this.PageMenu = function PageMenu() { -} - -PageMenu.prototype = { - PAGEMENU_ATTR: "pagemenu", - GENERATEDITEMID_ATTR: "generateditemid", - - _popup: null, - _builder: null, - - // Given a target node, get the context menu for it or its ancestor. - getContextMenu: function(aTarget) { - let target = aTarget; - while (target) { - let contextMenu = target.contextMenu; - if (contextMenu) { - return contextMenu; - } - target = target.parentNode; - } - - return null; - }, - - // Given a target node, generate a JSON object for any context menu - // associated with it, or null if there is no context menu. - maybeBuild: function(aTarget) { - let pageMenu = this.getContextMenu(aTarget); - if (!pageMenu) { - return null; - } - - pageMenu.QueryInterface(Components.interfaces.nsIHTMLMenu); - pageMenu.sendShowEvent(); - // the show event is not cancelable, so no need to check a result here - - this._builder = pageMenu.createBuilder(); - if (!this._builder) { - return null; - } - - pageMenu.build(this._builder); - - // This serializes then parses again, however this could be avoided in - // the single-process case with further improvement. - let menuString = this._builder.toJSONString(); - if (!menuString) { - return null; - } - - return JSON.parse(menuString); - }, - - // Given a JSON menu object and popup, add the context menu to the popup. - buildAndAttachMenuWithObject: function(aMenu, aBrowser, aPopup) { - if (!aMenu) { - return false; - } - - let insertionPoint = this.getInsertionPoint(aPopup); - if (!insertionPoint) { - return false; - } - - let fragment = aPopup.ownerDocument.createDocumentFragment(); - this.buildXULMenu(aMenu, fragment); - - let pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR); - if (pos == "start") { - insertionPoint.insertBefore(fragment, - insertionPoint.firstChild); - } else if (pos.startsWith("#")) { - insertionPoint.insertBefore(fragment, insertionPoint.querySelector(pos)); - } else { - insertionPoint.appendChild(fragment); - } - - this._popup = aPopup; - - this._popup.addEventListener("command", this); - this._popup.addEventListener("popuphidden", this); - - return true; - }, - - // Construct the XUL menu structure for a given JSON object. - buildXULMenu: function(aNode, aElementForAppending) { - let document = aElementForAppending.ownerDocument; - - let children = aNode.children; - for (let child of children) { - let menuitem; - switch (child.type) { - case "menuitem": - if (!child.id) { - continue; // Ignore children without ids - } - - menuitem = document.createElement("menuitem"); - if (child.checkbox) { - menuitem.setAttribute("type", "checkbox"); - if (child.checked) { - menuitem.setAttribute("checked", "true"); - } - } - - if (child.label) { - menuitem.setAttribute("label", child.label); - } - if (child.icon) { - menuitem.setAttribute("image", child.icon); - menuitem.className = "menuitem-iconic"; - } - if (child.disabled) { - menuitem.setAttribute("disabled", true); - } - - break; - - case "separator": - menuitem = document.createElement("menuseparator"); - break; - - case "menu": - menuitem = document.createElement("menu"); - if (child.label) { - menuitem.setAttribute("label", child.label); - } - - let menupopup = document.createElement("menupopup"); - menuitem.appendChild(menupopup); - - this.buildXULMenu(child, menupopup); - break; - } - - menuitem.setAttribute(this.GENERATEDITEMID_ATTR, child.id ? child.id : 0); - aElementForAppending.appendChild(menuitem); - } - }, - - // Called when the generated menuitem is executed. - handleEvent: function(event) { - let type = event.type; - let target = event.target; - if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) { - // If a builder is assigned, call click on it directly. Otherwise, this is - // likely a menu with data from another process, so send a message to the - // browser to execute the menuitem. - if (this._builder) { - this._builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR)); - } - } else if (type == "popuphidden" && this._popup == target) { - this.removeGeneratedContent(this._popup); - - this._popup.removeEventListener("popuphidden", this); - this._popup.removeEventListener("command", this); - - this._popup = null; - this._builder = null; - } - }, - - // Get the first child of the given element with the given tag name. - getImmediateChild: function(element, tag) { - let child = element.firstChild; - while (child) { - if (child.localName == tag) { - return child; - } - child = child.nextSibling; - } - return null; - }, - - // Return the location where the generated items should be inserted into the - // given popup. They should be inserted as the next sibling of the returned - // element. - getInsertionPoint: function(aPopup) { - if (aPopup.hasAttribute(this.PAGEMENU_ATTR)) - return aPopup; - - let element = aPopup.firstChild; - while (element) { - if (element.localName == "menu") { - let popup = this.getImmediateChild(element, "menupopup"); - if (popup) { - let result = this.getInsertionPoint(popup); - if (result) { - return result; - } - } - } - element = element.nextSibling; - } - - return null; - }, - - // Returns true if custom menu items were present. - maybeBuildAndAttachMenu: function(aTarget, aPopup) { - let menuObject = this.maybeBuild(aTarget); - if (!menuObject) { - return false; - } - - return this.buildAndAttachMenuWithObject(menuObject, null, aPopup); - }, - - // Remove the generated content from the given popup. - removeGeneratedContent: function(aPopup) { - let ungenerated = []; - ungenerated.push(aPopup); - - let count; - while (0 != (count = ungenerated.length)) { - let last = count - 1; - let element = ungenerated[last]; - ungenerated.splice(last, 1); - - let i = element.childNodes.length; - while (i-- > 0) { - let child = element.childNodes[i]; - if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) { - ungenerated.push(child); - continue; - } - element.removeChild(child); - } - } - } -} diff --git a/application/palemoon/modules/PopupNotifications.jsm b/application/palemoon/modules/PopupNotifications.jsm deleted file mode 100644 index 0cb970230..000000000 --- a/application/palemoon/modules/PopupNotifications.jsm +++ /dev/null @@ -1,994 +0,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/. */ - -this.EXPORTED_SYMBOLS = ["PopupNotifications"]; - -var Cc = Components.classes, Ci = Components.interfaces, Cu = Components.utils; - -Cu.import("resource://gre/modules/Services.jsm"); - -const NOTIFICATION_EVENT_DISMISSED = "dismissed"; -const NOTIFICATION_EVENT_REMOVED = "removed"; -const NOTIFICATION_EVENT_SHOWING = "showing"; -const NOTIFICATION_EVENT_SHOWN = "shown"; -const NOTIFICATION_EVENT_SWAPPING = "swapping"; - -const ICON_SELECTOR = ".notification-anchor-icon"; -const ICON_ATTRIBUTE_SHOWING = "showing"; - -const PREF_SECURITY_DELAY = "security.notification_enable_delay"; - -var popupNotificationsMap = new WeakMap(); -var gNotificationParents = new WeakMap; - -function getAnchorFromBrowser(aBrowser) { - let anchor = aBrowser.getAttribute("popupnotificationanchor") || - aBrowser.popupnotificationanchor; - if (anchor) { - if (anchor instanceof Ci.nsIDOMXULElement) { - return anchor; - } - return aBrowser.ownerDocument.getElementById(anchor); - } - return null; -} - -function getNotificationFromElement(aElement) { - // Need to find the associated notification object, which is a bit tricky - // since it isn't associated with the element directly - this is kind of - // gross and very dependent on the structure of the popupnotification - // binding's content. - let notificationEl; - let parent = aElement; - while (parent && (parent = aElement.ownerDocument.getBindingParent(parent))) - notificationEl = parent; - return notificationEl; -} - -/** - * Notification object describes a single popup notification. - * - * @see PopupNotifications.show() - */ -function Notification(id, message, anchorID, mainAction, secondaryActions, - browser, owner, options) { - this.id = id; - this.message = message; - this.anchorID = anchorID; - this.mainAction = mainAction; - this.secondaryActions = secondaryActions || []; - this.browser = browser; - this.owner = owner; - this.options = options || {}; -} - -Notification.prototype = { - - id: null, - message: null, - anchorID: null, - mainAction: null, - secondaryActions: null, - browser: null, - owner: null, - options: null, - timeShown: null, - - /** - * Removes the notification and updates the popup accordingly if needed. - */ - remove: function Notification_remove() { - this.owner.remove(this); - }, - - get anchorElement() { - let iconBox = this.owner.iconBox; - - let anchorElement = getAnchorFromBrowser(this.browser); - - if (!iconBox) - return anchorElement; - - if (!anchorElement && this.anchorID) - anchorElement = iconBox.querySelector("#"+this.anchorID); - - // Use a default anchor icon if it's available - if (!anchorElement) - anchorElement = iconBox.querySelector("#default-notification-icon") || - iconBox; - - return anchorElement; - }, - - reshow: function() { - this.owner._reshowNotifications(this.anchorElement, this.browser); - } -}; - -/** - * The PopupNotifications object manages popup notifications for a given browser - * window. - * @param tabbrowser - * window's <xul:tabbrowser/>. Used to observe tab switching events and - * for determining the active browser element. - * @param panel - * The <xul:panel/> element to use for notifications. The panel is - * populated with <popupnotification> children and displayed it as - * needed. - * @param iconBox - * Reference to a container element that should be hidden or - * unhidden when notifications are hidden or shown. It should be the - * parent of anchor elements whose IDs are passed to show(). - * It is used as a fallback popup anchor if notifications specify - * invalid or non-existent anchor IDs. - */ -this.PopupNotifications = function PopupNotifications(tabbrowser, panel, iconBox) { - if (!(tabbrowser instanceof Ci.nsIDOMXULElement)) - throw "Invalid tabbrowser"; - if (iconBox && !(iconBox instanceof Ci.nsIDOMXULElement)) - throw "Invalid iconBox"; - if (!(panel instanceof Ci.nsIDOMXULElement)) - throw "Invalid panel"; - - this.window = tabbrowser.ownerDocument.defaultView; - this.panel = panel; - this.tabbrowser = tabbrowser; - this.iconBox = iconBox; - this.buttonDelay = Services.prefs.getIntPref(PREF_SECURITY_DELAY); - - this.panel.addEventListener("popuphidden", this, true); - - this.window.addEventListener("activate", this, true); - if (this.tabbrowser.tabContainer) - this.tabbrowser.tabContainer.addEventListener("TabSelect", this, true); -} - -PopupNotifications.prototype = { - - window: null, - panel: null, - tabbrowser: null, - - _iconBox: null, - set iconBox(iconBox) { - // Remove the listeners on the old iconBox, if needed - if (this._iconBox) { - this._iconBox.removeEventListener("click", this, false); - this._iconBox.removeEventListener("keypress", this, false); - } - this._iconBox = iconBox; - if (iconBox) { - iconBox.addEventListener("click", this, false); - iconBox.addEventListener("keypress", this, false); - } - }, - get iconBox() { - return this._iconBox; - }, - - /** - * Retrieve a Notification object associated with the browser/ID pair. - * @param id - * The Notification ID to search for. - * @param browser - * The browser whose notifications should be searched. If null, the - * currently selected browser's notifications will be searched. - * - * @returns the corresponding Notification object, or null if no such - * notification exists. - */ - getNotification: function PopupNotifications_getNotification(id, browser) { - let n = null; - let notifications = this._getNotificationsForBrowser(browser || this.tabbrowser.selectedBrowser); - notifications.some(function(x) x.id == id && (n = x)); - return n; - }, - - /** - * Adds a new popup notification. - * @param browser - * The <xul:browser> element associated with the notification. Must not - * be null. - * @param id - * A unique ID that identifies the type of notification (e.g. - * "geolocation"). Only one notification with a given ID can be visible - * at a time. If a notification already exists with the given ID, it - * will be replaced. - * @param message - * The text to be displayed in the notification. - * @param anchorID - * The ID of the element that should be used as this notification - * popup's anchor. May be null, in which case the notification will be - * anchored to the iconBox. - * @param mainAction - * A JavaScript object literal describing the notification button's - * action. If present, it must have the following properties: - * - label (string): the button's label. - * - accessKey (string): the button's accessKey. - * - callback (function): a callback to be invoked when the button is - * pressed, is passed an object that contains the following fields: - * - checkboxChecked: (boolean) If the optional checkbox is checked. - * If null, the notification will not have a button, and - * secondaryActions will be ignored. - * @param secondaryActions - * An optional JavaScript array describing the notification's alternate - * actions. The array should contain objects with the same properties - * as mainAction. These are used to populate the notification button's - * dropdown menu. - * @param options - * An options JavaScript object holding additional properties for the - * notification. The following properties are currently supported: - * persistence: An integer. The notification will not automatically - * dismiss for this many page loads. - * timeout: A time in milliseconds. The notification will not - * automatically dismiss before this time. - * persistWhileVisible: - * A boolean. If true, a visible notification will always - * persist across location changes. - * dismissed: Whether the notification should be added as a dismissed - * notification. Dismissed notifications can be activated - * by clicking on their anchorElement. - * eventCallback: - * Callback to be invoked when the notification changes - * state. The callback's first argument is a string - * identifying the state change: - * "dismissed": notification has been dismissed by the - * user (e.g. by clicking away or switching - * tabs) - * "removed": notification has been removed (due to - * location change or user action) - * "showing": notification is about to be shown - * (this can be fired multiple times as - * notifications are dismissed and re-shown) - * "shown": notification has been shown (this can be fired - * multiple times as notifications are dismissed - * and re-shown) - * "swapping": the docshell of the browser that created - * the notification is about to be swapped to - * another browser. A second parameter contains - * the browser that is receiving the docshell, - * so that the event callback can transfer stuff - * specific to this notification. - * If the callback returns true, the notification - * will be moved to the new browser. - * If the callback isn't implemented, returns false, - * or doesn't return any value, the notification - * will be removed. - * neverShow: Indicate that no popup should be shown for this - * notification. Useful for just showing the anchor icon. - * removeOnDismissal: - * Notifications with this parameter set to true will be - * removed when they would have otherwise been dismissed - * (i.e. any time the popup is closed due to user - * interaction). - * checkbox: An object that allows you to add a checkbox and - * control its behavior with these fields: - * label: - * (required) Label to be shown next to the checkbox. - * checked: - * (optional) Whether the checkbox should be checked - * by default. Defaults to false. - * checkedState: - * (optional) An object that allows you to customize - * the notification state when the checkbox is checked. - * disableMainAction: - * (optional) Whether the mainAction is disabled. - * Defaults to false. - * warningLabel: - * (optional) A (warning) text that is shown below the - * checkbox. Pass null to hide. - * uncheckedState: - * (optional) An object that allows you to customize - * the notification state when the checkbox is not checked. - * Has the same attributes as checkedState. - * popupIconURL: - * A string. URL of the image to be displayed in the popup. - * Normally specified in CSS using list-style-image and the - * .popup-notification-icon[popupid=...] selector. - * learnMoreURL: - * A string URL. Setting this property will make the - * prompt display a "Learn More" link that, when clicked, - * opens the URL in a new tab. - * @returns the Notification object corresponding to the added notification. - */ - show: function PopupNotifications_show(browser, id, message, anchorID, - mainAction, secondaryActions, options) { - function isInvalidAction(a) { - return !a || !(typeof(a.callback) == "function") || !a.label || !a.accessKey; - } - - if (!browser) - throw "PopupNotifications_show: invalid browser"; - if (!id) - throw "PopupNotifications_show: invalid ID"; - if (mainAction && isInvalidAction(mainAction)) - throw "PopupNotifications_show: invalid mainAction"; - if (secondaryActions && secondaryActions.some(isInvalidAction)) - throw "PopupNotifications_show: invalid secondaryActions"; - - let notification = new Notification(id, message, anchorID, mainAction, - secondaryActions, browser, this, options); - - if (options && options.dismissed) - notification.dismissed = true; - - let existingNotification = this.getNotification(id, browser); - if (existingNotification) - this._remove(existingNotification); - - let notifications = this._getNotificationsForBrowser(browser); - notifications.push(notification); - - let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); - if (browser.docShell.isActive && fm.activeWindow == this.window) { - // show panel now - this._update(notifications, notification.anchorElement, true); - } else { - // Otherwise, update() will display the notification the next time the - // relevant tab/window is selected. - - // If the tab is selected but the window is in the background, let the OS - // tell the user that there's a notification waiting in that window. - // At some point we might want to do something about background tabs here - // too. When the user switches to this window, we'll show the panel if - // this browser is a tab (thus showing the anchor icon). For - // non-tabbrowser browsers, we need to make the icon visible now or the - // user will not be able to open the panel. - if (!notification.dismissed && browser.docShell.isActive) { - this.window.getAttention(); - if (notification.anchorElement.parentNode != this.iconBox) { - notification.anchorElement.setAttribute(ICON_ATTRIBUTE_SHOWING, "true"); - } - } - - // Notify observers that we're not showing the popup (useful for testing) - this._notify("backgroundShow"); - } - - return notification; - }, - - /** - * Returns true if the notification popup is currently being displayed. - */ - get isPanelOpen() { - let panelState = this.panel.state; - - return panelState == "showing" || panelState == "open"; - }, - - /** - * Called by the consumer to indicate that a browser's location has changed, - * so that we can update the active notifications accordingly. - */ - locationChange: function PopupNotifications_locationChange(aBrowser) { - if (!aBrowser) - throw "PopupNotifications_locationChange: invalid browser"; - - let notifications = this._getNotificationsForBrowser(aBrowser); - - notifications = notifications.filter(function (notification) { - // The persistWhileVisible option allows an open notification to persist - // across location changes - if (notification.options.persistWhileVisible && - this.isPanelOpen) { - if ("persistence" in notification.options && - notification.options.persistence) - notification.options.persistence--; - return true; - } - - // The persistence option allows a notification to persist across multiple - // page loads - if ("persistence" in notification.options && - notification.options.persistence) { - notification.options.persistence--; - return true; - } - - // The timeout option allows a notification to persist until a certain time - if ("timeout" in notification.options && - Date.now() <= notification.options.timeout) { - return true; - } - - this._fireCallback(notification, NOTIFICATION_EVENT_REMOVED); - return false; - }, this); - - this._setNotificationsForBrowser(aBrowser, notifications); - - if (aBrowser.docShell.isActive) { - // get the anchor element if the browser has defined one so it will - // _update will handle both the tabs iconBox and non-tab permission - // anchors. - let anchorElement = notifications.length > 0 ? notifications[0].anchorElement : null; - if (!anchorElement) - anchorElement = getAnchorFromBrowser(aBrowser); - this._update(notifications, anchorElement); - } - }, - - /** - * Removes a Notification. - * @param notification - * The Notification object to remove. - */ - remove: function PopupNotifications_remove(notification) { - this._remove(notification); - - if (notification.browser.docShell.isActive) { - let notifications = this._getNotificationsForBrowser(notification.browser); - this._update(notifications, notification.anchorElement); - } - }, - - handleEvent: function (aEvent) { - switch (aEvent.type) { - case "popuphidden": - this._onPopupHidden(aEvent); - break; - case "activate": - case "TabSelect": - let self = this; - // setTimeout(..., 0) needed, otherwise openPopup from "activate" event - // handler results in the popup being hidden again for some reason... - this.window.setTimeout(function () { - self._update(); - }, 0); - break; - case "click": - case "keypress": - this._onIconBoxCommand(aEvent); - break; - } - }, - -//////////////////////////////////////////////////////////////////////////////// -// Utility methods -//////////////////////////////////////////////////////////////////////////////// - - _ignoreDismissal: null, - _currentAnchorElement: null, - - /** - * Gets notifications for the currently selected browser. - */ - get _currentNotifications() { - return this.tabbrowser.selectedBrowser ? this._getNotificationsForBrowser(this.tabbrowser.selectedBrowser) : []; - }, - - _remove: function PopupNotifications_removeHelper(notification) { - // This notification may already be removed, in which case let's just fail - // silently. - let notifications = this._getNotificationsForBrowser(notification.browser); - if (!notifications) - return; - - var index = notifications.indexOf(notification); - if (index == -1) - return; - - if (notification.browser.docShell.isActive) - notification.anchorElement.removeAttribute(ICON_ATTRIBUTE_SHOWING); - - // remove the notification - notifications.splice(index, 1); - this._fireCallback(notification, NOTIFICATION_EVENT_REMOVED); - }, - - /** - * Dismisses the notification without removing it. - */ - _dismiss: function PopupNotifications_dismiss() { - let browser = this.panel.firstChild && - this.panel.firstChild.notification.browser; - if (typeof this.panel.hidePopup === "function") { - this.panel.hidePopup(); - } - if (browser) - browser.focus(); - }, - - /** - * Hides the notification popup. - */ - _hidePanel: function PopupNotifications_hide() { - this._ignoreDismissal = true; - if (typeof this.panel.hidePopup === "function") { - this.panel.hidePopup(); - } - this._ignoreDismissal = false; - }, - - /** - * Removes all notifications from the notification popup. - */ - _clearPanel: function () { - let popupnotification; - while ((popupnotification = this.panel.lastChild)) { - this.panel.removeChild(popupnotification); - - // If this notification was provided by the chrome document rather than - // created ad hoc, move it back to where we got it from. - let originalParent = gNotificationParents.get(popupnotification); - if (originalParent) { - popupnotification.notification = null; - - // Remove nodes dynamically added to the notification's menu button - // in _refreshPanel. Keep popupnotificationcontent nodes; they are - // provided by the chrome document. - let contentNode = popupnotification.lastChild; - while (contentNode) { - let previousSibling = contentNode.previousSibling; - if (contentNode.nodeName != "popupnotificationcontent") - popupnotification.removeChild(contentNode); - contentNode = previousSibling; - } - - // Re-hide the notification such that it isn't rendered in the chrome - // document. _refreshPanel will unhide it again when needed. - popupnotification.hidden = true; - - originalParent.appendChild(popupnotification); - } - } - }, - - _refreshPanel: function PopupNotifications_refreshPanel(notificationsToShow) { - this._clearPanel(); - - const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; - - notificationsToShow.forEach(function (n) { - let doc = this.window.document; - - // Append "-notification" to the ID to try to avoid ID conflicts with other stuff - // in the document. - let popupnotificationID = n.id + "-notification"; - - // If the chrome document provides a popupnotification with this id, use - // that. Otherwise create it ad-hoc. - let popupnotification = doc.getElementById(popupnotificationID); - if (popupnotification) - gNotificationParents.set(popupnotification, popupnotification.parentNode); - else - popupnotification = doc.createElementNS(XUL_NS, "popupnotification"); - - popupnotification.setAttribute("label", n.message); - popupnotification.setAttribute("id", popupnotificationID); - popupnotification.setAttribute("popupid", n.id); - popupnotification.setAttribute("closebuttoncommand", "PopupNotifications._dismiss();"); - if (n.mainAction) { - popupnotification.setAttribute("buttonlabel", n.mainAction.label); - popupnotification.setAttribute("buttonaccesskey", n.mainAction.accessKey); - popupnotification.setAttribute("buttoncommand", "PopupNotifications._onButtonCommand(event);"); - popupnotification.setAttribute("menucommand", "PopupNotifications._onMenuCommand(event);"); - popupnotification.setAttribute("closeitemcommand", "PopupNotifications._dismiss();event.stopPropagation();"); - } else { - popupnotification.removeAttribute("buttonlabel"); - popupnotification.removeAttribute("buttonaccesskey"); - popupnotification.removeAttribute("buttoncommand"); - popupnotification.removeAttribute("menucommand"); - popupnotification.removeAttribute("closeitemcommand"); - } - - if (n.options.popupIconURL) - popupnotification.setAttribute("icon", n.options.popupIconURL); - if (n.options.learnMoreURL) - popupnotification.setAttribute("learnmoreurl", n.options.learnMoreURL); - else - popupnotification.removeAttribute("learnmoreurl"); - - popupnotification.notification = n; - - if (n.secondaryActions) { - n.secondaryActions.forEach(function (a) { - let item = doc.createElementNS(XUL_NS, "menuitem"); - item.setAttribute("label", a.label); - item.setAttribute("accesskey", a.accessKey); - item.notification = n; - item.action = a; - - popupnotification.appendChild(item); - }, this); - - if (n.secondaryActions.length) { - let closeItemSeparator = doc.createElementNS(XUL_NS, "menuseparator"); - popupnotification.appendChild(closeItemSeparator); - } - } - - let checkbox = n.options.checkbox; - if (checkbox && checkbox.label) { - let checked = n._checkboxChecked != null ? n._checkboxChecked : !!checkbox.checked; - - popupnotification.setAttribute("checkboxhidden", "false"); - popupnotification.setAttribute("checkboxchecked", checked); - popupnotification.setAttribute("checkboxlabel", checkbox.label); - - popupnotification.setAttribute("checkboxcommand", "PopupNotifications._onCheckboxCommand(event);"); - - if (checked) { - this._setNotificationUIState(popupnotification, checkbox.checkedState); - } else { - this._setNotificationUIState(popupnotification, checkbox.uncheckedState); - } - } else { - popupnotification.setAttribute("checkboxhidden", "true"); - } - - this.panel.appendChild(popupnotification); - - // The popupnotification may be hidden if we got it from the chrome - // document rather than creating it ad hoc. - popupnotification.hidden = false; - }, this); - }, - - _setNotificationUIState(notification, state={}) { - notification.setAttribute("mainactiondisabled", state.disableMainAction || "false"); - - if (state.warningLabel) { - notification.setAttribute("warninglabel", state.warningLabel); - notification.setAttribute("warninghidden", "false"); - } else { - notification.setAttribute("warninghidden", "true"); - } - }, - - _onCheckboxCommand(event) { - let notificationEl = getNotificationFromElement(event.originalTarget); - let checked = notificationEl.checkbox.checked; - let notification = notificationEl.notification; - - // Save checkbox state to be able to persist it when re-opening the doorhanger. - notification._checkboxChecked = checked; - - if (checked) { - this._setNotificationUIState(notificationEl, notification.options.checkbox.checkedState); - } else { - this._setNotificationUIState(notificationEl, notification.options.checkbox.uncheckedState); - } - }, - - _showPanel: function PopupNotifications_showPanel(notificationsToShow, anchorElement) { - this.panel.hidden = false; - - notificationsToShow.forEach(function (n) { - this._fireCallback(n, NOTIFICATION_EVENT_SHOWING); - }, this); - this._refreshPanel(notificationsToShow); - - if (this.isPanelOpen && this._currentAnchorElement == anchorElement) - return; - - // If the panel is already open but we're changing anchors, we need to hide - // it first. Otherwise it can appear in the wrong spot. (_hidePanel is - // safe to call even if the panel is already hidden.) - this._hidePanel(); - - // If the anchor element is hidden or null, use the tab as the anchor. We - // only ever show notifications for the current browser, so we can just use - // the current tab. - let selectedTab = this.tabbrowser.selectedTab; - if (anchorElement) { - let bo = anchorElement.boxObject; - if (bo.height == 0 && bo.width == 0) - anchorElement = selectedTab; // hidden - } else { - anchorElement = selectedTab; // null - } - - this._currentAnchorElement = anchorElement; - - // On OS X and Linux we need a different panel arrow color for - // click-to-play plugins, so copy the popupid and use css. - this.panel.setAttribute("popupid", this.panel.firstChild.getAttribute("popupid")); - notificationsToShow.forEach(function (n) { - // Remember the time the notification was shown for the security delay. - n.timeShown = this.window.performance.now(); - }, this); - this.panel.openPopup(anchorElement, "bottomcenter topleft"); - notificationsToShow.forEach(function (n) { - this._fireCallback(n, NOTIFICATION_EVENT_SHOWN); - }, this); - }, - - /** - * Updates the notification state in response to window activation or tab - * selection changes. - * - * @param notifications an array of Notification instances. if null, - * notifications will be retrieved off the current - * browser tab - * @param anchor is a XUL element that the notifications panel will be - * anchored to - * @param dismissShowing if true, dismiss any currently visible notifications - * if there are no notifications to show. Otherwise, - * currently displayed notifications will be left alone. - */ - _update: function PopupNotifications_update(notifications, anchor, dismissShowing = false) { - let useIconBox = this.iconBox && (!anchor || anchor.parentNode == this.iconBox); - if (useIconBox) { - // hide icons of the previous tab. - this._hideIcons(); - } - - let anchorElement = anchor, notificationsToShow = []; - if (!notifications) - notifications = this._currentNotifications; - let haveNotifications = notifications.length > 0; - if (haveNotifications) { - // Only show the notifications that have the passed-in anchor (or the - // first notification's anchor, if none was passed in). Other - // notifications will be shown once these are dismissed. - anchorElement = anchor || notifications[0].anchorElement; - - if (useIconBox) { - this._showIcons(notifications); - this.iconBox.hidden = false; - } else if (anchorElement) { - anchorElement.setAttribute(ICON_ATTRIBUTE_SHOWING, "true"); - // use the anchorID as a class along with the default icon class as a - // fallback if anchorID is not defined in CSS. We always use the first - // notifications icon, so in the case of multiple notifications we'll - // only use the default icon - if (anchorElement.classList.contains("notification-anchor-icon")) { - // remove previous icon classes - let className = anchorElement.className.replace(/([-\w]+-notification-icon\s?)/g,"") - className = "default-notification-icon " + className; - if (notifications.length == 1) { - className = notifications[0].anchorID + " " + className; - } - anchorElement.className = className; - } - } - - // Also filter out notifications that have been dismissed. - notificationsToShow = notifications.filter(function (n) { - return !n.dismissed && n.anchorElement == anchorElement && - !n.options.neverShow; - }); - } - - if (notificationsToShow.length > 0) { - this._showPanel(notificationsToShow, anchorElement); - } else { - // Notify observers that we're not showing the popup (useful for testing) - this._notify("updateNotShowing"); - - // Close the panel if there are no notifications to show. - // When called from PopupNotifications.show() we should never close the - // panel, however. It may just be adding a dismissed notification, in - // which case we want to continue showing any existing notifications. - if (!dismissShowing) - this._dismiss(); - - // Only hide the iconBox if we actually have no notifications (as opposed - // to not having any showable notifications) - if (!haveNotifications) { - if (useIconBox) - this.iconBox.hidden = true; - else if (anchorElement) - anchorElement.removeAttribute(ICON_ATTRIBUTE_SHOWING); - } - } - }, - - _showIcons: function PopupNotifications_showIcons(aCurrentNotifications) { - for (let notification of aCurrentNotifications) { - let anchorElm = notification.anchorElement; - if (anchorElm) { - anchorElm.setAttribute(ICON_ATTRIBUTE_SHOWING, "true"); - } - } - }, - - _hideIcons: function PopupNotifications_hideIcons() { - let icons = this.iconBox.querySelectorAll(ICON_SELECTOR); - for (let icon of icons) { - icon.removeAttribute(ICON_ATTRIBUTE_SHOWING); - } - }, - - /** - * Gets and sets notifications for the browser. - */ - _getNotificationsForBrowser: function PopupNotifications_getNotifications(browser) { - let notifications = popupNotificationsMap.get(browser); - if (!notifications) { - // Initialize the WeakMap for the browser so callers can reference/manipulate the array. - notifications = []; - popupNotificationsMap.set(browser, notifications); - } - return notifications; - }, - _setNotificationsForBrowser: function PopupNotifications_setNotifications(browser, notifications) { - popupNotificationsMap.set(browser, notifications); - return notifications; - }, - - _onIconBoxCommand: function PopupNotifications_onIconBoxCommand(event) { - // Left click, space or enter only - let type = event.type; - if (type == "click" && event.button != 0) - return; - - if (type == "keypress" && - !(event.charCode == Ci.nsIDOMKeyEvent.DOM_VK_SPACE || - event.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RETURN)) - return; - - if (this._currentNotifications.length == 0) - return; - - // Get the anchor that is the immediate child of the icon box - let anchor = event.target; - while (anchor && anchor.parentNode != this.iconBox) - anchor = anchor.parentNode; - - this._reshowNotifications(anchor); - }, - - _reshowNotifications: function PopupNotifications_reshowNotifications(anchor, browser) { - // Mark notifications anchored to this anchor as un-dismissed - let notifications = this._getNotificationsForBrowser(browser || this.tabbrowser.selectedBrowser); - notifications.forEach(function (n) { - if (n.anchorElement == anchor) - n.dismissed = false; - }); - - // ...and then show them. - this._update(notifications, anchor); - }, - - _swapBrowserNotifications: function PopupNotifications_swapBrowserNoficications(ourBrowser, otherBrowser) { - // When swaping browser docshells (e.g. dragging tab to new window) we need - // to update our notification map. - - let ourNotifications = this._getNotificationsForBrowser(ourBrowser); - let other = otherBrowser.ownerDocument.defaultView.PopupNotifications; - if (!other) { - if (ourNotifications.length > 0) - Cu.reportError("unable to swap notifications: otherBrowser doesn't support notifications"); - return; - } - let otherNotifications = other._getNotificationsForBrowser(otherBrowser); - if (ourNotifications.length < 1 && otherNotifications.length < 1) { - // No notification to swap. - return; - } - - otherNotifications = otherNotifications.filter(n => { - if (this._fireCallback(n, NOTIFICATION_EVENT_SWAPPING, ourBrowser)) { - n.browser = ourBrowser; - n.owner = this; - return true; - } - other._fireCallback(n, NOTIFICATION_EVENT_REMOVED); - return false; - }); - - ourNotifications = ourNotifications.filter(n => { - if (this._fireCallback(n, NOTIFICATION_EVENT_SWAPPING, otherBrowser)) { - n.browser = otherBrowser; - n.owner = other; - return true; - } - this._fireCallback(n, NOTIFICATION_EVENT_REMOVED); - return false; - }); - - this._setNotificationsForBrowser(otherBrowser, ourNotifications); - other._setNotificationsForBrowser(ourBrowser, otherNotifications); - - if (otherNotifications.length > 0) - this._update(otherNotifications, otherNotifications[0].anchorElement); - if (ourNotifications.length > 0) - other._update(ourNotifications, ourNotifications[0].anchorElement); - }, - - _fireCallback: function PopupNotifications_fireCallback(n, event, ...args) { - try { - if (n.options.eventCallback) - return n.options.eventCallback.call(n, event, ...args); - } catch (error) { - Cu.reportError(error); - } - return undefined; - }, - - _onPopupHidden: function PopupNotifications_onPopupHidden(event) { - if (event.target != this.panel || this._ignoreDismissal) - return; - - let browser = this.panel.firstChild && - this.panel.firstChild.notification.browser; - if (!browser) - return; - - let notifications = this._getNotificationsForBrowser(browser); - // Mark notifications as dismissed and call dismissal callbacks - Array.forEach(this.panel.childNodes, function (nEl) { - let notificationObj = nEl.notification; - // Never call a dismissal handler on a notification that's been removed. - if (notifications.indexOf(notificationObj) == -1) - return; - - // Do not mark the notification as dismissed or fire NOTIFICATION_EVENT_DISMISSED - // if the notification is removed. - if (notificationObj.options.removeOnDismissal) - this._remove(notificationObj); - else { - notificationObj.dismissed = true; - this._fireCallback(notificationObj, NOTIFICATION_EVENT_DISMISSED); - } - }, this); - - this._clearPanel(); - - this._update(); - }, - - _onButtonCommand: function PopupNotifications_onButtonCommand(event) { - let notificationEl = getNotificationFromElement(event.originalTarget); - - if (!notificationEl) - throw "PopupNotifications_onButtonCommand: couldn't find notification element"; - - if (!notificationEl.notification) - throw "PopupNotifications_onButtonCommand: couldn't find notification"; - - let notification = notificationEl.notification; - let timeSinceShown = this.window.performance.now() - notification.timeShown; - - // Only report the first time mainAction is triggered and remember that this occurred. - if (!notification.timeMainActionFirstTriggered) { - notification.timeMainActionFirstTriggered = timeSinceShown; - } - - if (timeSinceShown < this.buttonDelay) { - Services.console.logStringMessage("PopupNotifications_onButtonCommand: " + - "Button click happened before the security delay: " + - timeSinceShown + "ms"); - return; - } - - try { - notification.mainAction.callback.call(undefined, { - checkboxChecked: notificationEl.checkbox.checked - }); - } catch (error) { - Cu.reportError(error); - } - - this._remove(notification); - this._update(); - }, - - _onMenuCommand: function PopupNotifications_onMenuCommand(event) { - let target = event.originalTarget; - if (!target.action || !target.notification) - throw "menucommand target has no associated action/notification"; - - let notificationEl = target.parentElement; - event.stopPropagation(); - - try { - target.action.callback.call(undefined, { - checkboxChecked: notificationEl.checkbox.checked - }); - } catch (error) { - Cu.reportError(error); - } - - this._remove(target.notification); - this._update(); - }, - - _notify: function PopupNotifications_notify(topic) { - Services.obs.notifyObservers(null, "PopupNotifications-" + topic, ""); - }, -}; diff --git a/application/palemoon/modules/QuotaManager.jsm b/application/palemoon/modules/QuotaManager.jsm deleted file mode 100644 index 48cfe88b3..000000000 --- a/application/palemoon/modules/QuotaManager.jsm +++ /dev/null @@ -1,51 +0,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/. */ - -this.EXPORTED_SYMBOLS = ["QuotaManagerHelper"]; - -Components.utils.import('resource://gre/modules/Services.jsm'); - -const Ci = Components.interfaces; -const Cc = Components.classes; -const Cu = Components.utils; - -this.QuotaManagerHelper = { - clear: function(isShutDown) { - try { - var stord = Services.dirsvc.get("ProfD", Ci.nsIFile); - stord.append("storage"); - if (stord.exists() && stord.isDirectory()) { - var doms = {}; - for (var stor of ["default", "permanent", "temporary"]) { - var storsubd = stord.clone(); - storsubd.append(stor); - if (storsubd.exists() && storsubd.isDirectory()) { - var entries = storsubd.directoryEntries; - while(entries.hasMoreElements()) { - var host, entry = entries.getNext(); - entry.QueryInterface(Ci.nsIFile); - if ((host = /^(https?|file)\+\+\+(.+)$/.exec(entry.leafName)) !== null) { - if (isShutDown) { - entry.remove(true); - } else { - doms[host[1] + "://" + host[2]] = true; - } - } - } - } - } - var qm = Cc["@mozilla.org/dom/quota-manager-service;1"] - .getService(Ci.nsIQuotaManagerService); - for (var dom in doms) { - var uri = Services.io.newURI(dom, null, null); - let principal = Services.scriptSecurityManager - .createCodebasePrincipal(uri, {}); - qm.clearStoragesForPrincipal(principal); - } - } - } catch(er) { - Cu.reportError(er); - } - } -}; diff --git a/application/palemoon/modules/RecentWindow.jsm b/application/palemoon/modules/RecentWindow.jsm deleted file mode 100644 index 0018b502c..000000000 --- a/application/palemoon/modules/RecentWindow.jsm +++ /dev/null @@ -1,68 +0,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/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["RecentWindow"]; - -const Cu = Components.utils; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); - -#ifndef XP_WIN -#define BROKEN_WM_Z_ORDER -#endif - -this.RecentWindow = { - /* - * Get the most recent browser window. - * - * @param aOptions an object accepting the arguments for the search. - * * private: true to restrict the search to private windows - * only, false to restrict the search to non-private only. - * Omit the property to search in both groups. - * * allowPopups: true if popup windows are permissable. - */ - getMostRecentBrowserWindow: function RW_getMostRecentBrowserWindow(aOptions) { - let checkPrivacy = typeof aOptions == "object" && - "private" in aOptions; - - let allowPopups = typeof aOptions == "object" && !!aOptions.allowPopups; - - function isSuitableBrowserWindow(win) { - return (!win.closed && - (allowPopups || win.toolbar.visible) && - (!checkPrivacy || - PrivateBrowsingUtils.permanentPrivateBrowsing || - PrivateBrowsingUtils.isWindowPrivate(win) == aOptions.private)); - } - -#ifdef BROKEN_WM_Z_ORDER - let win = Services.wm.getMostRecentWindow("navigator:browser"); - - // if we're lucky, this isn't a popup, and we can just return this - if (win && !isSuitableBrowserWindow(win)) { - win = null; - let windowList = Services.wm.getEnumerator("navigator:browser"); - // this is oldest to newest, so this gets a bit ugly - while (windowList.hasMoreElements()) { - let nextWin = windowList.getNext(); - if (isSuitableBrowserWindow(nextWin)) - win = nextWin; - } - } - return win; -#else - let windowList = Services.wm.getZOrderDOMWindowEnumerator("navigator:browser", true); - while (windowList.hasMoreElements()) { - let win = windowList.getNext(); - if (isSuitableBrowserWindow(win)) - return win; - } - return null; -#endif - } -}; - diff --git a/application/palemoon/modules/SharedFrame.jsm b/application/palemoon/modules/SharedFrame.jsm deleted file mode 100644 index b9d59bfa9..000000000 --- a/application/palemoon/modules/SharedFrame.jsm +++ /dev/null @@ -1,221 +0,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/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = [ "SharedFrame" ]; - -const Ci = Components.interfaces; -const Cu = Components.utils; - -/** - * The purpose of this module is to create and group various iframe - * elements that are meant to all display the same content and only - * one at a time. This makes it possible to have the content loaded - * only once, while the other iframes can be kept as placeholders to - * quickly move the content to them through the swapFrameLoaders function - * when another one of the placeholder is meant to be displayed. - * */ - -var Frames = new Map(); - -/** - * The Frames map is the main data structure that holds information - * about the groups being tracked. Each entry's key is the group name, - * and the object holds information about what is the URL being displayed - * on that group, and what is the active element on the group (the frame that - * holds the loaded content). - * The reference to the activeFrame is a weak reference, which allows the - * frame to go away at any time, and when that happens the module considers that - * there are no active elements in that group. The group can be reactivated - * by changing the URL, calling preload again or adding a new element. - * - * - * Frames = { - * "messages-panel": { - * url: string, - * activeFrame: weakref - * } - * } - * - * Each object on the map is called a _SharedFrameGroup, which is an internal - * class of this module which does not automatically keep track of its state. This - * object should not be used externally, and all control should be handled by the - * module's functions. - */ - -function UNLOADED_URL(aStr) "data:text/html;charset=utf-8,<!-- Unloaded frame " + aStr + " -->"; - - -this.SharedFrame = { - /** - * Creates an iframe element and track it as part of the specified group - * The module must create the iframe itself because it needs to do some special - * handling for the element's src attribute. - * - * @param aGroupName the name of the group to which this frame belongs - * @param aParent the parent element to which the frame will be appended to - * @param aFrameAttributes an object with a list of attributes to set in the iframe - * before appending it to the DOM. The "src" attribute has - * special meaning here and if it's not blank it specifies - * the URL that will be initially assigned to this group - * @param aPreload optional, tells if the URL specified in the src attribute - * should be preloaded in the frame being created, in case - * it's not yet preloaded in any other frame of the group. - * This parameter has no meaning if src is blank. - */ - createFrame: function (aGroupName, aParent, aFrameAttributes, aPreload = true) { - let frame = aParent.ownerDocument.createElement("iframe"); - - for (let [key, val] of Iterator(aFrameAttributes)) { - frame.setAttribute(key, val); - } - - let src = aFrameAttributes.src; - if (!src) { - aPreload = false; - } - - let group = Frames.get(aGroupName); - - if (group) { - // If this group has already been created - - if (aPreload && !group.isAlive) { - // If aPreload is set and the group is not already loaded, load it. - // This can happen if: - // - aPreload was not used while creating the previous frames of this group, or - // - the previously active frame went dead in the meantime - group.url = src; - this.preload(aGroupName, frame); - } else { - // If aPreload is not set, or the group is already loaded in a different frame, - // there's not much that we need to do here: just create this frame as an - // inactivate placeholder - frame.setAttribute("src", UNLOADED_URL(aGroupName)); - } - - } else { - // This is the first time we hear about this group, so let's start tracking it, - // and also preload it if the src attribute was set and aPreload = true - group = new _SharedFrameGroup(src); - Frames.set(aGroupName, group); - - if (aPreload) { - this.preload(aGroupName, frame); - } else { - frame.setAttribute("src", UNLOADED_URL(aGroupName)); - } - } - - aParent.appendChild(frame); - return frame; - - }, - - /** - * Function that moves the loaded content from one active frame to - * another one that is currently a placeholder. If there's no active - * frame in the group, the content is loaded/reloaded. - * - * @param aGroupName the name of the group - * @param aTargetFrame the frame element to which the content should - * be moved to. - */ - setOwner: function (aGroupName, aTargetFrame) { - let group = Frames.get(aGroupName); - let frame = group.activeFrame; - - if (frame == aTargetFrame) { - // nothing to do here - return; - } - - if (group.isAlive) { - // Move document ownership to the desired frame, and make it the active one - frame.QueryInterface(Ci.nsIFrameLoaderOwner).swapFrameLoaders(aTargetFrame); - group.activeFrame = aTargetFrame; - } else { - // Previous owner was dead, reload the document at the new owner and make it the active one - aTargetFrame.setAttribute("src", group.url); - group.activeFrame = aTargetFrame; - } - }, - - /** - * Updates the current URL in use by this group, and loads it into the active frame. - * - * @param aGroupName the name of the group - * @param aURL the new url - */ - updateURL: function (aGroupName, aURL) { - let group = Frames.get(aGroupName); - group.url = aURL; - - if (group.isAlive) { - group.activeFrame.setAttribute("src", aURL); - } - }, - - /** - * Loads the group's url into a target frame, if the group doesn't have a currently - * active frame. - * - * @param aGroupName the name of the group - * @param aTargetFrame the frame element which should be made active and - * have the group's content loaded to - */ - preload: function (aGroupName, aTargetFrame) { - let group = Frames.get(aGroupName); - if (!group.isAlive) { - aTargetFrame.setAttribute("src", group.url); - group.activeFrame = aTargetFrame; - } - }, - - /** - * Tells if a group currently have an active element. - * - * @param aGroupName the name of the group - */ - isGroupAlive: function (aGroupName) { - return Frames.get(aGroupName).isAlive; - }, - - /** - * Forgets about this group. This function doesn't need to be used - * unless the group's name needs to be reused. - * - * @param aGroupName the name of the group - */ - forgetGroup: function (aGroupName) { - Frames.delete(aGroupName); - } -} - - -function _SharedFrameGroup(aURL) { - this.url = aURL; - this._activeFrame = null; -} - -_SharedFrameGroup.prototype = { - get isAlive() { - let frame = this.activeFrame; - return !!(frame && - frame.contentDocument && - frame.contentDocument.location); - }, - - get activeFrame() { - return this._activeFrame && - this._activeFrame.get(); - }, - - set activeFrame(aActiveFrame) { - this._activeFrame = aActiveFrame - ? Cu.getWeakReference(aActiveFrame) - : null; - } -} diff --git a/application/palemoon/modules/Windows8WindowFrameColor.jsm b/application/palemoon/modules/Windows8WindowFrameColor.jsm deleted file mode 100644 index e7a447db2..000000000 --- a/application/palemoon/modules/Windows8WindowFrameColor.jsm +++ /dev/null @@ -1,53 +0,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/. */ - -"use strict"; -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -this.EXPORTED_SYMBOLS = ["Windows8WindowFrameColor"]; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/WindowsRegistry.jsm"); - -var Windows8WindowFrameColor = { - _windowFrameColor: null, - - get_win8: function() { - if (this._windowFrameColor) - return this._windowFrameColor; - - const HKCU = Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER; - const dwmKey = "Software\\Microsoft\\Windows\\DWM"; - - // Window frame base color component values when Color Intensity is at 0. - let frameBaseColor = 217; - - let windowFrameColor = WindowsRegistry.readRegKey(HKCU, dwmKey, - "ColorizationColor"); - if (windowFrameColor == undefined) { - // Return the default color if unset or colorization not used - return this._windowFrameColor = [frameBaseColor, frameBaseColor, frameBaseColor]; - } - // The color returned from the Registry is in decimal form. - let windowFrameColorHex = windowFrameColor.toString(16); - // Zero-pad the number just to make sure that it is 8 digits. - windowFrameColorHex = ("00000000" + windowFrameColorHex).substr(-8); - let windowFrameColorArray = windowFrameColorHex.match(/../g); - let [unused, fgR, fgG, fgB] = windowFrameColorArray.map(function(val) parseInt(val, 16)); - let windowFrameColorBalance = WindowsRegistry.readRegKey(HKCU, dwmKey, - "ColorizationColorBalance"); - // Default to balance=78 if reg key isn't defined - if (windowFrameColorBalance == undefined) { - windowFrameColorBalance = 78; - } - let alpha = windowFrameColorBalance / 100; - - // Alpha-blend the foreground color with the frame base color. - let r = Math.round(fgR * alpha + frameBaseColor * (1 - alpha)); - let g = Math.round(fgG * alpha + frameBaseColor * (1 - alpha)); - let b = Math.round(fgB * alpha + frameBaseColor * (1 - alpha)); - return this._windowFrameColor = [r, g, b]; - } -}; diff --git a/application/palemoon/modules/WindowsJumpLists.jsm b/application/palemoon/modules/WindowsJumpLists.jsm deleted file mode 100644 index e7f785519..000000000 --- a/application/palemoon/modules/WindowsJumpLists.jsm +++ /dev/null @@ -1,581 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); - -/** - * Constants - */ - -const Cc = Components.classes; -const Ci = Components.interfaces; - -// Stop updating jumplists after some idle time. -const IDLE_TIMEOUT_SECONDS = 5 * 60; - -// Prefs -const PREF_TASKBAR_BRANCH = "browser.taskbar.lists."; -const PREF_TASKBAR_ENABLED = "enabled"; -const PREF_TASKBAR_ITEMCOUNT = "maxListItemCount"; -const PREF_TASKBAR_FREQUENT = "frequent.enabled"; -const PREF_TASKBAR_RECENT = "recent.enabled"; -const PREF_TASKBAR_TASKS = "tasks.enabled"; -const PREF_TASKBAR_REFRESH = "refreshInSeconds"; - -// Hash keys for pendingStatements. -const LIST_TYPE = { - FREQUENT: 0 -, RECENT: 1 -} - -/** - * Exports - */ - -this.EXPORTED_SYMBOLS = [ - "WinTaskbarJumpList", -]; - -/** - * Smart getters - */ - -XPCOMUtils.defineLazyGetter(this, "_prefs", function() { - return Services.prefs.getBranch(PREF_TASKBAR_BRANCH); -}); - -XPCOMUtils.defineLazyGetter(this, "_stringBundle", function() { - return Services.strings - .createBundle("chrome://browser/locale/taskbar.properties"); -}); - -XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() { - Components.utils.import("resource://gre/modules/PlacesUtils.jsm"); - return PlacesUtils; -}); - -XPCOMUtils.defineLazyGetter(this, "NetUtil", function() { - Components.utils.import("resource://gre/modules/NetUtil.jsm"); - return NetUtil; -}); - -XPCOMUtils.defineLazyServiceGetter(this, "_idle", - "@mozilla.org/widget/idleservice;1", - "nsIIdleService"); - -XPCOMUtils.defineLazyServiceGetter(this, "_taskbarService", - "@mozilla.org/windows-taskbar;1", - "nsIWinTaskbar"); - -XPCOMUtils.defineLazyServiceGetter(this, "_winShellService", - "@mozilla.org/browser/shell-service;1", - "nsIWindowsShellService"); - -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm"); - -/** - * Global functions - */ - -function _getString(name) { - return _stringBundle.GetStringFromName(name); -} - -///////////////////////////////////////////////////////////////////////////// -// Task list configuration data object. - -var tasksCfg = [ - /** - * Task configuration options: title, description, args, iconIndex, open, close. - * - * title - Task title displayed in the list. (strings in the table are temp fillers.) - * description - Tooltip description on the list item. - * args - Command line args to invoke the task. - * iconIndex - Optional win icon index into the main application for the - * list item. - * open - Boolean indicates if the command should be visible after the browser opens. - * close - Boolean indicates if the command should be visible after the browser closes. - */ - // Open new tab - { - get title() _getString("taskbar.tasks.newTab.label"), - get description() _getString("taskbar.tasks.newTab.description"), - args: "-new-tab about:blank", - iconIndex: 3, // New window icon - open: true, - close: true, // The jump list already has an app launch icon, but - // we don't always update the list on shutdown. - // Thus true for consistency. - }, - - // Open new window - { - get title() _getString("taskbar.tasks.newWindow.label"), - get description() _getString("taskbar.tasks.newWindow.description"), - args: "-browser", - iconIndex: 2, // New tab icon - open: true, - close: true, // No point, but we don't always update the list on - // shutdown. Thus true for consistency. - }, - - // Open new private window - { - get title() _getString("taskbar.tasks.newPrivateWindow.label"), - get description() _getString("taskbar.tasks.newPrivateWindow.description"), - args: "-private-window", - iconIndex: 4, // Private browsing mode icon - open: true, - close: true, // No point, but we don't always update the list on - // shutdown. Thus true for consistency. - }, -]; - -///////////////////////////////////////////////////////////////////////////// -// Implementation - -this.WinTaskbarJumpList = -{ - _builder: null, - _tasks: null, - _shuttingDown: false, - - /** - * Startup, shutdown, and update - */ - - startup: function WTBJL_startup() { - // exit if this isn't win7 or higher. - if (!this._initTaskbar()) - return; - - // Win shell shortcut maintenance. If we've gone through an update, - // this will update any pinned taskbar shortcuts. Not specific to - // jump lists, but this was a convienent place to call it. - try { - // dev builds may not have helper.exe, ignore failures. - this._shortcutMaintenance(); - } catch (ex) { - } - - // Store our task list config data - this._tasks = tasksCfg; - - // retrieve taskbar related prefs. - this._refreshPrefs(); - - // observer for private browsing and our prefs branch - this._initObs(); - - // jump list refresh timer - this._updateTimer(); - }, - - update: function WTBJL_update() { - // are we disabled via prefs? don't do anything! - if (!this._enabled) - return; - - // do what we came here to do, update the taskbar jumplist - this._buildList(); - }, - - _shutdown: function WTBJL__shutdown() { - this._shuttingDown = true; - - // Correctly handle a clear history on shutdown. If there are no - // entries be sure to empty all history lists. Luckily Places caches - // this value, so it's a pretty fast call. - if (!PlacesUtils.history.hasHistoryEntries) { - this.update(); - } - - this._free(); - }, - - _shortcutMaintenance: function WTBJL__maintenace() { - _winShellService.shortcutMaintenance(); - }, - - /** - * List building - * - * @note Async builders must add their mozIStoragePendingStatement to - * _pendingStatements object, using a different LIST_TYPE entry for - * each statement. Once finished they must remove it and call - * commitBuild(). When there will be no more _pendingStatements, - * commitBuild() will commit for real. - */ - - _pendingStatements: {}, - _hasPendingStatements: function WTBJL__hasPendingStatements() { - return Object.keys(this._pendingStatements).length > 0; - }, - - _buildList: function WTBJL__buildList() { - if (this._hasPendingStatements()) { - // We were requested to update the list while another update was in - // progress, this could happen at shutdown, idle or privatebrowsing. - // Abort the current list building. - for (let listType in this._pendingStatements) { - this._pendingStatements[listType].cancel(); - delete this._pendingStatements[listType]; - } - this._builder.abortListBuild(); - } - - // anything to build? - if (!this._showFrequent && !this._showRecent && !this._showTasks) { - // don't leave the last list hanging on the taskbar. - this._deleteActiveJumpList(); - return; - } - - if (!this._startBuild()) - return; - - if (this._showTasks) - this._buildTasks(); - - // Space for frequent items takes priority over recent. - if (this._showFrequent) - this._buildFrequent(); - - if (this._showRecent) - this._buildRecent(); - - this._commitBuild(); - }, - - /** - * Taskbar api wrappers - */ - - _startBuild: function WTBJL__startBuild() { - var removedItems = Cc["@mozilla.org/array;1"]. - createInstance(Ci.nsIMutableArray); - this._builder.abortListBuild(); - if (this._builder.initListBuild(removedItems)) { - // Prior to building, delete removed items from history. - this._clearHistory(removedItems); - return true; - } - return false; - }, - - _commitBuild: function WTBJL__commitBuild() { - if (!this._hasPendingStatements() && !this._builder.commitListBuild()) { - this._builder.abortListBuild(); - } - }, - - _buildTasks: function WTBJL__buildTasks() { - var items = Cc["@mozilla.org/array;1"]. - createInstance(Ci.nsIMutableArray); - this._tasks.forEach(function (task) { - if ((this._shuttingDown && !task.close) || (!this._shuttingDown && !task.open)) - return; - var item = this._getHandlerAppItem(task.title, task.description, - task.args, task.iconIndex, null); - items.appendElement(item, false); - }, this); - - if (items.length > 0) - this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_TASKS, items); - }, - - _buildCustom: function WTBJL__buildCustom(title, items) { - if (items.length > 0) - this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_CUSTOMLIST, items, title); - }, - - _buildFrequent: function WTBJL__buildFrequent() { - // If history is empty, just bail out. - if (!PlacesUtils.history.hasHistoryEntries) { - return; - } - - // Windows supports default frequent and recent lists, - // but those depend on internal windows visit tracking - // which we don't populate. So we build our own custom - // frequent and recent lists using our nav history data. - - var items = Cc["@mozilla.org/array;1"]. - createInstance(Ci.nsIMutableArray); - // track frequent items so that we don't add them to - // the recent list. - this._frequentHashList = []; - - this._pendingStatements[LIST_TYPE.FREQUENT] = this._getHistoryResults( - Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING, - this._maxItemCount, - function (aResult) { - if (!aResult) { - delete this._pendingStatements[LIST_TYPE.FREQUENT]; - // The are no more results, build the list. - this._buildCustom(_getString("taskbar.frequent.label"), items); - this._commitBuild(); - return; - } - - let title = aResult.title || aResult.uri; - let faviconPageUri = Services.io.newURI(aResult.uri, null, null); - let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1, - faviconPageUri); - items.appendElement(shortcut, false); - this._frequentHashList.push(aResult.uri); - }, - this - ); - }, - - _buildRecent: function WTBJL__buildRecent() { - // If history is empty, just bail out. - if (!PlacesUtils.history.hasHistoryEntries) { - return; - } - - var items = Cc["@mozilla.org/array;1"]. - createInstance(Ci.nsIMutableArray); - // Frequent items will be skipped, so we select a double amount of - // entries and stop fetching results at _maxItemCount. - var count = 0; - - this._pendingStatements[LIST_TYPE.RECENT] = this._getHistoryResults( - Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING, - this._maxItemCount * 2, - function (aResult) { - if (!aResult) { - // The are no more results, build the list. - this._buildCustom(_getString("taskbar.recent.label"), items); - delete this._pendingStatements[LIST_TYPE.RECENT]; - this._commitBuild(); - return; - } - - if (count >= this._maxItemCount) { - return; - } - - // Do not add items to recent that have already been added to frequent. - if (this._frequentHashList && - this._frequentHashList.indexOf(aResult.uri) != -1) { - return; - } - - let title = aResult.title || aResult.uri; - let faviconPageUri = Services.io.newURI(aResult.uri, null, null); - let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1, - faviconPageUri); - items.appendElement(shortcut, false); - count++; - }, - this - ); - }, - - _deleteActiveJumpList: function WTBJL__deleteAJL() { - this._builder.deleteActiveList(); - }, - - /** - * Jump list item creation helpers - */ - - _getHandlerAppItem: function WTBJL__getHandlerAppItem(name, description, - args, iconIndex, - faviconPageUri) { - var file = Services.dirsvc.get("XREExeF", Ci.nsILocalFile); - - var handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]. - createInstance(Ci.nsILocalHandlerApp); - handlerApp.executable = file; - // handlers default to the leaf name if a name is not specified - if (name && name.length != 0) - handlerApp.name = name; - handlerApp.detailedDescription = description; - handlerApp.appendParameter(args); - - var item = Cc["@mozilla.org/windows-jumplistshortcut;1"]. - createInstance(Ci.nsIJumpListShortcut); - item.app = handlerApp; - item.iconIndex = iconIndex; - item.faviconPageUri = faviconPageUri; - return item; - }, - - _getSeparatorItem: function WTBJL__getSeparatorItem() { - var item = Cc["@mozilla.org/windows-jumplistseparator;1"]. - createInstance(Ci.nsIJumpListSeparator); - return item; - }, - - /** - * Nav history helpers - */ - - _getHistoryResults: - function WTBLJL__getHistoryResults(aSortingMode, aLimit, aCallback, aScope) { - var options = PlacesUtils.history.getNewQueryOptions(); - options.maxResults = aLimit; - options.sortingMode = aSortingMode; - var query = PlacesUtils.history.getNewQuery(); - - // Return the pending statement to the caller, to allow cancelation. - return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) - .asyncExecuteLegacyQueries([query], 1, options, { - handleResult: function (aResultSet) { - for (let row; (row = aResultSet.getNextRow());) { - try { - aCallback.call(aScope, - { uri: row.getResultByIndex(1) - , title: row.getResultByIndex(2) - }); - } catch (e) {} - } - }, - handleError: function (aError) { - Components.utils.reportError( - "Async execution error (" + aError.result + "): " + aError.message); - }, - handleCompletion: function (aReason) { - aCallback.call(WinTaskbarJumpList, null); - }, - }); - }, - - _clearHistory: function WTBJL__clearHistory(items) { - if (!items) - return; - var URIsToRemove = []; - var e = items.enumerate(); - while (e.hasMoreElements()) { - let oldItem = e.getNext().QueryInterface(Ci.nsIJumpListShortcut); - if (oldItem) { - try { // in case we get a bad uri - let uriSpec = oldItem.app.getParameter(0); - URIsToRemove.push(NetUtil.newURI(uriSpec)); - } catch (err) { } - } - } - if (URIsToRemove.length > 0) { - PlacesUtils.bhistory.removePages(URIsToRemove, URIsToRemove.length, true); - } - }, - - /** - * Prefs utilities - */ - - _refreshPrefs: function WTBJL__refreshPrefs() { - this._enabled = _prefs.getBoolPref(PREF_TASKBAR_ENABLED); - this._showFrequent = _prefs.getBoolPref(PREF_TASKBAR_FREQUENT); - this._showRecent = _prefs.getBoolPref(PREF_TASKBAR_RECENT); - this._showTasks = _prefs.getBoolPref(PREF_TASKBAR_TASKS); - this._maxItemCount = _prefs.getIntPref(PREF_TASKBAR_ITEMCOUNT); - }, - - /** - * Init and shutdown utilities - */ - - _initTaskbar: function WTBJL__initTaskbar() { - this._builder = _taskbarService.createJumpListBuilder(); - if (!this._builder || !this._builder.available) - return false; - - return true; - }, - - _initObs: function WTBJL__initObs() { - // If the browser is closed while in private browsing mode, the "exit" - // notification is fired on quit-application-granted. - // History cleanup can happen at profile-change-teardown. - Services.obs.addObserver(this, "profile-before-change", false); - Services.obs.addObserver(this, "browser:purge-session-history", false); - _prefs.addObserver("", this, false); - }, - - _freeObs: function WTBJL__freeObs() { - Services.obs.removeObserver(this, "profile-before-change"); - Services.obs.removeObserver(this, "browser:purge-session-history"); - _prefs.removeObserver("", this); - }, - - _updateTimer: function WTBJL__updateTimer() { - if (this._enabled && !this._shuttingDown && !this._timer) { - this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this._timer.initWithCallback(this, - _prefs.getIntPref(PREF_TASKBAR_REFRESH)*1000, - this._timer.TYPE_REPEATING_SLACK); - } - else if ((!this._enabled || this._shuttingDown) && this._timer) { - this._timer.cancel(); - delete this._timer; - } - }, - - _hasIdleObserver: false, - _updateIdleObserver: function WTBJL__updateIdleObserver() { - if (this._enabled && !this._shuttingDown && !this._hasIdleObserver) { - _idle.addIdleObserver(this, IDLE_TIMEOUT_SECONDS); - this._hasIdleObserver = true; - } - else if ((!this._enabled || this._shuttingDown) && this._hasIdleObserver) { - _idle.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS); - this._hasIdleObserver = false; - } - }, - - _free: function WTBJL__free() { - this._freeObs(); - this._updateTimer(); - this._updateIdleObserver(); - delete this._builder; - }, - - /** - * Notification handlers - */ - - notify: function WTBJL_notify(aTimer) { - // Add idle observer on the first notification so it doesn't hit startup. - this._updateIdleObserver(); - this.update(); - }, - - observe: function WTBJL_observe(aSubject, aTopic, aData) { - switch (aTopic) { - case "nsPref:changed": - if (this._enabled == true && !_prefs.getBoolPref(PREF_TASKBAR_ENABLED)) - this._deleteActiveJumpList(); - this._refreshPrefs(); - this._updateTimer(); - this._updateIdleObserver(); - this.update(); - break; - - case "profile-before-change": - this._shutdown(); - break; - - case "browser:purge-session-history": - this.update(); - break; - case "idle": - if (this._timer) { - this._timer.cancel(); - delete this._timer; - } - break; - - case "back": - this._updateTimer(); - break; - } - }, -}; diff --git a/application/palemoon/modules/WindowsPreviewPerTab.jsm b/application/palemoon/modules/WindowsPreviewPerTab.jsm deleted file mode 100644 index 4b5030ad4..000000000 --- a/application/palemoon/modules/WindowsPreviewPerTab.jsm +++ /dev/null @@ -1,861 +0,0 @@ -/* vim: se cin sw=2 ts=2 et filetype=javascript : - * 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/. */ -/* - * This module implements the front end behavior for AeroPeek. The taskbar - * allows an application to expose its tabbed interface by showing thumbnail - * previews rather than the default window preview. - * Additionally, when a user hovers over a thumbnail (tab or window), - * they are shown a live preview of the window (or tab + its containing window). - * - * In Windows 7, a title, icon, close button and optional toolbar are shown for - * each preview. This feature does not make use of the toolbar. For window - * previews, the title is the window title and the icon the window icon. For - * tab previews, the title is the page title and the page's favicon. In both - * cases, the close button "does the right thing." - * - * The primary objects behind this feature are nsITaskbarTabPreview and - * nsITaskbarPreviewController. Each preview has a controller. The controller - * responds to the user's interactions on the taskbar and provides the required - * data to the preview for determining the size of the tab and thumbnail. The - * PreviewController class implements this interface. The preview will request - * the controller to provide a thumbnail or preview when the user interacts with - * the taskbar. To reduce the overhead of drawing the tab area, the controller - * implementation caches the tab's contents in a <canvas> element. If no - * previews or thumbnails have been requested for some time, the controller will - * discard its cached tab contents. - * - * Screen real estate is limited so when there are too many thumbnails to fit - * on the screen, the taskbar stops displaying thumbnails and instead displays - * just the title, icon and close button in a similar fashion to previous - * versions of the taskbar. If there are still too many previews to fit on the - * screen, the taskbar resorts to a scroll up and scroll down button pair to let - * the user scroll through the list of tabs. Since this is undoubtedly - * inconvenient for users with many tabs, the AeroPeek objects turns off all of - * the tab previews. This tells the taskbar to revert to one preview per window. - * If the number of tabs falls below this magic threshold, the preview-per-tab - * behavior returns. There is no reliable way to determine when the scroll - * buttons appear on the taskbar, so a magic pref-controlled number determines - * when this threshold has been crossed. - */ -this.EXPORTED_SYMBOLS = ["AeroPeek"]; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/NetUtil.jsm"); -Cu.import("resource://gre/modules/PlacesUtils.jsm"); -Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -// Pref to enable/disable preview-per-tab -const TOGGLE_PREF_NAME = "browser.taskbar.previews.enable"; -// Pref to determine the magic auto-disable threshold -const DISABLE_THRESHOLD_PREF_NAME = "browser.taskbar.previews.max"; -// Pref to control the time in seconds that tab contents live in the cache -const CACHE_EXPIRATION_TIME_PREF_NAME = "browser.taskbar.previews.cachetime"; - -const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1"; - -// Various utility properties -XPCOMUtils.defineLazyServiceGetter(this, "imgTools", - "@mozilla.org/image/tools;1", - "imgITools"); -XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", - "resource://gre/modules/PageThumbs.jsm"); - -// nsIURI -> imgIContainer -function _imageFromURI(uri, privateMode, callback) { - let channel = NetUtil.newChannel({ - uri: uri, - loadUsingSystemPrincipal: true, - contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE - }); - - try { - channel.QueryInterface(Ci.nsIPrivateBrowsingChannel); - channel.setPrivate(privateMode); - } catch (e) { - // Ignore channels which do not support nsIPrivateBrowsingChannel - } - NetUtil.asyncFetch(channel, function(inputStream, resultCode) { - if (!Components.isSuccessCode(resultCode)) - return; - try { - let out_img = { value: null }; - imgTools.decodeImageData(inputStream, channel.contentType, out_img); - callback(out_img.value); - } catch (e) { - // We failed, so use the default favicon (only if this wasn't the default - // favicon). - let defaultURI = PlacesUtils.favicons.defaultFavicon; - if (!defaultURI.equals(uri)) - _imageFromURI(defaultURI, privateMode, callback); - } - }); -} - -// string? -> imgIContainer -function getFaviconAsImage(iconurl, privateMode, callback) { - if (iconurl) { - _imageFromURI(NetUtil.newURI(iconurl), privateMode, callback); - } else { - _imageFromURI(PlacesUtils.favicons.defaultFavicon, privateMode, callback); - } -} - -// Snaps the given rectangle to be pixel-aligned at the given scale -function snapRectAtScale(r, scale) { - let x = Math.floor(r.x * scale); - let y = Math.floor(r.y * scale); - let width = Math.ceil((r.x + r.width) * scale) - x; - let height = Math.ceil((r.y + r.height) * scale) - y; - - r.x = x / scale; - r.y = y / scale; - r.width = width / scale; - r.height = height / scale; -} - -// PreviewController - -/* - * This class manages the behavior of thumbnails and previews. It has the following - * responsibilities: - * 1) Responding to requests from Windows taskbar for a thumbnail or window - * preview. - * 2) Listening for DOM events that result in a thumbnail or window preview needing - * to be refreshed, and communicating this to the taskbar. - * 3) Handling queryies and returning new thumbnail or window preview images to the - * taskbar through PageThumbs. - * - * @param win - * The TabWindow (see below) that owns the preview that this controls - * @param tab - * The <tab> that this preview is associated with - */ -function PreviewController(win, tab) { - this.win = win; - this.tab = tab; - this.linkedBrowser = tab.linkedBrowser; - this.preview = this.win.createTabPreview(this); - - this.tab.addEventListener("TabAttrModified", this, false); - - XPCOMUtils.defineLazyGetter(this, "canvasPreview", function () { - let canvas = PageThumbs.createCanvas(); - canvas.mozOpaque = true; - return canvas; - }); -} - -PreviewController.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITaskbarPreviewController, - Ci.nsIDOMEventListener]), - - destroy: function () { - this.tab.removeEventListener("TabAttrModified", this, false); - - // Break cycles, otherwise we end up leaking the window with everything - // attached to it. - delete this.win; - delete this.preview; - }, - - get wrappedJSObject() { - return this; - }, - - // Resizes the canvasPreview to 0x0, essentially freeing its memory. - resetCanvasPreview: function () { - this.canvasPreview.width = 0; - this.canvasPreview.height = 0; - }, - - /** - * Set the canvas dimensions. - */ - resizeCanvasPreview: function (aRequestedWidth, aRequestedHeight) { - this.canvasPreview.width = aRequestedWidth; - this.canvasPreview.height = aRequestedHeight; - }, - - - get zoom() { - // Note that winutils.fullZoom accounts for "quantization" of the zoom factor - // from nsIContentViewer due to conversion through appUnits. - // We do -not- want screenPixelsPerCSSPixel here, because that would -also- - // incorporate any scaling that is applied due to hi-dpi resolution options. - return this.tab.linkedBrowser.fullZoom; - }, - - get screenPixelsPerCSSPixel() { - let chromeWin = this.tab.ownerGlobal; - let windowUtils = chromeWin.getInterface(Ci.nsIDOMWindowUtils); - return windowUtils.screenPixelsPerCSSPixel; - }, - - get browserDims() { - return this.tab.linkedBrowser.getBoundingClientRect(); - }, - - cacheBrowserDims: function () { - let dims = this.browserDims; - this._cachedWidth = dims.width; - this._cachedHeight = dims.height; - }, - - testCacheBrowserDims: function () { - let dims = this.browserDims; - return this._cachedWidth == dims.width && - this._cachedHeight == dims.height; - }, - - /** - * Capture a new thumbnail image for this preview. Called by the controller - * in response to a request for a new thumbnail image. - */ - updateCanvasPreview: function (aFullScale, aCallback) { - // Update our cached browser dims so that delayed resize - // events don't trigger another invalidation if this tab becomes active. - this.cacheBrowserDims(); - PageThumbs.captureToCanvas(this.linkedBrowser, this.canvasPreview, - aCallback, { fullScale: aFullScale }); - // If we're updating the canvas, then we're in the middle of a peek so - // don't discard the cache of previews. - AeroPeek.resetCacheTimer(); - }, - - updateTitleAndTooltip: function () { - let title = this.win.tabbrowser.getWindowTitleForBrowser(this.linkedBrowser); - this.preview.title = title; - this.preview.tooltip = title; - }, - - // nsITaskbarPreviewController - - // window width and height, not browser - get width() { - return this.win.width; - }, - - // window width and height, not browser - get height() { - return this.win.height; - }, - - get thumbnailAspectRatio() { - let browserDims = this.browserDims; - // Avoid returning 0 - let tabWidth = browserDims.width || 1; - // Avoid divide by 0 - let tabHeight = browserDims.height || 1; - return tabWidth / tabHeight; - }, - - /** - * Responds to taskbar requests for window previews. Returns the results asynchronously - * through updateCanvasPreview. - * - * @param aTaskbarCallback nsITaskbarPreviewCallback results callback - */ - requestPreview: function (aTaskbarCallback) { - // Grab a high res content preview - this.resetCanvasPreview(); - this.updateCanvasPreview(true, (aPreviewCanvas) => { - let winWidth = this.win.width; - let winHeight = this.win.height; - - let composite = PageThumbs.createCanvas(); - - // Use transparency, Aero glass is drawn black without it. - composite.mozOpaque = false; - - let ctx = composite.getContext('2d'); - let scale = this.screenPixelsPerCSSPixel / this.zoom; - - composite.width = winWidth * scale; - composite.height = winHeight * scale; - - ctx.save(); - ctx.scale(scale, scale); - - // Draw chrome. Note we currently do not get scrollbars for remote frames - // in the image above. - ctx.drawWindow(this.win.win, 0, 0, winWidth, winHeight, "rgba(0,0,0,0)"); - - // Draw the content are into the composite canvas at the right location. - ctx.drawImage(aPreviewCanvas, this.browserDims.x, this.browserDims.y, - aPreviewCanvas.width, aPreviewCanvas.height); - ctx.restore(); - - // Deliver the resulting composite canvas to Windows - this.win.tabbrowser.previewTab(this.tab, function () { - aTaskbarCallback.done(composite, false); - }); - }); - }, - - /** - * Responds to taskbar requests for tab thumbnails. Returns the results asynchronously - * through updateCanvasPreview. - * - * Note Windows requests a specific width and height here, if the resulting thumbnail - * does not match these dimensions thumbnail display will fail. - * - * @param aTaskbarCallback nsITaskbarPreviewCallback results callback - * @param aRequestedWidth width of the requested thumbnail - * @param aRequestedHeight height of the requested thumbnail - */ - requestThumbnail: function (aTaskbarCallback, aRequestedWidth, aRequestedHeight) { - this.resizeCanvasPreview(aRequestedWidth, aRequestedHeight); - this.updateCanvasPreview(false, (aThumbnailCanvas) => { - aTaskbarCallback.done(aThumbnailCanvas, false); - }); - }, - - // Event handling - - onClose: function () { - this.win.tabbrowser.removeTab(this.tab); - }, - - onActivate: function () { - this.win.tabbrowser.selectedTab = this.tab; - - // Accept activation - this will restore the browser window - // if it's minimized - return true; - }, - - // nsIDOMEventListener - handleEvent: function (evt) { - switch (evt.type) { - case "TabAttrModified": - this.updateTitleAndTooltip(); - break; - } - } -}; - -XPCOMUtils.defineLazyGetter(PreviewController.prototype, "canvasPreviewFlags", - function () { let canvasInterface = Ci.nsIDOMCanvasRenderingContext2D; - return canvasInterface.DRAWWINDOW_DRAW_VIEW - | canvasInterface.DRAWWINDOW_DRAW_CARET - | canvasInterface.DRAWWINDOW_ASYNC_DECODE_IMAGES - | canvasInterface.DRAWWINDOW_DO_NOT_FLUSH; -}); - -// TabWindow - -/* - * This class monitors a browser window for changes to its tabs - * - * @param win - * The nsIDOMWindow browser window - */ -function TabWindow(win) { - this.win = win; - this.tabbrowser = win.gBrowser; - - this.previews = new Map(); - - for (let i = 0; i < this.tabEvents.length; i++) - this.tabbrowser.tabContainer.addEventListener(this.tabEvents[i], this, false); - - for (let i = 0; i < this.winEvents.length; i++) - this.win.addEventListener(this.winEvents[i], this, false); - - this.tabbrowser.addTabsProgressListener(this); - - AeroPeek.windows.push(this); - let tabs = this.tabbrowser.tabs; - for (let i = 0; i < tabs.length; i++) - this.newTab(tabs[i]); - - this.updateTabOrdering(); - AeroPeek.checkPreviewCount(); -} - -TabWindow.prototype = { - _enabled: false, - _cachedWidth: 0, - _cachedHeight: 0, - tabEvents: ["TabOpen", "TabClose", "TabSelect", "TabMove"], - winEvents: ["resize"], - - destroy: function () { - this._destroying = true; - - let tabs = this.tabbrowser.tabs; - - this.tabbrowser.removeTabsProgressListener(this); - - for (let i = 0; i < this.winEvents.length; i++) - this.win.removeEventListener(this.winEvents[i], this, false); - - for (let i = 0; i < this.tabEvents.length; i++) - this.tabbrowser.tabContainer.removeEventListener(this.tabEvents[i], this, false); - - for (let i = 0; i < tabs.length; i++) - this.removeTab(tabs[i]); - - let idx = AeroPeek.windows.indexOf(this.win.gTaskbarTabGroup); - AeroPeek.windows.splice(idx, 1); - AeroPeek.checkPreviewCount(); - }, - - get width () { - return this.win.innerWidth; - }, - get height () { - return this.win.innerHeight; - }, - - cacheDims: function () { - this._cachedWidth = this.width; - this._cachedHeight = this.height; - }, - - testCacheDims: function () { - return this._cachedWidth == this.width && this._cachedHeight == this.height; - }, - - // Invoked when the given tab is added to this window - newTab: function (tab) { - let controller = new PreviewController(this, tab); - // It's OK to add the preview now while the favicon still loads. - this.previews.set(tab, controller.preview); - AeroPeek.addPreview(controller.preview); - // updateTitleAndTooltip relies on having controller.preview which is lazily resolved. - // Now that we've updated this.previews, it will resolve successfully. - controller.updateTitleAndTooltip(); - }, - - createTabPreview: function (controller) { - let docShell = this.win - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell); - let preview = AeroPeek.taskbar.createTaskbarTabPreview(docShell, controller); - preview.visible = AeroPeek.enabled; - preview.active = this.tabbrowser.selectedTab == controller.tab; - this.onLinkIconAvailable(controller.tab.linkedBrowser, - controller.tab.getAttribute("image")); - return preview; - }, - - // Invoked when the given tab is closed - removeTab: function (tab) { - let preview = this.previewFromTab(tab); - preview.active = false; - preview.visible = false; - preview.move(null); - preview.controller.wrappedJSObject.destroy(); - - this.previews.delete(tab); - AeroPeek.removePreview(preview); - }, - - get enabled () { - return this._enabled; - }, - - set enabled (enable) { - this._enabled = enable; - // Because making a tab visible requires that the tab it is next to be - // visible, it is far simpler to unset the 'next' tab and recreate them all - // at once. - for (let [, preview] of this.previews) { - preview.move(null); - preview.visible = enable; - } - this.updateTabOrdering(); - }, - - previewFromTab: function (tab) { - return this.previews.get(tab); - }, - - updateTabOrdering: function () { - let previews = this.previews; - let tabs = this.tabbrowser.tabs; - - // Previews are internally stored using a map, so we need to iterate the - // tabbrowser's array of tabs to retrieve previews in the same order. - let inorder = []; - for (let t of tabs) { - if (previews.has(t)) { - inorder.push(previews.get(t)); - } - } - - // Since the internal taskbar array has not yet been updated we must force - // on it the sorting order of our local array. To do so we must walk - // the local array backwards, otherwise we would send move requests in the - // wrong order. See bug 522610 for details. - for (let i = inorder.length - 1; i >= 0; i--) { - inorder[i].move(inorder[i + 1] || null); - } - }, - - // nsIDOMEventListener - handleEvent: function (evt) { - let tab = evt.originalTarget; - switch (evt.type) { - case "TabOpen": - this.newTab(tab); - this.updateTabOrdering(); - break; - case "TabClose": - this.removeTab(tab); - this.updateTabOrdering(); - break; - case "TabSelect": - this.previewFromTab(tab).active = true; - break; - case "TabMove": - this.updateTabOrdering(); - break; - case "resize": - if (!AeroPeek._prefenabled) - return; - this.onResize(); - break; - } - }, - - // Set or reset a timer that will invalidate visible thumbnails soon. - setInvalidationTimer: function () { - if (!this.invalidateTimer) { - this.invalidateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - } - this.invalidateTimer.cancel(); - - // delay 1 second before invalidating - this.invalidateTimer.initWithCallback(() => { - // invalidate every preview. note the internal implementation of - // invalidate ignores thumbnails that aren't visible. - this.previews.forEach(function (aPreview) { - let controller = aPreview.controller.wrappedJSObject; - if (!controller.testCacheBrowserDims()) { - controller.cacheBrowserDims(); - aPreview.invalidate(); - } - }); - }, 1000, Ci.nsITimer.TYPE_ONE_SHOT); - }, - - onResize: function () { - // Specific to a window. - - // Call invalidate on each tab thumbnail so that Windows will request an - // updated image. However don't do this repeatedly across multiple resize - // events triggered during window border drags. - - if (this.testCacheDims()) { - return; - } - - // update the window dims on our TabWindow object. - this.cacheDims(); - - // invalidate soon - this.setInvalidationTimer(); - }, - - invalidateTabPreview: function(aBrowser) { - for (let [tab, preview] of this.previews) { - if (aBrowser == tab.linkedBrowser) { - preview.invalidate(); - break; - } - } - }, - - // Browser progress listener - - onLocationChange: function (aBrowser) { - // I'm not sure we need this, onStateChange does a really good job - // of picking up page changes. - // this.invalidateTabPreview(aBrowser); - }, - - onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { - if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP && - aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) { - this.invalidateTabPreview(aBrowser); - } - }, - - directRequestProtocols: new Set([ - "file", "chrome", "resource", "about" - ]), - onLinkIconAvailable: function (aBrowser, aIconURL) { - let self = this; - let requestURL = null; - if (aIconURL) { - let shouldRequestFaviconURL = true; - try { - let urlObject = NetUtil.newURI(aIconURL); - shouldRequestFaviconURL = - !this.directRequestProtocols.has(urlObject.scheme); - } catch (ex) {} - - requestURL = shouldRequestFaviconURL ? - "moz-anno:favicon:" + aIconURL : - aIconURL; - } - let isDefaultFavicon = !requestURL; - getFaviconAsImage( - requestURL, - PrivateBrowsingUtils.isWindowPrivate(self.win), - img => { - let index = self.tabbrowser.browsers.indexOf(aBrowser); - // Only add it if we've found the index and the URI is still the same. - // The tab could have closed, and there's no guarantee the icons - // will have finished fetching 'in order'. - if (index != -1) { - let tab = self.tabbrowser.tabs[index]; - let preview = self.previews.get(tab); - if (tab.getAttribute("image") == aIconURL || - (!preview.icon && isDefaultFavicon)) { - preview.icon = img; - } - } - } - ); - } -} - -// AeroPeek - -/* - * This object acts as global storage and external interface for this feature. - * It maintains the values of the prefs. - */ -this.AeroPeek = { - available: false, - // Does the pref say we're enabled? - __prefenabled: false, - - _enabled: true, - - initialized: false, - - // nsITaskbarTabPreview array - previews: [], - - // TabWindow array - windows: [], - - // nsIWinTaskbar service - taskbar: null, - - // Maximum number of previews - maxpreviews: 20, - - // Length of time in seconds that previews are cached - cacheLifespan: 20, - - initialize: function () { - if (!(WINTASKBAR_CONTRACTID in Cc)) - return; - this.taskbar = Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar); - this.available = this.taskbar.available; - if (!this.available) - return; - - this.prefs.addObserver(TOGGLE_PREF_NAME, this, true); - this.enabled = this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME); - this.initialized = true; - }, - - destroy: function destroy() { - this._enabled = false; - - if (this.cacheTimer) - this.cacheTimer.cancel(); - }, - - get enabled() { - return this._enabled; - }, - - set enabled(enable) { - if (this._enabled == enable) - return; - - this._enabled = enable; - - this.windows.forEach(function (win) { - win.enabled = enable; - }); - }, - - get _prefenabled() { - return this.__prefenabled; - }, - - set _prefenabled(enable) { - if (enable == this.__prefenabled) { - return; - } - this.__prefenabled = enable; - - if (enable) { - this.enable(); - } else { - this.disable(); - } - }, - - _observersAdded: false, - - enable() { - if (!this._observersAdded) { - this.prefs.addObserver(DISABLE_THRESHOLD_PREF_NAME, this, true); - this.prefs.addObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this, true); - PlacesUtils.history.addObserver(this, true); - this._observersAdded = true; - } - - this.cacheLifespan = this.prefs.getIntPref(CACHE_EXPIRATION_TIME_PREF_NAME); - - this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME); - - // If the user toggled us on/off while the browser was already up - // (rather than this code running on startup because the pref was - // already set to true), we must initialize previews for open windows: - if (this.initialized) { - let browserWindows = Services.wm.getEnumerator("navigator:browser"); - while (browserWindows.hasMoreElements()) { - let win = browserWindows.getNext(); - if (!win.closed) { - this.onOpenWindow(win); - } - } - } - }, - - disable() { - while (this.windows.length) { - // We can't call onCloseWindow here because it'll bail if we're not - // enabled. - let tabWinObject = this.windows[0]; - tabWinObject.destroy(); // This will remove us from the array. - delete tabWinObject.win.gTaskbarTabGroup; // Tidy up the window. - } - }, - - addPreview: function (preview) { - this.previews.push(preview); - this.checkPreviewCount(); - }, - - removePreview: function (preview) { - let idx = this.previews.indexOf(preview); - this.previews.splice(idx, 1); - this.checkPreviewCount(); - }, - - checkPreviewCount: function () { - if (!this._prefenabled) { - return; - } - this.enabled = this.previews.length <= this.maxpreviews; - }, - - onOpenWindow: function (win) { - // This occurs when the taskbar service is not available (xp, vista) - if (!this.available || !this._prefenabled) - return; - - win.gTaskbarTabGroup = new TabWindow(win); - }, - - onCloseWindow: function (win) { - // This occurs when the taskbar service is not available (xp, vista) - if (!this.available || !this._prefenabled) - return; - - win.gTaskbarTabGroup.destroy(); - delete win.gTaskbarTabGroup; - - if (this.windows.length == 0) - this.destroy(); - }, - - resetCacheTimer: function () { - this.cacheTimer.cancel(); - this.cacheTimer.init(this, 1000*this.cacheLifespan, Ci.nsITimer.TYPE_ONE_SHOT); - }, - - // nsIObserver - observe: function (aSubject, aTopic, aData) { - if (aTopic == "nsPref:changed" && aData == TOGGLE_PREF_NAME) { - this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME); - } - if (!this._prefenabled) { - return; - } - switch (aTopic) { - case "nsPref:changed": - if (aData == CACHE_EXPIRATION_TIME_PREF_NAME) - break; - - if (aData == DISABLE_THRESHOLD_PREF_NAME) - this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME); - // Might need to enable/disable ourselves - this.checkPreviewCount(); - break; - case "timer-callback": - this.previews.forEach(function (preview) { - let controller = preview.controller.wrappedJSObject; - controller.resetCanvasPreview(); - }); - break; - } - }, - - /* nsINavHistoryObserver implementation */ - onBeginUpdateBatch() {}, - onEndUpdateBatch() {}, - onVisit() {}, - onTitleChanged() {}, - onFrecencyChanged() {}, - onManyFrecenciesChanged() {}, - onDeleteURI() {}, - onClearHistory() {}, - onDeleteVisits() {}, - onPageChanged(uri, changedConst, newValue) { - if (this.enabled && changedConst == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) { - for (let win of this.windows) { - for (let [tab, ] of win.previews) { - if (tab.getAttribute("image") == newValue) { - win.onLinkIconAvailable(tab.linkedBrowser, newValue); - } - } - } - } - }, - - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsISupportsWeakReference, - Ci.nsINavHistoryObserver, - Ci.nsIObserver - ]), -}; - -XPCOMUtils.defineLazyGetter(AeroPeek, "cacheTimer", () => - Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer) -); - -XPCOMUtils.defineLazyServiceGetter(AeroPeek, "prefs", - "@mozilla.org/preferences-service;1", - "nsIPrefBranch"); - -AeroPeek.initialize(); diff --git a/application/palemoon/modules/moz.build b/application/palemoon/modules/moz.build deleted file mode 100644 index 12a3ece2e..000000000 --- a/application/palemoon/modules/moz.build +++ /dev/null @@ -1,42 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -EXTRA_JS_MODULES += [ - 'AutoCompletePopup.jsm', - 'BrowserNewTabPreloader.jsm', - 'CharsetMenu.jsm', - 'FormSubmitObserver.jsm', - 'FormValidationHandler.jsm', - 'NetworkPrioritizer.jsm', - 'offlineAppCache.jsm', - 'openLocationLastURL.jsm', - 'PageMenu.jsm', - 'PopupNotifications.jsm', - 'QuotaManager.jsm', - 'SharedFrame.jsm' -] - -if CONFIG['MOZ_WEBRTC']: - EXTRA_JS_MODULES += ['webrtcUI.jsm'] - -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': - EXTRA_JS_MODULES += [ - 'Windows8WindowFrameColor.jsm', - 'WindowsJumpLists.jsm', - 'WindowsPreviewPerTab.jsm', - ] - -EXTRA_PP_JS_MODULES += [ - 'AboutHomeUtils.jsm', - 'RecentWindow.jsm', -] - -# Pass down 'official build' flags -if CONFIG['MC_OFFICIAL']: - DEFINES['MC_OFFICIAL'] = 1 - -if CONFIG['MOZILLA_OFFICIAL']: - DEFINES['MOZILLA_OFFICIAL'] = 1 diff --git a/application/palemoon/modules/offlineAppCache.jsm b/application/palemoon/modules/offlineAppCache.jsm deleted file mode 100644 index 00ded0956..000000000 --- a/application/palemoon/modules/offlineAppCache.jsm +++ /dev/null @@ -1,20 +0,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/. */ - -this.EXPORTED_SYMBOLS = ["OfflineAppCacheHelper"]; - -Components.utils.import('resource://gre/modules/LoadContextInfo.jsm'); - -const Cc = Components.classes; -const Ci = Components.interfaces; - -this.OfflineAppCacheHelper = { - clear: function() { - var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService); - var appCacheStorage = cacheService.appCacheStorage(LoadContextInfo.default, null); - try { - appCacheStorage.asyncEvictStorage(null); - } catch(er) {} - } -}; diff --git a/application/palemoon/modules/openLocationLastURL.jsm b/application/palemoon/modules/openLocationLastURL.jsm deleted file mode 100644 index 3f58db8ce..000000000 --- a/application/palemoon/modules/openLocationLastURL.jsm +++ /dev/null @@ -1,85 +0,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/. */ - -const LAST_URL_PREF = "general.open_location.last_url"; -const nsISupportsString = Components.interfaces.nsISupportsString; -const Ci = Components.interfaces; - -Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); - -this.EXPORTED_SYMBOLS = [ "OpenLocationLastURL" ]; - -var prefSvc = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranch); -var gOpenLocationLastURLData = ""; - -var observer = { - QueryInterface: function (aIID) { - if (aIID.equals(Components.interfaces.nsIObserver) || - aIID.equals(Components.interfaces.nsISupports) || - aIID.equals(Components.interfaces.nsISupportsWeakReference)) - return this; - throw Components.results.NS_NOINTERFACE; - }, - observe: function (aSubject, aTopic, aData) { - switch (aTopic) { - case "last-pb-context-exited": - gOpenLocationLastURLData = ""; - break; - case "browser:purge-session-history": - prefSvc.clearUserPref(LAST_URL_PREF); - gOpenLocationLastURLData = ""; - break; - } - } -}; - -var os = Components.classes["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); -os.addObserver(observer, "last-pb-context-exited", true); -os.addObserver(observer, "browser:purge-session-history", true); - - -this.OpenLocationLastURL = function OpenLocationLastURL(aWindow) { - this.window = aWindow; -} - -OpenLocationLastURL.prototype = { - isPrivate: function OpenLocationLastURL_isPrivate() { - // Assume not in private browsing mode, unless the browser window is - // in private mode. - if (!this.window) - return false; - - return PrivateBrowsingUtils.isWindowPrivate(this.window); - }, - get value() { - if (this.isPrivate()) - return gOpenLocationLastURLData; - else { - try { - return prefSvc.getComplexValue(LAST_URL_PREF, nsISupportsString).data; - } - catch (e) { - return ""; - } - } - }, - set value(val) { - if (typeof val != "string") - val = ""; - if (this.isPrivate()) - gOpenLocationLastURLData = val; - else { - let str = Components.classes["@mozilla.org/supports-string;1"] - .createInstance(Components.interfaces.nsISupportsString); - str.data = val; - prefSvc.setComplexValue(LAST_URL_PREF, nsISupportsString, str); - } - }, - reset: function() { - prefSvc.clearUserPref(LAST_URL_PREF); - gOpenLocationLastURLData = ""; - } -}; diff --git a/application/palemoon/modules/webrtcUI.jsm b/application/palemoon/modules/webrtcUI.jsm deleted file mode 100644 index 819ca181f..000000000 --- a/application/palemoon/modules/webrtcUI.jsm +++ /dev/null @@ -1,292 +0,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/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["webrtcUI"]; - -const Cu = Components.utils; -const Cc = Components.classes; -const Ci = Components.interfaces; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", - "resource://gre/modules/PluralForm.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService", - "@mozilla.org/mediaManagerService;1", - "nsIMediaManagerService"); - -this.webrtcUI = { - init: function () { - Services.obs.addObserver(handleRequest, "getUserMedia:request", false); - Services.obs.addObserver(updateIndicators, "recording-device-events", false); - Services.obs.addObserver(removeBrowserSpecificIndicator, "recording-window-ended", false); - }, - - uninit: function () { - Services.obs.removeObserver(handleRequest, "getUserMedia:request"); - Services.obs.removeObserver(updateIndicators, "recording-device-events"); - Services.obs.removeObserver(removeBrowserSpecificIndicator, "recording-window-ended"); - }, - - showGlobalIndicator: false, - - get activeStreams() { - let contentWindowSupportsArray = MediaManagerService.activeMediaCaptureWindows; - let count = contentWindowSupportsArray.Count(); - let activeStreams = []; - for (let i = 0; i < count; i++) { - let contentWindow = contentWindowSupportsArray.GetElementAt(i); - let browser = getBrowserForWindow(contentWindow); - let browserWindow = browser.ownerDocument.defaultView; - let tab = browserWindow.gBrowser && - browserWindow.gBrowser._getTabForContentWindow(contentWindow.top); - activeStreams.push({ - uri: contentWindow.location.href, - tab: tab, - browser: browser - }); - } - return activeStreams; - } -} - -function getBrowserForWindowId(aWindowID) { - return getBrowserForWindow(Services.wm.getOuterWindowWithId(aWindowID)); -} - -function getBrowserForWindow(aContentWindow) { - return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler; -} - -function handleRequest(aSubject, aTopic, aData) { - let {windowID: windowID, callID: callID} = JSON.parse(aData); - - let params = aSubject.QueryInterface(Ci.nsIMediaStreamOptions); - - Services.wm.getMostRecentWindow(null).navigator.mozGetUserMediaDevices( - function (devices) { - prompt(windowID, callID, params.audio, params.video || params.picture, devices); - }, - function (error) { - // bug 827146 -- In the future, the UI should catch NO_DEVICES_FOUND - // and allow the user to plug in a device, instead of immediately failing. - denyRequest(callID, error); - } - ); -} - -function denyRequest(aCallID, aError) { - let msg = null; - if (aError) { - msg = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); - msg.data = aError; - } - Services.obs.notifyObservers(msg, "getUserMedia:response:deny", aCallID); -} - -function prompt(aWindowID, aCallID, aAudioRequested, aVideoRequested, aDevices) { - let audioDevices = []; - let videoDevices = []; - for (let device of aDevices) { - device = device.QueryInterface(Ci.nsIMediaDevice); - switch (device.type) { - case "audio": - if (aAudioRequested) - audioDevices.push(device); - break; - case "video": - if (aVideoRequested) - videoDevices.push(device); - break; - } - } - - let requestType; - if (audioDevices.length && videoDevices.length) - requestType = "CameraAndMicrophone"; - else if (audioDevices.length) - requestType = "Microphone"; - else if (videoDevices.length) - requestType = "Camera"; - else { - denyRequest(aCallID, "NO_DEVICES_FOUND"); - return; - } - - let contentWindow = Services.wm.getOuterWindowWithId(aWindowID); - let host = contentWindow.document.documentURIObject.host; - let browser = getBrowserForWindow(contentWindow); - let chromeDoc = browser.ownerDocument; - let chromeWin = chromeDoc.defaultView; - let stringBundle = chromeWin.gNavigatorBundle; - let message = stringBundle.getFormattedString("getUserMedia.share" + requestType + ".message", - [ host ]); - - let mainAction = { - label: PluralForm.get(requestType == "CameraAndMicrophone" ? 2 : 1, - stringBundle.getString("getUserMedia.shareSelectedDevices.label")), - accessKey: stringBundle.getString("getUserMedia.shareSelectedDevices.accesskey"), - // The real callback will be set during the "showing" event. The - // empty function here is so that PopupNotifications.show doesn't - // reject the action. - callback: function() {} - }; - - let secondaryActions = [{ - label: stringBundle.getString("getUserMedia.denyRequest.label"), - accessKey: stringBundle.getString("getUserMedia.denyRequest.accesskey"), - callback: function () { - denyRequest(aCallID); - } - }]; - - let options = { - eventCallback: function(aTopic, aNewBrowser) { - if (aTopic == "swapping") - return true; - - if (aTopic != "showing") - return false; - - let chromeDoc = this.browser.ownerDocument; - - function listDevices(menupopup, devices) { - while (menupopup.lastChild) - menupopup.removeChild(menupopup.lastChild); - - let deviceIndex = 0; - for (let device of devices) { - addDeviceToList(menupopup, device.name, deviceIndex); - deviceIndex++; - } - } - - function addDeviceToList(menupopup, deviceName, deviceIndex) { - let menuitem = chromeDoc.createElement("menuitem"); - menuitem.setAttribute("value", deviceIndex); - menuitem.setAttribute("label", deviceName); - menuitem.setAttribute("tooltiptext", deviceName); - menupopup.appendChild(menuitem); - } - - chromeDoc.getElementById("webRTC-selectCamera").hidden = !videoDevices.length; - chromeDoc.getElementById("webRTC-selectMicrophone").hidden = !audioDevices.length; - - let camMenupopup = chromeDoc.getElementById("webRTC-selectCamera-menupopup"); - let micMenupopup = chromeDoc.getElementById("webRTC-selectMicrophone-menupopup"); - listDevices(camMenupopup, videoDevices); - listDevices(micMenupopup, audioDevices); - if (requestType == "CameraAndMicrophone") { - let stringBundle = chromeDoc.defaultView.gNavigatorBundle; - addDeviceToList(camMenupopup, stringBundle.getString("getUserMedia.noVideo.label"), "-1"); - addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1"); - } - - this.mainAction.callback = function() { - let allowedDevices = Cc["@mozilla.org/supports-array;1"] - .createInstance(Ci.nsISupportsArray); - if (videoDevices.length) { - let videoDeviceIndex = chromeDoc.getElementById("webRTC-selectCamera-menulist").value; - if (videoDeviceIndex != "-1") - allowedDevices.AppendElement(videoDevices[videoDeviceIndex]); - } - if (audioDevices.length) { - let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value; - if (audioDeviceIndex != "-1") - allowedDevices.AppendElement(audioDevices[audioDeviceIndex]); - } - - if (allowedDevices.Count() == 0) { - denyRequest(aCallID); - return; - } - - Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID); - }; - return true; - } - }; - - chromeWin.PopupNotifications.show(browser, "webRTC-shareDevices", message, - "webRTC-shareDevices-notification-icon", mainAction, - secondaryActions, options); -} - -function updateIndicators() { - webrtcUI.showGlobalIndicator = - MediaManagerService.activeMediaCaptureWindows.Count() > 0; - - let e = Services.wm.getEnumerator("navigator:browser"); - while (e.hasMoreElements()) - e.getNext().WebrtcIndicator.updateButton(); - - for (let {browser: browser} of webrtcUI.activeStreams) - showBrowserSpecificIndicator(browser); -} - -function showBrowserSpecificIndicator(aBrowser) { - let hasVideo = {}; - let hasAudio = {}; - MediaManagerService.mediaCaptureWindowState(aBrowser.contentWindow, - hasVideo, hasAudio); - let captureState; - if (hasVideo.value && hasAudio.value) { - captureState = "CameraAndMicrophone"; - } else if (hasVideo.value) { - captureState = "Camera"; - } else if (hasAudio.value) { - captureState = "Microphone"; - } else { - Cu.reportError("showBrowserSpecificIndicator: got neither video nor audio access"); - return; - } - - let chromeWin = aBrowser.ownerDocument.defaultView; - let stringBundle = chromeWin.gNavigatorBundle; - - let message = stringBundle.getString("getUserMedia.sharing" + captureState + ".message2"); - - let windowId = aBrowser.contentWindow - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils) - .currentInnerWindowID; - let mainAction = { - label: "Continue Sharing", //stringBundle.getString("getUserMedia.continueSharing.label"), - accessKey: "C", //stringBundle.getString("getUserMedia.continueSharing.accesskey"), - callback: function () {}, - dismiss: true - }; - let secondaryActions = [{ - label: "Stop Sharing", //stringBundle.getString("getUserMedia.stopSharing.label"), - accessKey: "S", //stringBundle.getString("getUserMedia.stopSharing.accesskey"), - callback: function () { - Services.obs.notifyObservers(null, "getUserMedia:revoke", windowId); - } - }]; - let options = { - hideNotNow: true, - dismissed: true, - eventCallback: function(aTopic) aTopic == "swapping" - }; - chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingDevices", message, - "webRTC-sharingDevices-notification-icon", mainAction, - secondaryActions, options); -} - -function removeBrowserSpecificIndicator(aSubject, aTopic, aData) { - let browser = getBrowserForWindowId(aData); - let PopupNotifications = browser.ownerDocument.defaultView.PopupNotifications; - let notification = PopupNotifications && - PopupNotifications.getNotification("webRTC-sharingDevices", - browser); - if (notification) - PopupNotifications.remove(notification); -} |