summaryrefslogtreecommitdiffstats
path: root/application/palemoon/modules
diff options
context:
space:
mode:
authorjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-07-06 15:53:52 +0200
committerjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-07-06 15:53:52 +0200
commit941e54654eabed0a3568f7fefe424a45aa02eddb (patch)
tree49aa02b174c428962d99142d8061267bfcd79e69 /application/palemoon/modules
parentad9ee72dcd7981bc47b3844a224d69fadfdfd8ef (diff)
parent0daa12376295d5d796256a116eb2a348a3a9273f (diff)
downloadUXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.gz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.lz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.xz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.zip
Merge branch 'master' of https://github.com/MoonchildProductions/UXP into _testBranch_test_1
Diffstat (limited to 'application/palemoon/modules')
-rw-r--r--application/palemoon/modules/AutoCompletePopup.jsm293
-rw-r--r--application/palemoon/modules/BrowserNewTabPreloader.jsm8
-rw-r--r--application/palemoon/modules/FormSubmitObserver.jsm16
-rw-r--r--application/palemoon/modules/FormValidationHandler.jsm10
-rw-r--r--application/palemoon/modules/NetworkPrioritizer.jsm8
-rw-r--r--application/palemoon/modules/PopupNotifications.jsm189
-rw-r--r--application/palemoon/modules/SharedFrame.jsm2
-rw-r--r--application/palemoon/modules/Windows8WindowFrameColor.jsm6
-rw-r--r--application/palemoon/modules/moz.build4
-rw-r--r--application/palemoon/modules/openLocationLastURL.jsm8
-rw-r--r--application/palemoon/modules/promise.js118
-rw-r--r--application/palemoon/modules/webrtcUI.jsm130
12 files changed, 568 insertions, 224 deletions
diff --git a/application/palemoon/modules/AutoCompletePopup.jsm b/application/palemoon/modules/AutoCompletePopup.jsm
new file mode 100644
index 000000000..c3698f905
--- /dev/null
+++ b/application/palemoon/modules/AutoCompletePopup.jsm
@@ -0,0 +1,293 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+this.EXPORTED_SYMBOLS = [ "AutoCompletePopup" ];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+// nsITreeView implementation that feeds the autocomplete popup
+// with the search data.
+var AutoCompleteTreeView = {
+ // nsISupports
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsITreeView,
+ Ci.nsIAutoCompleteController]),
+
+ // Private variables
+ treeBox: null,
+ results: [],
+
+ // nsITreeView
+ selection: null,
+
+ get rowCount() { return this.results.length; },
+ setTree: function(treeBox) { this.treeBox = treeBox; },
+ getCellText: function(idx, column) { return this.results[idx].value },
+ isContainer: function(idx) { return false; },
+ getCellValue: function(idx, column) { return false },
+ isContainerOpen: function(idx) { return false; },
+ isContainerEmpty: function(idx) { return false; },
+ isSeparator: function(idx) { return false; },
+ isSorted: function() { return false; },
+ isEditable: function(idx, column) { return false; },
+ canDrop: function(idx, orientation, dt) { return false; },
+ getLevel: function(idx) { return 0; },
+ getParentIndex: function(idx) { return -1; },
+ hasNextSibling: function(idx, after) { return idx < this.results.length - 1 },
+ toggleOpenState: function(idx) { },
+ getCellProperties: function(idx, column) { return this.results[idx].style || ""; },
+ getRowProperties: function(idx) { return ""; },
+ getImageSrc: function(idx, column) { return null; },
+ getProgressMode : function(idx, column) { },
+ cycleHeader: function(column) { },
+ cycleCell: function(idx, column) { },
+ selectionChanged: function() { },
+ performAction: function(action) { },
+ performActionOnCell: function(action, index, column) { },
+ getColumnProperties: function(column) { return ""; },
+
+ // nsIAutoCompleteController
+ get matchCount() {
+ return this.rowCount;
+ },
+
+ handleEnter: function(aIsPopupSelection) {
+ AutoCompletePopup.handleEnter(aIsPopupSelection);
+ },
+
+ stopSearch: function() {},
+
+ // Internal JS-only API
+ clearResults: function() {
+ this.results = [];
+ },
+
+ setResults: function(results) {
+ this.results = results;
+ },
+};
+
+this.AutoCompletePopup = {
+ MESSAGES: [
+ "FormAutoComplete:SelectBy",
+ "FormAutoComplete:GetSelectedIndex",
+ "FormAutoComplete:SetSelectedIndex",
+ "FormAutoComplete:MaybeOpenPopup",
+ "FormAutoComplete:ClosePopup",
+ "FormAutoComplete:Disconnect",
+ "FormAutoComplete:RemoveEntry",
+ "FormAutoComplete:Invalidate",
+ ],
+
+ init: function() {
+ for (let msg of this.MESSAGES) {
+ Services.mm.addMessageListener(msg, this);
+ }
+ },
+
+ uninit: function() {
+ for (let msg of this.MESSAGES) {
+ Services.mm.removeMessageListener(msg, this);
+ }
+ },
+
+ handleEvent: function(evt) {
+ switch (evt.type) {
+ case "popupshowing": {
+ this.sendMessageToBrowser("FormAutoComplete:PopupOpened");
+ break;
+ }
+
+ case "popuphidden": {
+ this.sendMessageToBrowser("FormAutoComplete:PopupClosed");
+ this.openedPopup = null;
+ this.weakBrowser = null;
+ evt.target.removeEventListener("popuphidden", this);
+ evt.target.removeEventListener("popupshowing", this);
+ break;
+ }
+ }
+ },
+
+ // Along with being called internally by the receiveMessage handler,
+ // this function is also called directly by the login manager, which
+ // uses a single message to fill in the autocomplete results. See
+ // "RemoteLogins:autoCompleteLogins".
+ showPopupWithResults: function({ browser, rect, dir, results }) {
+ if (!results.length || this.openedPopup) {
+ // We shouldn't ever be showing an empty popup, and if we
+ // already have a popup open, the old one needs to close before
+ // we consider opening a new one.
+ return;
+ }
+
+ let window = browser.ownerDocument.defaultView;
+ let tabbrowser = window.gBrowser;
+ if (Services.focus.activeWindow != window ||
+ tabbrowser.selectedBrowser != browser) {
+ // We were sent a message from a window or tab that went into the
+ // background, so we'll ignore it for now.
+ return;
+ }
+
+ this.weakBrowser = Cu.getWeakReference(browser);
+ this.openedPopup = browser.autoCompletePopup;
+ this.openedPopup.hidden = false;
+ // don't allow the popup to become overly narrow
+ this.openedPopup.setAttribute("width", Math.max(100, rect.width));
+ this.openedPopup.style.direction = dir;
+
+ AutoCompleteTreeView.setResults(results);
+ this.openedPopup.view = AutoCompleteTreeView;
+ this.openedPopup.selectedIndex = -1;
+ this.openedPopup.invalidate();
+
+ if (results.length) {
+ // Reset fields that were set from the last time the search popup was open
+ this.openedPopup.mInput = null;
+ this.openedPopup.showCommentColumn = false;
+ this.openedPopup.showImageColumn = false;
+ this.openedPopup.addEventListener("popuphidden", this);
+ this.openedPopup.addEventListener("popupshowing", this);
+ this.openedPopup.openPopupAtScreenRect("after_start", rect.left, rect.top,
+ rect.width, rect.height, false,
+ false);
+ } else {
+ this.closePopup();
+ }
+ },
+
+ invalidate(results) {
+ if (!this.openedPopup) {
+ return;
+ }
+
+ if (!results.length) {
+ this.closePopup();
+ } else {
+ AutoCompleteTreeView.setResults(results);
+ // We need to re-set the view in order for the
+ // tree to know the view has changed.
+ this.openedPopup.view = AutoCompleteTreeView;
+ this.openedPopup.invalidate();
+ }
+ },
+
+ closePopup() {
+ if (this.openedPopup) {
+ // Note that hidePopup() closes the popup immediately,
+ // so popuphiding or popuphidden events will be fired
+ // and handled during this call.
+ this.openedPopup.hidePopup();
+ }
+ AutoCompleteTreeView.clearResults();
+ },
+
+ removeLogin(login) {
+ Services.logins.removeLogin(login);
+ },
+
+ receiveMessage: function(message) {
+ if (!message.target.autoCompletePopup) {
+ // Returning false to pacify ESLint, but this return value is
+ // ignored by the messaging infrastructure.
+ return false;
+ }
+
+ switch (message.name) {
+ case "FormAutoComplete:SelectBy": {
+ this.openedPopup.selectBy(message.data.reverse, message.data.page);
+ break;
+ }
+
+ case "FormAutoComplete:GetSelectedIndex": {
+ if (this.openedPopup) {
+ return this.openedPopup.selectedIndex;
+ }
+ // If the popup was closed, then the selection
+ // has not changed.
+ return -1;
+ }
+
+ case "FormAutoComplete:SetSelectedIndex": {
+ let { index } = message.data;
+ if (this.openedPopup) {
+ this.openedPopup.selectedIndex = index;
+ }
+ break;
+ }
+
+ case "FormAutoComplete:MaybeOpenPopup": {
+ let { results, rect, dir } = message.data;
+ this.showPopupWithResults({ browser: message.target, rect, dir,
+ results });
+ break;
+ }
+
+ case "FormAutoComplete:Invalidate": {
+ let { results } = message.data;
+ this.invalidate(results);
+ break;
+ }
+
+ case "FormAutoComplete:ClosePopup": {
+ this.closePopup();
+ break;
+ }
+
+ case "FormAutoComplete:Disconnect": {
+ // The controller stopped controlling the current input, so clear
+ // any cached data. This is necessary cause otherwise we'd clear data
+ // only when starting a new search, but the next input could not support
+ // autocomplete and it would end up inheriting the existing data.
+ AutoCompleteTreeView.clearResults();
+ break;
+ }
+ }
+ // Returning false to pacify ESLint, but this return value is
+ // ignored by the messaging infrastructure.
+ return false;
+ },
+
+ /**
+ * Despite its name, this handleEnter is only called when the user clicks on
+ * one of the items in the popup since the popup is rendered in the parent process.
+ * The real controller's handleEnter is called directly in the content process
+ * for other methods of completing a selection (e.g. using the tab or enter
+ * keys) since the field with focus is in that process.
+ */
+ handleEnter(aIsPopupSelection) {
+ if (this.openedPopup) {
+ this.sendMessageToBrowser("FormAutoComplete:HandleEnter", {
+ selectedIndex: this.openedPopup.selectedIndex,
+ isPopupSelection: aIsPopupSelection,
+ });
+ }
+ },
+
+ /**
+ * If a browser exists that AutoCompletePopup knows about,
+ * sends it a message. Otherwise, this is a no-op.
+ *
+ * @param {string} msgName
+ * The name of the message to send.
+ * @param {object} data
+ * The optional data to send with the message.
+ */
+ sendMessageToBrowser(msgName, data) {
+ let browser = this.weakBrowser ? this.weakBrowser.get()
+ : null;
+ if (browser) {
+ browser.messageManager.sendAsyncMessage(msgName, data);
+ }
+ },
+
+ stopSearch: function() {}
+}
diff --git a/application/palemoon/modules/BrowserNewTabPreloader.jsm b/application/palemoon/modules/BrowserNewTabPreloader.jsm
index 719a9e05e..778698fba 100644
--- a/application/palemoon/modules/BrowserNewTabPreloader.jsm
+++ b/application/palemoon/modules/BrowserNewTabPreloader.jsm
@@ -79,7 +79,7 @@ this.BrowserNewTabPreloader = {
Object.freeze(BrowserNewTabPreloader);
-let Initializer = {
+var Initializer = {
_timer: null,
_observing: false,
@@ -120,7 +120,7 @@ let Initializer = {
}
};
-let Preferences = {
+var Preferences = {
_enabled: null,
_branch: null,
@@ -157,7 +157,7 @@ let Preferences = {
},
};
-let HiddenBrowsers = {
+var HiddenBrowsers = {
_browsers: null,
_updateTimer: null,
@@ -379,7 +379,7 @@ HiddenBrowser.prototype = {
}
};
-let HostFrame = {
+var HostFrame = {
_frame: null,
_deferred: null,
diff --git a/application/palemoon/modules/FormSubmitObserver.jsm b/application/palemoon/modules/FormSubmitObserver.jsm
index 72c5ca601..e4d3e765e 100644
--- a/application/palemoon/modules/FormSubmitObserver.jsm
+++ b/application/palemoon/modules/FormSubmitObserver.jsm
@@ -9,14 +9,14 @@
"use strict";
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cu = Components.utils;
-
-let HTMLInputElement = Ci.nsIDOMHTMLInputElement;
-let HTMLTextAreaElement = Ci.nsIDOMHTMLTextAreaElement;
-let HTMLSelectElement = Ci.nsIDOMHTMLSelectElement;
-let HTMLButtonElement = Ci.nsIDOMHTMLButtonElement;
+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" ];
diff --git a/application/palemoon/modules/FormValidationHandler.jsm b/application/palemoon/modules/FormValidationHandler.jsm
index 05be510e1..387c221d7 100644
--- a/application/palemoon/modules/FormValidationHandler.jsm
+++ b/application/palemoon/modules/FormValidationHandler.jsm
@@ -8,15 +8,15 @@
"use strict";
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cu = Components.utils;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
this.EXPORTED_SYMBOLS = [ "FormValidationHandler" ];
Cu.import("resource://gre/modules/Services.jsm");
-let FormValidationHandler =
+var FormValidationHandler =
{
_panel: null,
_anchor: null,
@@ -122,7 +122,7 @@ let FormValidationHandler =
this._panel.hidden = false;
let tabBrowser = aWindow.gBrowser;
- this._anchor = tabBrowser.formValidationAnchor;
+ this._anchor = tabBrowser.popupAnchor;
this._anchor.left = aPanelData.contentRect.left;
this._anchor.top = aPanelData.contentRect.top;
this._anchor.width = aPanelData.contentRect.width;
diff --git a/application/palemoon/modules/NetworkPrioritizer.jsm b/application/palemoon/modules/NetworkPrioritizer.jsm
index ea4a87790..23d688a30 100644
--- a/application/palemoon/modules/NetworkPrioritizer.jsm
+++ b/application/palemoon/modules/NetworkPrioritizer.jsm
@@ -34,8 +34,8 @@ const PRIORITY_DELTA = -10;
// Variables
-let _lastFocusedWindow = null;
-let _windows = [];
+var _lastFocusedWindow = null;
+var _windows = [];
// Exported symbol
@@ -64,7 +64,7 @@ function _handleEvent(aEvent) {
// Methods that impact a browser. Put into single object for organization.
-let BrowserHelper = {
+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)
@@ -91,7 +91,7 @@ let BrowserHelper = {
// Methods that impact a window. Put into single object for organization.
-let WindowHelper = {
+var WindowHelper = {
addWindow: function NP_WH_addWindow(aWindow) {
// Build internal data object
_windows.push({ window: aWindow, lastSelectedBrowser: null });
diff --git a/application/palemoon/modules/PopupNotifications.jsm b/application/palemoon/modules/PopupNotifications.jsm
index 9b2e8e5d1..0cb970230 100644
--- a/application/palemoon/modules/PopupNotifications.jsm
+++ b/application/palemoon/modules/PopupNotifications.jsm
@@ -4,22 +4,23 @@
this.EXPORTED_SYMBOLS = ["PopupNotifications"];
-var Cc = Components.classes, Ci = Components.interfaces;
+var Cc = Components.classes, Ci = Components.interfaces, Cu = Components.utils;
-Components.utils.import("resource://gre/modules/Services.jsm");
+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";
-let popupNotificationsMap = new WeakMap();
-let gNotificationParents = new WeakMap;
+var popupNotificationsMap = new WeakMap();
+var gNotificationParents = new WeakMap;
function getAnchorFromBrowser(aBrowser) {
let anchor = aBrowser.getAttribute("popupnotificationanchor") ||
@@ -33,6 +34,18 @@ function getAnchorFromBrowser(aBrowser) {
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.
*
@@ -194,7 +207,8 @@ PopupNotifications.prototype = {
* - label (string): the button's label.
* - accessKey (string): the button's accessKey.
* - callback (function): a callback to be invoked when the button is
- * pressed.
+ * 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
@@ -224,9 +238,23 @@ PopupNotifications.prototype = {
* 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:
@@ -234,6 +262,26 @@ PopupNotifications.prototype = {
* 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
@@ -552,6 +600,25 @@ PopupNotifications.prototype = {
}
}
+ 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
@@ -560,6 +627,32 @@ PopupNotifications.prototype = {
}, 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;
@@ -751,9 +844,60 @@ PopupNotifications.prototype = {
this._update(notifications, anchor);
},
- _fireCallback: function PopupNotifications_fireCallback(n, event) {
- if (n.options.eventCallback)
- n.options.eventCallback.call(n, event);
+ _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) {
@@ -789,15 +933,7 @@ PopupNotifications.prototype = {
},
_onButtonCommand: function PopupNotifications_onButtonCommand(event) {
- // Need to find the associated notification object, which is a bit tricky
- // since it isn't associated with the button directly - this is kind of
- // gross and very dependent on the structure of the popupnotification
- // binding's content.
- let target = event.originalTarget;
- let notificationEl;
- let parent = target;
- while (parent && (parent = target.ownerDocument.getBindingParent(parent)))
- notificationEl = parent;
+ let notificationEl = getNotificationFromElement(event.originalTarget);
if (!notificationEl)
throw "PopupNotifications_onButtonCommand: couldn't find notification element";
@@ -819,7 +955,14 @@ PopupNotifications.prototype = {
timeSinceShown + "ms");
return;
}
- notification.mainAction.callback.call();
+
+ try {
+ notification.mainAction.callback.call(undefined, {
+ checkboxChecked: notificationEl.checkbox.checked
+ });
+ } catch (error) {
+ Cu.reportError(error);
+ }
this._remove(notification);
this._update();
@@ -830,8 +973,16 @@ PopupNotifications.prototype = {
if (!target.action || !target.notification)
throw "menucommand target has no associated action/notification";
+ let notificationEl = target.parentElement;
event.stopPropagation();
- target.action.callback.call();
+
+ try {
+ target.action.callback.call(undefined, {
+ checkboxChecked: notificationEl.checkbox.checked
+ });
+ } catch (error) {
+ Cu.reportError(error);
+ }
this._remove(target.notification);
this._update();
diff --git a/application/palemoon/modules/SharedFrame.jsm b/application/palemoon/modules/SharedFrame.jsm
index 4d248ae5b..b9d59bfa9 100644
--- a/application/palemoon/modules/SharedFrame.jsm
+++ b/application/palemoon/modules/SharedFrame.jsm
@@ -18,7 +18,7 @@ const Cu = Components.utils;
* when another one of the placeholder is meant to be displayed.
* */
-let Frames = new Map();
+var Frames = new Map();
/**
* The Frames map is the main data structure that holds information
diff --git a/application/palemoon/modules/Windows8WindowFrameColor.jsm b/application/palemoon/modules/Windows8WindowFrameColor.jsm
index d424da499..e7a447db2 100644
--- a/application/palemoon/modules/Windows8WindowFrameColor.jsm
+++ b/application/palemoon/modules/Windows8WindowFrameColor.jsm
@@ -11,15 +11,15 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/WindowsRegistry.jsm");
-const Windows8WindowFrameColor = {
+var Windows8WindowFrameColor = {
_windowFrameColor: null,
get_win8: function() {
if (this._windowFrameColor)
return this._windowFrameColor;
- let HKCU = Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER;
- let dwmKey = "Software\\Microsoft\\Windows\\DWM";
+ 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;
diff --git a/application/palemoon/modules/moz.build b/application/palemoon/modules/moz.build
index f7717ef89..8032930b2 100644
--- a/application/palemoon/modules/moz.build
+++ b/application/palemoon/modules/moz.build
@@ -5,10 +5,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-# XXX: Include this until we convert browser/ to use toolkit promises directly
-EXTRA_JS_MODULES += [ 'promise.js' ]
-
EXTRA_JS_MODULES += [
+ 'AutoCompletePopup.jsm',
'BrowserNewTabPreloader.jsm',
'CharsetMenu.jsm',
'FormSubmitObserver.jsm',
diff --git a/application/palemoon/modules/openLocationLastURL.jsm b/application/palemoon/modules/openLocationLastURL.jsm
index 0d653df28..3f58db8ce 100644
--- a/application/palemoon/modules/openLocationLastURL.jsm
+++ b/application/palemoon/modules/openLocationLastURL.jsm
@@ -10,11 +10,11 @@ Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
this.EXPORTED_SYMBOLS = [ "OpenLocationLastURL" ];
-let prefSvc = Components.classes["@mozilla.org/preferences-service;1"]
+var prefSvc = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
-let gOpenLocationLastURLData = "";
+var gOpenLocationLastURLData = "";
-let observer = {
+var observer = {
QueryInterface: function (aIID) {
if (aIID.equals(Components.interfaces.nsIObserver) ||
aIID.equals(Components.interfaces.nsISupports) ||
@@ -35,7 +35,7 @@ let observer = {
}
};
-let os = Components.classes["@mozilla.org/observer-service;1"]
+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);
diff --git a/application/palemoon/modules/promise.js b/application/palemoon/modules/promise.js
deleted file mode 100644
index 7c96f02cf..000000000
--- a/application/palemoon/modules/promise.js
+++ /dev/null
@@ -1,118 +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';
-
-/*
- * Uses `Promise.jsm` as a core implementation, with additional sugar
- * from previous implementation, with inspiration from `Q` and `when`
- *
- * https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm
- * https://github.com/cujojs/when
- * https://github.com/kriskowal/q
- */
-const PROMISE_URI = 'resource://gre/modules/Promise.jsm';
-
-getEnvironment.call(this, function ({ require, exports, module, Cu }) {
-
-const Promise = Cu.import(PROMISE_URI, {}).Promise;
-const { Debugging, defer, resolve, all, reject, race } = Promise;
-
-module.metadata = {
- 'stability': 'unstable'
-};
-
-let promised = (function() {
- // Note: Define shortcuts and utility functions here in order to avoid
- // slower property accesses and unnecessary closure creations on each
- // call of this popular function.
-
- var call = Function.call;
- var concat = Array.prototype.concat;
-
- // Utility function that does following:
- // execute([ f, self, args...]) => f.apply(self, args)
- function execute (args) call.apply(call, args)
-
- // Utility function that takes promise of `a` array and maybe promise `b`
- // as arguments and returns promise for `a.concat(b)`.
- function promisedConcat(promises, unknown) {
- return promises.then(function (values) {
- return resolve(unknown)
- .then(function (value) values.concat([value]));
- });
- }
-
- return function promised(f, prototype) {
- /**
- Returns a wrapped `f`, which when called returns a promise that resolves to
- `f(...)` passing all the given arguments to it, which by the way may be
- promises. Optionally second `prototype` argument may be provided to be used
- a prototype for a returned promise.
-
- ## Example
-
- var promise = promised(Array)(1, promise(2), promise(3))
- promise.then(console.log) // => [ 1, 2, 3 ]
- **/
-
- return function promised(...args) {
- // create array of [ f, this, args... ]
- return [f, this, ...args].
- // reduce it via `promisedConcat` to get promised array of fulfillments
- reduce(promisedConcat, resolve([], prototype)).
- // finally map that to promise of `f.apply(this, args...)`
- then(execute);
- };
- };
-})();
-
-exports.promised = promised;
-exports.all = all;
-exports.defer = defer;
-exports.resolve = resolve;
-exports.reject = reject;
-exports.race = race;
-exports.Promise = Promise;
-exports.Debugging = Debugging;
-});
-
-function getEnvironment (callback) {
- let Cu, _exports, _module, _require;
-
- // CommonJS / SDK
- if (typeof(require) === 'function') {
- Cu = require('chrome').Cu;
- _exports = exports;
- _module = module;
- _require = require;
- }
- // JSM
- else if (String(this).indexOf('BackstagePass') >= 0) {
- Cu = this['Components'].utils;
- _exports = this.Promise = {};
- _module = { uri: __URI__, id: 'promise/core' };
- _require = uri => {
- let imports = {};
- Cu.import(uri, imports);
- return imports;
- };
- this.EXPORTED_SYMBOLS = ['Promise'];
- // mozIJSSubScriptLoader.loadSubscript
- } else if (~String(this).indexOf('Sandbox')) {
- Cu = this['Components'].utils;
- _exports = this;
- _module = { id: 'promise/core' };
- _require = uri => {};
- }
-
- callback({
- Cu: Cu,
- exports: _exports,
- module: _module,
- require: _require
- });
-}
-
diff --git a/application/palemoon/modules/webrtcUI.jsm b/application/palemoon/modules/webrtcUI.jsm
index c957bfd9a..819ca181f 100644
--- a/application/palemoon/modules/webrtcUI.jsm
+++ b/application/palemoon/modules/webrtcUI.jsm
@@ -11,9 +11,11 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PluralForm.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");
@@ -128,62 +130,14 @@ function prompt(aWindowID, aCallID, aAudioRequested, aVideoRequested, aDevices)
let message = stringBundle.getFormattedString("getUserMedia.share" + requestType + ".message",
[ host ]);
- 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") {
- addDeviceToList(camMenupopup, stringBundle.getString("getUserMedia.noVideo.label"), "-1");
- addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1");
- }
-
let mainAction = {
label: PluralForm.get(requestType == "CameraAndMicrophone" ? 2 : 1,
stringBundle.getString("getUserMedia.shareSelectedDevices.label")),
accessKey: stringBundle.getString("getUserMedia.shareSelectedDevices.accesskey"),
- 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);
- }
+ // 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 = [{
@@ -194,7 +148,72 @@ function prompt(aWindowID, aCallID, aAudioRequested, aVideoRequested, aDevices)
}
}];
- let options = null;
+ 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,
@@ -254,7 +273,8 @@ function showBrowserSpecificIndicator(aBrowser) {
}];
let options = {
hideNotNow: true,
- dismissed: true
+ dismissed: true,
+ eventCallback: function(aTopic) aTopic == "swapping"
};
chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingDevices", message,
"webRTC-sharingDevices-notification-icon", mainAction,