summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/AboutHomeUtils.jsm67
-rw-r--r--modules/AutoCompletePopup.jsm293
-rw-r--r--modules/BrowserNewTabPreloader.jsm436
-rw-r--r--modules/CharsetMenu.jsm160
-rw-r--r--modules/FormSubmitObserver.jsm235
-rw-r--r--modules/FormValidationHandler.jsm157
-rw-r--r--modules/NetworkPrioritizer.jsm179
-rw-r--r--modules/PageMenu.jsm238
-rw-r--r--modules/PopupNotifications.jsm994
-rw-r--r--modules/QuotaManager.jsm51
-rw-r--r--modules/RecentWindow.jsm68
-rw-r--r--modules/SharedFrame.jsm221
-rw-r--r--modules/Windows8WindowFrameColor.jsm53
-rw-r--r--modules/WindowsJumpLists.jsm581
-rw-r--r--modules/WindowsPreviewPerTab.jsm861
-rw-r--r--modules/moz.build42
-rw-r--r--modules/offlineAppCache.jsm20
-rw-r--r--modules/openLocationLastURL.jsm85
-rw-r--r--modules/webrtcUI.jsm292
19 files changed, 0 insertions, 5033 deletions
diff --git a/modules/AboutHomeUtils.jsm b/modules/AboutHomeUtils.jsm
deleted file mode 100644
index 72712e1..0000000
--- a/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/modules/AutoCompletePopup.jsm b/modules/AutoCompletePopup.jsm
deleted file mode 100644
index c3698f9..0000000
--- a/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/modules/BrowserNewTabPreloader.jsm b/modules/BrowserNewTabPreloader.jsm
deleted file mode 100644
index 778698f..0000000
--- a/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/modules/CharsetMenu.jsm b/modules/CharsetMenu.jsm
deleted file mode 100644
index f973088..0000000
--- a/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/modules/FormSubmitObserver.jsm b/modules/FormSubmitObserver.jsm
deleted file mode 100644
index 6b2ea3c..0000000
--- a/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/modules/FormValidationHandler.jsm b/modules/FormValidationHandler.jsm
deleted file mode 100644
index 387c221..0000000
--- a/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/modules/NetworkPrioritizer.jsm b/modules/NetworkPrioritizer.jsm
deleted file mode 100644
index 23d688a..0000000
--- a/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/modules/PageMenu.jsm b/modules/PageMenu.jsm
deleted file mode 100644
index d01f626..0000000
--- a/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/modules/PopupNotifications.jsm b/modules/PopupNotifications.jsm
deleted file mode 100644
index 0cb9702..0000000
--- a/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/modules/QuotaManager.jsm b/modules/QuotaManager.jsm
deleted file mode 100644
index 48cfe88..0000000
--- a/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/modules/RecentWindow.jsm b/modules/RecentWindow.jsm
deleted file mode 100644
index 0018b50..0000000
--- a/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/modules/SharedFrame.jsm b/modules/SharedFrame.jsm
deleted file mode 100644
index b9d59bf..0000000
--- a/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/modules/Windows8WindowFrameColor.jsm b/modules/Windows8WindowFrameColor.jsm
deleted file mode 100644
index e7a447d..0000000
--- a/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/modules/WindowsJumpLists.jsm b/modules/WindowsJumpLists.jsm
deleted file mode 100644
index e7f7855..0000000
--- a/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/modules/WindowsPreviewPerTab.jsm b/modules/WindowsPreviewPerTab.jsm
deleted file mode 100644
index 4b5030a..0000000
--- a/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/modules/moz.build b/modules/moz.build
deleted file mode 100644
index 12a3ece..0000000
--- a/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/modules/offlineAppCache.jsm b/modules/offlineAppCache.jsm
deleted file mode 100644
index 00ded09..0000000
--- a/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/modules/openLocationLastURL.jsm b/modules/openLocationLastURL.jsm
deleted file mode 100644
index 3f58db8..0000000
--- a/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/modules/webrtcUI.jsm b/modules/webrtcUI.jsm
deleted file mode 100644
index 819ca18..0000000
--- a/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);
-}