summaryrefslogtreecommitdiffstats
path: root/application/palemoon/base/content
diff options
context:
space:
mode:
Diffstat (limited to 'application/palemoon/base/content')
-rw-r--r--application/palemoon/base/content/abouthome/aboutHome.js4
-rw-r--r--application/palemoon/base/content/autocomplete.css17
-rw-r--r--application/palemoon/base/content/autocomplete.xml2128
-rw-r--r--application/palemoon/base/content/autorecovery.js6
-rw-r--r--application/palemoon/base/content/baseMenuOverlay.xul2
-rw-r--r--application/palemoon/base/content/browser-addons.js4
-rw-r--r--application/palemoon/base/content/browser-appmenu.inc35
-rw-r--r--application/palemoon/base/content/browser-devtools-theme.js91
-rw-r--r--application/palemoon/base/content/browser-fullScreen.js5
-rw-r--r--application/palemoon/base/content/browser-fullZoom.js210
-rw-r--r--application/palemoon/base/content/browser-gestureSupport.js4
-rw-r--r--application/palemoon/base/content/browser-menubar.inc31
-rw-r--r--application/palemoon/base/content/browser-places.js23
-rw-r--r--application/palemoon/base/content/browser-plugins.js20
-rw-r--r--application/palemoon/base/content/browser-sets.inc78
-rw-r--r--application/palemoon/base/content/browser-syncui.js2
-rw-r--r--application/palemoon/base/content/browser-thumbnails.js11
-rw-r--r--application/palemoon/base/content/browser-uacompat.js45
-rw-r--r--application/palemoon/base/content/browser-webrtcUI.js2
-rw-r--r--application/palemoon/base/content/browser.css83
-rw-r--r--application/palemoon/base/content/browser.js694
-rw-r--r--application/palemoon/base/content/browser.xul62
-rw-r--r--application/palemoon/base/content/content.js127
-rw-r--r--application/palemoon/base/content/global-devtools-theme-scripts.inc6
-rw-r--r--application/palemoon/base/content/macBrowserOverlay.xul3
-rw-r--r--application/palemoon/base/content/newtab/drag.js2
-rw-r--r--application/palemoon/base/content/newtab/dragDataHelper.js2
-rw-r--r--application/palemoon/base/content/newtab/drop.js2
-rw-r--r--application/palemoon/base/content/newtab/dropPreview.js2
-rw-r--r--application/palemoon/base/content/newtab/dropTargetShim.js2
-rw-r--r--application/palemoon/base/content/newtab/grid.js16
-rw-r--r--application/palemoon/base/content/newtab/newTab.js6
-rw-r--r--application/palemoon/base/content/newtab/page.js2
-rw-r--r--application/palemoon/base/content/newtab/transformations.js2
-rw-r--r--application/palemoon/base/content/newtab/undo.js2
-rw-r--r--application/palemoon/base/content/newtab/updater.js2
-rw-r--r--application/palemoon/base/content/nsContextMenu.js69
-rw-r--r--application/palemoon/base/content/openLocation.js81
-rw-r--r--application/palemoon/base/content/padlock.js6
-rw-r--r--application/palemoon/base/content/pageinfo/pageInfo.js7
-rw-r--r--application/palemoon/base/content/pageinfo/permissions.js68
-rw-r--r--application/palemoon/base/content/popup-notifications.inc13
-rw-r--r--application/palemoon/base/content/sanitize.js19
-rw-r--r--application/palemoon/base/content/sync/aboutSyncTabs.js2
-rw-r--r--application/palemoon/base/content/sync/addDevice.js2
-rw-r--r--application/palemoon/base/content/sync/genericChange.js2
-rw-r--r--application/palemoon/base/content/sync/progress.js4
-rw-r--r--application/palemoon/base/content/sync/quota.js4
-rw-r--r--application/palemoon/base/content/sync/utils.js2
-rw-r--r--application/palemoon/base/content/tabbrowser.xml363
-rw-r--r--application/palemoon/base/content/urlbarBindings.xml377
-rw-r--r--application/palemoon/base/content/utilityOverlay.js57
52 files changed, 3638 insertions, 1171 deletions
diff --git a/application/palemoon/base/content/abouthome/aboutHome.js b/application/palemoon/base/content/abouthome/aboutHome.js
index 9e826b69e..6a970acd6 100644
--- a/application/palemoon/base/content/abouthome/aboutHome.js
+++ b/application/palemoon/base/content/abouthome/aboutHome.js
@@ -234,8 +234,8 @@ const SEARCH_ENGINES = {
};
// This global tracks if the page has been set up before, to prevent double inits
-let gInitialized = false;
-let gObserver = new MutationObserver(function (mutations) {
+var gInitialized = false;
+var gObserver = new MutationObserver(function (mutations) {
for (let mutation of mutations) {
if (mutation.attributeName == "searchEngineURL") {
setupSearchEngine();
diff --git a/application/palemoon/base/content/autocomplete.css b/application/palemoon/base/content/autocomplete.css
new file mode 100644
index 000000000..960bdc456
--- /dev/null
+++ b/application/palemoon/base/content/autocomplete.css
@@ -0,0 +1,17 @@
+/* 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/. */
+
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+@namespace html url("http://www.w3.org/1999/xhtml");
+
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ .ac-site-icon {
+ image-rendering: -moz-crisp-edges;
+ }
+}
+
+richlistitem > .ac-title-box > .ac-title > .ac-comment:not([selected]) > html|span.ac-selected-text {
+ display: none;
+}
diff --git a/application/palemoon/base/content/autocomplete.xml b/application/palemoon/base/content/autocomplete.xml
new file mode 100644
index 000000000..bd0928436
--- /dev/null
+++ b/application/palemoon/base/content/autocomplete.xml
@@ -0,0 +1,2128 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<bindings id="privateAutocompleteBindings"
+ xmlns="http://www.mozilla.org/xbl"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:xbl="http://www.mozilla.org/xbl">
+
+ <binding id="private-autocomplete" role="xul:combobox"
+ extends="chrome://global/content/bindings/textbox.xml#textbox">
+ <resources>
+ <stylesheet src="chrome://browser/content/autocomplete.css"/>
+ <stylesheet src="chrome://browser/skin/autocomplete.css"/>
+ </resources>
+
+ <content sizetopopup="pref">
+ <xul:hbox class="private-autocomplete-textbox-container" flex="1" xbl:inherits="focused">
+ <children includes="image|deck|stack|box">
+ <xul:image class="private-autocomplete-icon" allowevents="true"/>
+ </children>
+
+ <xul:hbox anonid="textbox-input-box" class="textbox-input-box" flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
+ <children/>
+ <html:input anonid="input" class="private-autocomplete-textbox textbox-input"
+ allowevents="true"
+ xbl:inherits="tooltiptext=inputtooltiptext,value,type=inputtype,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,mozactionhint"/>
+ </xul:hbox>
+ <children includes="hbox"/>
+ </xul:hbox>
+
+ <xul:dropmarker anonid="historydropmarker" class="private-autocomplete-history-dropmarker"
+ allowevents="true"
+ xbl:inherits="open,enablehistory,parentfocused=focused"/>
+
+ <xul:popupset anonid="popupset" class="private-autocomplete-result-popupset"/>
+
+ <children includes="toolbarbutton"/>
+ </content>
+
+ <implementation implements="nsIAutoCompleteInput, nsIDOMXULMenuListElement">
+ <field name="mController">null</field>
+ <field name="mSearchNames">null</field>
+ <field name="mIgnoreInput">false</field>
+ <field name="mEnterEvent">null</field>
+
+ <field name="_searchBeginHandler">null</field>
+ <field name="_searchCompleteHandler">null</field>
+ <field name="_textEnteredHandler">null</field>
+ <field name="_textRevertedHandler">null</field>
+
+ <constructor><![CDATA[
+ this.mController = Components.classes["@mozilla.org/autocomplete/controller;1"].
+ getService(Components.interfaces.nsIAutoCompleteController);
+
+ this._searchBeginHandler = this.initEventHandler("searchbegin");
+ this._searchCompleteHandler = this.initEventHandler("searchcomplete");
+ this._textEnteredHandler = this.initEventHandler("textentered");
+ this._textRevertedHandler = this.initEventHandler("textreverted");
+
+ // For security reasons delay searches on pasted values.
+ this.inputField.controllers.insertControllerAt(0, this._pasteController);
+ ]]></constructor>
+
+ <destructor><![CDATA[
+ this.inputField.controllers.removeController(this._pasteController);
+ ]]></destructor>
+
+ <!-- =================== nsIAutoCompleteInput =================== -->
+
+ <field name="popup"><![CDATA[
+ // Wrap in a block so that the let statements don't
+ // create properties on 'this' (bug 635252).
+ {
+ let popup = null;
+ let popupId = this.getAttribute("autocompletepopup");
+ if (popupId)
+ popup = document.getElementById(popupId);
+ if (!popup) {
+ popup = document.createElement("panel");
+ popup.setAttribute("type", "autocomplete");
+ popup.setAttribute("noautofocus", "true");
+
+ let popupset = document.getAnonymousElementByAttribute(this, "anonid", "popupset");
+ popupset.appendChild(popup);
+ }
+ popup.mInput = this;
+ popup;
+ }
+ ]]></field>
+
+ <property name="controller" onget="return this.mController;" readonly="true"/>
+
+ <property name="popupOpen"
+ onget="return this.popup.popupOpen;"
+ onset="if (val) this.openPopup(); else this.closePopup();"/>
+
+ <property name="disableAutoComplete"
+ onset="this.setAttribute('disableautocomplete', val); return val;"
+ onget="return this.getAttribute('disableautocomplete') == 'true';"/>
+
+ <property name="completeDefaultIndex"
+ onset="this.setAttribute('completedefaultindex', val); return val;"
+ onget="return this.getAttribute('completedefaultindex') == 'true';"/>
+
+ <property name="completeSelectedIndex"
+ onset="this.setAttribute('completeselectedindex', val); return val;"
+ onget="return this.getAttribute('completeselectedindex') == 'true';"/>
+
+ <property name="forceComplete"
+ onset="this.setAttribute('forcecomplete', val); return val;"
+ onget="return this.getAttribute('forcecomplete') == 'true';"/>
+
+ <property name="minResultsForPopup"
+ onset="this.setAttribute('minresultsforpopup', val); return val;"
+ onget="var m = parseInt(this.getAttribute('minresultsforpopup')); return isNaN(m) ? 1 : m;"/>
+
+ <property name="showCommentColumn"
+ onset="this.setAttribute('showcommentcolumn', val); return val;"
+ onget="return this.getAttribute('showcommentcolumn') == 'true';"/>
+
+ <property name="showImageColumn"
+ onset="this.setAttribute('showimagecolumn', val); return val;"
+ onget="return this.getAttribute('showimagecolumn') == 'true';"/>
+
+ <property name="timeout"
+ onset="this.setAttribute('timeout', val); return val;">
+ <getter><![CDATA[
+ // For security reasons delay searches on pasted values.
+ if (this._valueIsPasted) {
+ let t = parseInt(this.getAttribute('pastetimeout'));
+ return isNaN(t) ? 1000 : t;
+ }
+
+ let t = parseInt(this.getAttribute('timeout'));
+ return isNaN(t) ? 50 : t;
+ ]]></getter>
+ </property>
+
+ <property name="searchParam"
+ onget="return this.getAttribute('autocompletesearchparam') || '';"
+ onset="this.setAttribute('autocompletesearchparam', val); return val;"/>
+
+ <property name="searchCount" readonly="true"
+ onget="this.initSearchNames(); return this.mSearchNames.length;"/>
+
+ <field name="shrinkDelay" readonly="true">
+ parseInt(this.getAttribute("shrinkdelay")) || 0
+ </field>
+
+ <field name="PrivateBrowsingUtils" readonly="true">
+ {
+ let utils = {};
+ Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm", utils);
+ utils.PrivateBrowsingUtils
+ }
+ </field>
+
+ <property name="inPrivateContext" readonly="true"
+ onget="return this.PrivateBrowsingUtils.isWindowPrivate(window);"/>
+
+ <property name="noRollupOnCaretMove" readonly="true"
+ onget="return this.popup.getAttribute('norolluponanchor') == 'true'"/>
+
+ <!-- This is the maximum number of drop-down rows we get when we
+ hit the drop marker beside fields that have it (like the URLbar).-->
+ <field name="maxDropMarkerRows" readonly="true">14</field>
+
+ <method name="getSearchAt">
+ <parameter name="aIndex"/>
+ <body><![CDATA[
+ this.initSearchNames();
+ return this.mSearchNames[aIndex];
+ ]]></body>
+ </method>
+
+ <property name="textValue"
+ onget="return this.value;">
+ <setter><![CDATA[
+ // Completing a result should simulate the user typing the result,
+ // so fire an input event.
+ // Trim popup selected values, but never trim results coming from
+ // autofill.
+ if (this.popup.selectedIndex == -1)
+ this._disableTrim = true;
+ this.value = val;
+ this._disableTrim = false;
+
+ var evt = document.createEvent("UIEvents");
+ evt.initUIEvent("input", true, false, window, 0);
+ this.mIgnoreInput = true;
+ this.dispatchEvent(evt);
+ this.mIgnoreInput = false;
+ return this.value;
+ ]]></setter>
+ </property>
+
+ <method name="selectTextRange">
+ <parameter name="aStartIndex"/>
+ <parameter name="aEndIndex"/>
+ <body><![CDATA[
+ this.inputField.setSelectionRange(aStartIndex, aEndIndex);
+ ]]></body>
+ </method>
+
+ <method name="onSearchBegin">
+ <body><![CDATA[
+ if (this.popup && typeof this.popup.onSearchBegin == "function")
+ this.popup.onSearchBegin();
+ if (this._searchBeginHandler)
+ this._searchBeginHandler();
+ ]]></body>
+ </method>
+
+ <method name="onSearchComplete">
+ <body><![CDATA[
+ if (this.mController.matchCount == 0)
+ this.setAttribute("nomatch", "true");
+ else
+ this.removeAttribute("nomatch");
+
+ if (this.ignoreBlurWhileSearching && !this.focused) {
+ this.handleEnter();
+ this.detachController();
+ }
+
+ if (this._searchCompleteHandler)
+ this._searchCompleteHandler();
+ ]]></body>
+ </method>
+
+ <method name="onTextEntered">
+ <body><![CDATA[
+ let rv = false;
+ if (this._textEnteredHandler)
+ rv = this._textEnteredHandler(this.mEnterEvent);
+ this.mEnterEvent = null;
+ return rv;
+ ]]></body>
+ </method>
+
+ <method name="onTextReverted">
+ <body><![CDATA[
+ if (this._textRevertedHandler)
+ return this._textRevertedHandler();
+ return false;
+ ]]></body>
+ </method>
+
+ <!-- =================== nsIDOMXULMenuListElement =================== -->
+
+ <property name="editable" readonly="true"
+ onget="return true;" />
+
+ <property name="crop"
+ onset="this.setAttribute('crop',val); return val;"
+ onget="return this.getAttribute('crop');"/>
+
+ <property name="open"
+ onget="return this.getAttribute('open') == 'true';">
+ <setter><![CDATA[
+ if (val)
+ this.showHistoryPopup();
+ else
+ this.closePopup();
+ ]]></setter>
+ </property>
+
+ <!-- =================== PUBLIC MEMBERS =================== -->
+
+ <field name="valueIsTyped">false</field>
+ <field name="_disableTrim">false</field>
+ <property name="value">
+ <getter><![CDATA[
+ if (typeof this.onBeforeValueGet == "function") {
+ var result = this.onBeforeValueGet();
+ if (result)
+ return result.value;
+ }
+ return this.inputField.value;
+ ]]></getter>
+ <setter><![CDATA[
+ this.mIgnoreInput = true;
+
+ if (typeof this.onBeforeValueSet == "function")
+ val = this.onBeforeValueSet(val);
+
+ if (typeof this.trimValue == "function" && !this._disableTrim)
+ val = this.trimValue(val);
+
+ this.valueIsTyped = false;
+ this.inputField.value = val;
+
+ if (typeof this.formatValue == "function")
+ this.formatValue();
+
+ this.mIgnoreInput = false;
+ var event = document.createEvent('Events');
+ event.initEvent('ValueChange', true, true);
+ this.inputField.dispatchEvent(event);
+ return val;
+ ]]></setter>
+ </property>
+
+ <property name="focused" readonly="true"
+ onget="return this.getAttribute('focused') == 'true';"/>
+
+ <!-- maximum number of rows to display at a time -->
+ <property name="maxRows"
+ onset="this.setAttribute('maxrows', val); return val;"
+ onget="return parseInt(this.getAttribute('maxrows')) || 0;"/>
+
+ <!-- option to allow scrolling through the list via the tab key, rather than
+ tab moving focus out of the textbox -->
+ <property name="tabScrolling"
+ onset="this.setAttribute('tabscrolling', val); return val;"
+ onget="return this.getAttribute('tabscrolling') == 'true';"/>
+
+ <!-- option to completely ignore any blur events while searches are
+ still going on. -->
+ <property name="ignoreBlurWhileSearching"
+ onset="this.setAttribute('ignoreblurwhilesearching', val); return val;"
+ onget="return this.getAttribute('ignoreblurwhilesearching') == 'true';"/>
+
+ <!-- disable key navigation handling in the popup results -->
+ <property name="disableKeyNavigation"
+ onset="this.setAttribute('disablekeynavigation', val); return val;"
+ onget="return this.getAttribute('disablekeynavigation') == 'true';"/>
+
+ <!-- option to highlight entries that don't have any matches -->
+ <property name="highlightNonMatches"
+ onset="this.setAttribute('highlightnonmatches', val); return val;"
+ onget="return this.getAttribute('highlightnonmatches') == 'true';"/>
+
+ <!-- =================== PRIVATE MEMBERS =================== -->
+
+ <!-- ::::::::::::: autocomplete controller ::::::::::::: -->
+
+ <method name="attachController">
+ <body><![CDATA[
+ this.mController.input = this;
+ ]]></body>
+ </method>
+
+ <method name="detachController">
+ <body><![CDATA[
+ if (this.mController.input == this)
+ this.mController.input = null;
+ ]]></body>
+ </method>
+
+ <!-- ::::::::::::: popup opening ::::::::::::: -->
+
+ <method name="openPopup">
+ <body><![CDATA[
+ if (this.focused)
+ this.popup.openAutocompletePopup(this, this);
+ ]]></body>
+ </method>
+
+ <method name="closePopup">
+ <body><![CDATA[
+ this.popup.closePopup();
+ ]]></body>
+ </method>
+
+ <method name="showHistoryPopup">
+ <body><![CDATA[
+ // history dropmarker pushed state
+ function cleanup(popup) {
+ popup.removeEventListener("popupshowing", onShow, false);
+ }
+ function onShow(event) {
+ var popup = event.target, input = popup.input;
+ cleanup(popup);
+ input.setAttribute("open", "true");
+ function onHide() {
+ input.removeAttribute("open");
+ popup.removeEventListener("popuphiding", onHide, false);
+ }
+ popup.addEventListener("popuphiding", onHide, false);
+ }
+ this.popup.addEventListener("popupshowing", onShow, false);
+ setTimeout(cleanup, 1000, this.popup);
+
+ // Store our "normal" maxRows on the popup, so that it can reset the
+ // value when the popup is hidden.
+ this.popup._normalMaxRows = this.maxRows;
+
+ // Increase our maxRows temporarily, since we want the dropdown to
+ // be bigger in this case. The popup's popupshowing/popuphiding
+ // handlers will take care of resetting this.
+ this.maxRows = this.maxDropMarkerRows;
+
+ // Ensure that we have focus.
+ if (!this.focused)
+ this.focus();
+ this.attachController();
+ this.mController.startSearch("");
+ ]]></body>
+ </method>
+
+ <method name="toggleHistoryPopup">
+ <body><![CDATA[
+ // If this method is called on the same event tick as the popup gets
+ // hidden, do nothing to avoid re-opening the popup when the drop
+ // marker is clicked while the popup is still open.
+ if (!this.popup.isPopupHidingTick && !this.popup.popupOpen)
+ this.showHistoryPopup();
+ else
+ this.closePopup();
+ ]]></body>
+ </method>
+
+ <!-- ::::::::::::: event dispatching ::::::::::::: -->
+
+ <method name="initEventHandler">
+ <parameter name="aEventType"/>
+ <body><![CDATA[
+ let handlerString = this.getAttribute("on" + aEventType);
+ if (handlerString) {
+ return (new Function("eventType", "param", handlerString)).bind(this, aEventType);
+ }
+ return null;
+ ]]></body>
+ </method>
+
+ <!-- ::::::::::::: key handling ::::::::::::: -->
+
+ <field name="_selectionDetails">null</field>
+ <method name="onKeyPress">
+ <parameter name="aEvent"/>
+ <body><![CDATA[
+ return this.handleKeyPress(aEvent);
+ ]]></body>
+ </method>
+
+ <method name="handleKeyPress">
+ <parameter name="aEvent"/>
+ <body><![CDATA[
+ if (aEvent.target.localName != "textbox")
+ return true; // Let child buttons of autocomplete take input
+
+ //XXXpch this is so bogus...
+ if (aEvent.defaultPrevented)
+ return false;
+
+ var cancel = false;
+
+ let { AppConstants } =
+ Components.utils.import("resource://gre/modules/AppConstants.jsm", {});
+ // Catch any keys that could potentially move the caret. Ctrl can be
+ // used in combination with these keys on Windows and Linux; and Alt
+ // can be used on OS X, so make sure the unused one isn't used.
+ let metaKey = AppConstants.platform == "macosx" ? aEvent.ctrlKey : aEvent.altKey;
+ if (!this.disableKeyNavigation && !metaKey) {
+ switch (aEvent.keyCode) {
+ case KeyEvent.DOM_VK_LEFT:
+ case KeyEvent.DOM_VK_RIGHT:
+ case KeyEvent.DOM_VK_HOME:
+ cancel = this.mController.handleKeyNavigation(aEvent.keyCode);
+ break;
+ }
+ }
+
+ // Handle keys that are not part of a keyboard shortcut (no Ctrl or Alt)
+ if (!this.disableKeyNavigation && !aEvent.ctrlKey && !aEvent.altKey) {
+ switch (aEvent.keyCode) {
+ case KeyEvent.DOM_VK_TAB:
+ if (this.tabScrolling && this.popup.popupOpen)
+ cancel = this.mController.handleKeyNavigation(aEvent.shiftKey ?
+ KeyEvent.DOM_VK_UP :
+ KeyEvent.DOM_VK_DOWN);
+ else if (this.forceComplete && this.mController.matchCount >= 1)
+ this.mController.handleTab();
+ break;
+ case KeyEvent.DOM_VK_UP:
+ case KeyEvent.DOM_VK_DOWN:
+ case KeyEvent.DOM_VK_PAGE_UP:
+ case KeyEvent.DOM_VK_PAGE_DOWN:
+ cancel = this.mController.handleKeyNavigation(aEvent.keyCode);
+ break;
+ }
+ }
+
+ // Handle keys we know aren't part of a shortcut, even with Alt or
+ // Ctrl.
+ switch (aEvent.keyCode) {
+ case KeyEvent.DOM_VK_ESCAPE:
+ cancel = this.mController.handleEscape();
+ break;
+ case KeyEvent.DOM_VK_RETURN:
+ if (AppConstants.platform == "macosx") {
+ // Prevent the default action, since it will beep on Mac
+ if (aEvent.metaKey)
+ aEvent.preventDefault();
+ }
+ this.mEnterEvent = aEvent;
+ if (this.mController.selection) {
+ this._selectionDetails = {
+ index: this.mController.selection.currentIndex,
+ kind: "key"
+ };
+ }
+ cancel = this.handleEnter();
+ break;
+ case KeyEvent.DOM_VK_DELETE:
+ if (AppConstants.platform == "macosx" && !aEvent.shiftKey) {
+ break;
+ }
+ cancel = this.handleDelete();
+ break;
+ case KeyEvent.DOM_VK_BACK_SPACE:
+ if (AppConstants.platform == "macosx" && aEvent.shiftKey) {
+ cancel = this.handleDelete();
+ }
+ break;
+ case KeyEvent.DOM_VK_DOWN:
+ case KeyEvent.DOM_VK_UP:
+ if (aEvent.altKey)
+ this.toggleHistoryPopup();
+ break;
+ case KeyEvent.DOM_VK_F4:
+ if (AppConstants.platform != "macosx") {
+ this.toggleHistoryPopup();
+ }
+ break;
+ }
+
+ if (cancel) {
+ aEvent.stopPropagation();
+ aEvent.preventDefault();
+ }
+
+ return true;
+ ]]></body>
+ </method>
+
+ <method name="handleEnter">
+ <body><![CDATA[
+ return this.mController.handleEnter(false);
+ ]]></body>
+ </method>
+
+ <method name="handleDelete">
+ <body><![CDATA[
+ return this.mController.handleDelete();
+ ]]></body>
+ </method>
+
+ <!-- ::::::::::::: miscellaneous ::::::::::::: -->
+
+ <method name="initSearchNames">
+ <body><![CDATA[
+ if (!this.mSearchNames) {
+ var names = this.getAttribute("autocompletesearch");
+ if (!names)
+ this.mSearchNames = [];
+ else
+ this.mSearchNames = names.split(" ");
+ }
+ ]]></body>
+ </method>
+
+ <method name="_focus">
+ <!-- doesn't reset this.mController -->
+ <body><![CDATA[
+ this._dontBlur = true;
+ this.focus();
+ this._dontBlur = false;
+ ]]></body>
+ </method>
+
+ <method name="resetActionType">
+ <body><![CDATA[
+ if (this.mIgnoreInput)
+ return;
+ this.removeAttribute("actiontype");
+ ]]></body>
+ </method>
+
+ <field name="_valueIsPasted">false</field>
+ <field name="_pasteController"><![CDATA[
+ ({
+ _autocomplete: this,
+ _kGlobalClipboard: Components.interfaces.nsIClipboard.kGlobalClipboard,
+ supportsCommand: aCommand => aCommand == "cmd_paste",
+ doCommand: function(aCommand) {
+ this._autocomplete._valueIsPasted = true;
+ this._autocomplete.editor.paste(this._kGlobalClipboard);
+ this._autocomplete._valueIsPasted = false;
+ },
+ isCommandEnabled: function(aCommand) {
+ return this._autocomplete.editor.isSelectionEditable &&
+ this._autocomplete.editor.canPaste(this._kGlobalClipboard);
+ },
+ onEvent: function() {}
+ })
+ ]]></field>
+
+ <method name="onInput">
+ <parameter name="aEvent"/>
+ <body><![CDATA[
+ if (!this.mIgnoreInput && this.mController.input == this) {
+ this.valueIsTyped = true;
+ this.mController.handleText();
+ }
+ this.resetActionType();
+ ]]></body>
+ </method>
+ </implementation>
+
+ <handlers>
+ <handler event="input"><![CDATA[
+ this.onInput(event);
+ ]]></handler>
+
+ <handler event="keypress" phase="capturing"
+ action="return this.onKeyPress(event);"/>
+
+ <handler event="compositionstart" phase="capturing"
+ action="if (this.mController.input == this) this.mController.handleStartComposition();"/>
+
+ <handler event="compositionend" phase="capturing"
+ action="if (this.mController.input == this) this.mController.handleEndComposition();"/>
+
+ <handler event="focus" phase="capturing"
+ action="this.attachController();"/>
+
+ <handler event="blur" phase="capturing"><![CDATA[
+ if (!this._dontBlur) {
+ if (this.forceComplete && this.mController.matchCount >= 1) {
+ // mousemove sets selected index. Don't blindly use that selected
+ // index in this blur handler since if the popup is open you can
+ // easily "select" another match just by moving the mouse over it.
+ let filledVal = this.value.replace(/.+ >> /, "").toLowerCase();
+ let selectedVal = null;
+ if (this.popup.selectedIndex >= 0) {
+ selectedVal = this.mController.getFinalCompleteValueAt(
+ this.popup.selectedIndex);
+ }
+ if (selectedVal && filledVal != selectedVal.toLowerCase()) {
+ for (let i = 0; i < this.mController.matchCount; i++) {
+ let matchVal = this.mController.getFinalCompleteValueAt(i);
+ if (matchVal.toLowerCase() == filledVal) {
+ this.popup.selectedIndex = i;
+ break;
+ }
+ }
+ }
+ this.mController.handleEnter(false);
+ }
+ if (!this.ignoreBlurWhileSearching)
+ this.detachController();
+ }
+ ]]></handler>
+ </handlers>
+ </binding>
+
+ <binding id="private-autocomplete-result-popup" extends="chrome://browser/content/autocomplete.xml#private-autocomplete-base-popup">
+ <resources>
+ <stylesheet src="chrome://browser/content/autocomplete.css"/>
+ <stylesheet src="chrome://global/skin/tree.css"/>
+ <stylesheet src="chrome://browser/skin/autocomplete.css"/>
+ </resources>
+
+ <content ignorekeys="true" level="top" consumeoutsideclicks="never">
+ <xul:tree anonid="tree" class="private-autocomplete-tree plain" hidecolumnpicker="true" flex="1" seltype="single">
+ <xul:treecols anonid="treecols">
+ <xul:treecol id="treecolAutoCompleteValue" class="private-autocomplete-treecol" flex="1" overflow="true"/>
+ </xul:treecols>
+ <xul:treechildren class="private-autocomplete-treebody"/>
+ </xul:tree>
+ </content>
+
+ <implementation>
+ <field name="mShowCommentColumn">false</field>
+ <field name="mShowImageColumn">false</field>
+
+ <property name="showCommentColumn"
+ onget="return this.mShowCommentColumn;">
+ <setter>
+ <![CDATA[
+ if (!val && this.mShowCommentColumn) {
+ // reset the flex on the value column and remove the comment column
+ document.getElementById("treecolAutoCompleteValue").setAttribute("flex", 1);
+ this.removeColumn("treecolAutoCompleteComment");
+ } else if (val && !this.mShowCommentColumn) {
+ // reset the flex on the value column and add the comment column
+ document.getElementById("treecolAutoCompleteValue").setAttribute("flex", 2);
+ this.addColumn({id: "treecolAutoCompleteComment", flex: 1});
+ }
+ this.mShowCommentColumn = val;
+ return val;
+ ]]>
+ </setter>
+ </property>
+
+ <property name="showImageColumn"
+ onget="return this.mShowImageColumn;">
+ <setter>
+ <![CDATA[
+ if (!val && this.mShowImageColumn) {
+ // remove the image column
+ this.removeColumn("treecolAutoCompleteImage");
+ } else if (val && !this.mShowImageColumn) {
+ // add the image column
+ this.addColumn({id: "treecolAutoCompleteImage", flex: 1});
+ }
+ this.mShowImageColumn = val;
+ return val;
+ ]]>
+ </setter>
+ </property>
+
+
+ <method name="addColumn">
+ <parameter name="aAttrs"/>
+ <body>
+ <![CDATA[
+ var col = document.createElement("treecol");
+ col.setAttribute("class", "private-autocomplete-treecol");
+ for (var name in aAttrs)
+ col.setAttribute(name, aAttrs[name]);
+ this.treecols.appendChild(col);
+ return col;
+ ]]>
+ </body>
+ </method>
+
+ <method name="removeColumn">
+ <parameter name="aColId"/>
+ <body>
+ <![CDATA[
+ return this.treecols.removeChild(document.getElementById(aColId));
+ ]]>
+ </body>
+ </method>
+
+ <property name="selectedIndex"
+ onget="return this.tree.currentIndex;">
+ <setter>
+ <![CDATA[
+ this.tree.view.selection.select(val);
+ if (this.tree.treeBoxObject.height > 0)
+ this.tree.treeBoxObject.ensureRowIsVisible(val < 0 ? 0 : val);
+ // Fire select event on xul:tree so that accessibility API
+ // support layer can fire appropriate accessibility events.
+ var event = document.createEvent('Events');
+ event.initEvent("select", true, true);
+ this.tree.dispatchEvent(event);
+ return val;
+ ]]></setter>
+ </property>
+
+ <method name="adjustHeight">
+ <body>
+ <![CDATA[
+ // detect the desired height of the tree
+ var bx = this.tree.treeBoxObject;
+ var view = this.tree.view;
+ if (!view)
+ return;
+ var rows = this.maxRows;
+ if (!view.rowCount || (rows && view.rowCount < rows))
+ rows = view.rowCount;
+
+ var height = rows * bx.rowHeight;
+
+ if (height == 0) {
+ this.tree.setAttribute("collapsed", "true");
+ } else {
+ if (this.tree.hasAttribute("collapsed"))
+ this.tree.removeAttribute("collapsed");
+
+ this.tree.setAttribute("height", height);
+ }
+ this.tree.setAttribute("hidescrollbar", view.rowCount <= rows);
+ ]]>
+ </body>
+ </method>
+
+ <method name="openAutocompletePopup">
+ <parameter name="aInput"/>
+ <parameter name="aElement"/>
+ <body><![CDATA[
+ // until we have "baseBinding", (see bug #373652) this allows
+ // us to override openAutocompletePopup(), but still call
+ // the method on the base class
+ this._openAutocompletePopup(aInput, aElement);
+ ]]></body>
+ </method>
+
+ <method name="_openAutocompletePopup">
+ <parameter name="aInput"/>
+ <parameter name="aElement"/>
+ <body><![CDATA[
+ if (!this.mPopupOpen) {
+ this.mInput = aInput;
+ this.view = aInput.controller.QueryInterface(Components.interfaces.nsITreeView);
+ this.invalidate();
+
+ this.showCommentColumn = this.mInput.showCommentColumn;
+ this.showImageColumn = this.mInput.showImageColumn;
+
+ var rect = aElement.getBoundingClientRect();
+ var nav = aElement.ownerDocument.defaultView.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIWebNavigation);
+ var docShell = nav.QueryInterface(Components.interfaces.nsIDocShell);
+ var docViewer = docShell.contentViewer;
+ var width = (rect.right - rect.left) * docViewer.fullZoom;
+ this.setAttribute("width", width > 100 ? width : 100);
+
+ // Adjust the direction of the autocomplete popup list based on the textbox direction, bug 649840
+ var popupDirection = aElement.ownerDocument.defaultView.getComputedStyle(aElement).direction;
+ this.style.direction = popupDirection;
+
+ this.openPopup(aElement, "after_start", 0, 0, false, false);
+ }
+ ]]></body>
+ </method>
+
+ <method name="invalidate">
+ <body><![CDATA[
+ this.adjustHeight();
+ this.tree.treeBoxObject.invalidate();
+ ]]></body>
+ </method>
+
+ <method name="selectBy">
+ <parameter name="aReverse"/>
+ <parameter name="aPage"/>
+ <body><![CDATA[
+ try {
+ var amount = aPage ? 5 : 1;
+ this.selectedIndex = this.getNextIndex(aReverse, amount, this.selectedIndex, this.tree.view.rowCount-1);
+ if (this.selectedIndex == -1) {
+ this.input._focus();
+ }
+ } catch (ex) {
+ // do nothing - occasionally timer-related js errors happen here
+ // e.g. "this.selectedIndex has no properties", when you type fast and hit a
+ // navigation key before this popup has opened
+ }
+ ]]></body>
+ </method>
+
+ <!-- =================== PUBLIC MEMBERS =================== -->
+
+ <field name="tree">
+ document.getAnonymousElementByAttribute(this, "anonid", "tree");
+ </field>
+
+ <field name="treecols">
+ document.getAnonymousElementByAttribute(this, "anonid", "treecols");
+ </field>
+
+ <property name="view"
+ onget="return this.mView;">
+ <setter><![CDATA[
+ // We must do this by hand because the tree binding may not be ready yet
+ this.mView = val;
+ this.tree.boxObject.view = val;
+ ]]></setter>
+ </property>
+
+ </implementation>
+ </binding>
+
+ <binding id="private-autocomplete-base-popup" role="none"
+extends="chrome://global/content/bindings/popup.xml#popup">
+ <implementation implements="nsIAutoCompletePopup">
+ <field name="mInput">null</field>
+ <field name="mPopupOpen">false</field>
+ <field name="mIsPopupHidingTick">false</field>
+
+ <!-- =================== nsIAutoCompletePopup =================== -->
+
+ <property name="input" readonly="true"
+ onget="return this.mInput"/>
+
+ <property name="overrideValue" readonly="true"
+ onget="return null;"/>
+
+ <property name="popupOpen" readonly="true"
+ onget="return this.mPopupOpen;"/>
+
+ <property name="isPopupHidingTick" readonly="true"
+ onget="return this.mIsPopupHidingTick;"/>
+
+ <method name="closePopup">
+ <body>
+ <![CDATA[
+ if (this.mPopupOpen) {
+ this.hidePopup();
+ this.removeAttribute("width");
+ }
+ ]]>
+ </body>
+ </method>
+
+ <!-- This is the default number of rows that we give the autocomplete
+ popup when the textbox doesn't have a "maxrows" attribute
+ for us to use. -->
+ <field name="defaultMaxRows" readonly="true">6</field>
+
+ <!-- In some cases (e.g. when the input's dropmarker button is clicked),
+ the input wants to display a popup with more rows. In that case, it
+ should increase its maxRows property and store the "normal" maxRows
+ in this field. When the popup is hidden, we restore the input's
+ maxRows to the value stored in this field.
+
+ This field is set to -1 between uses so that we can tell when it's
+ been set by the input and when we need to set it in the popupshowing
+ handler. -->
+ <field name="_normalMaxRows">-1</field>
+
+ <property name="maxRows" readonly="true">
+ <getter>
+ <![CDATA[
+ return (this.mInput && this.mInput.maxRows) || this.defaultMaxRows;
+ ]]>
+ </getter>
+ </property>
+
+ <method name="getNextIndex">
+ <parameter name="aReverse"/>
+ <parameter name="aAmount"/>
+ <parameter name="aIndex"/>
+ <parameter name="aMaxRow"/>
+ <body><![CDATA[
+ if (aMaxRow < 0)
+ return -1;
+
+ var newIdx = aIndex + (aReverse?-1:1)*aAmount;
+ if (aReverse && aIndex == -1 || newIdx > aMaxRow && aIndex != aMaxRow)
+ newIdx = aMaxRow;
+ else if (!aReverse && aIndex == -1 || newIdx < 0 && aIndex != 0)
+ newIdx = 0;
+
+ if (newIdx < 0 && aIndex == 0 || newIdx > aMaxRow && aIndex == aMaxRow)
+ aIndex = -1;
+ else
+ aIndex = newIdx;
+
+ return aIndex;
+ ]]></body>
+ </method>
+
+ <method name="onPopupClick">
+ <parameter name="aEvent"/>
+ <body><![CDATA[
+ var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
+ controller.handleEnter(true);
+ ]]></body>
+ </method>
+ </implementation>
+
+ <handlers>
+ <handler event="popupshowing"><![CDATA[
+ // If normalMaxRows wasn't already set by the input, then set it here
+ // so that we restore the correct number when the popup is hidden.
+
+ // Null-check this.mInput; see bug 1017914
+ if (this._normalMaxRows < 0 && this.mInput) {
+ this._normalMaxRows = this.mInput.maxRows;
+ }
+
+ // Set an attribute for styling the popup based on the input.
+ let inputID = "";
+ if (this.mInput && this.mInput.ownerDocument &&
+ this.mInput.ownerDocument.documentURIObject.schemeIs("chrome")) {
+ inputID = this.mInput.id;
+ // Take care of elements with no id that are inside xbl bindings
+ if (!inputID) {
+ let bindingParent = this.mInput.ownerDocument.getBindingParent(this.mInput);
+ if (bindingParent) {
+ inputID = bindingParent.id;
+ }
+ }
+ }
+ this.setAttribute("autocompleteinput", inputID);
+
+ this.mPopupOpen = true;
+ ]]></handler>
+
+ <handler event="popuphiding"><![CDATA[
+ var isListActive = true;
+ if (this.selectedIndex == -1)
+ isListActive = false;
+ var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
+ controller.stopSearch();
+
+ this.removeAttribute("autocompleteinput");
+ this.mPopupOpen = false;
+
+ // Prevent opening popup from historydropmarker mousedown handler
+ // on the same event tick the popup is hidden by the same mousedown
+ // event.
+ this.mIsPopupHidingTick = true;
+ setTimeout(() => {
+ this.mIsPopupHidingTick = false;
+ }, 0);
+
+ // Reset the maxRows property to the cached "normal" value, and reset
+ // _normalMaxRows so that we can detect whether it was set by the input
+ // when the popupshowing handler runs.
+
+ // Null-check this.mInput; see bug 1017914
+ if (this.mInput)
+ this.mInput.maxRows = this._normalMaxRows;
+ this._normalMaxRows = -1;
+ // If the list was being navigated and then closed, make sure
+ // we fire accessible focus event back to textbox
+
+ // Null-check this.mInput; see bug 1017914
+ if (isListActive && this.mInput) {
+ this.mInput.mIgnoreFocus = true;
+ this.mInput._focus();
+ this.mInput.mIgnoreFocus = false;
+ }
+ ]]></handler>
+ </handlers>
+ </binding>
+
+ <binding id="private-autocomplete-rich-result-popup" extends="chrome://browser/content/autocomplete.xml#private-autocomplete-base-popup">
+ <resources>
+ <stylesheet src="chrome://browser/content/autocomplete.css"/>
+ <stylesheet src="chrome://browser/skin/autocomplete.css"/>
+ </resources>
+
+ <content ignorekeys="true" level="top" consumeoutsideclicks="never">
+ <xul:richlistbox anonid="richlistbox" class="private-autocomplete-richlistbox" flex="1"/>
+ <xul:hbox>
+ <children/>
+ </xul:hbox>
+ </content>
+
+ <implementation implements="nsIAutoCompletePopup">
+ <field name="_currentIndex">0</field>
+ <field name="_rowHeight">0</field>
+ <field name="_rlbAnimated">false</field>
+
+ <!-- =================== nsIAutoCompletePopup =================== -->
+
+ <property name="selectedIndex"
+ onget="return this.richlistbox.selectedIndex;">
+ <setter>
+ <![CDATA[
+ this.richlistbox.selectedIndex = val;
+
+ // when clearing the selection (val == -1, so selectedItem will be
+ // null), we want to scroll back to the top. see bug #406194
+ this.richlistbox.ensureElementIsVisible(
+ this.richlistbox.selectedItem || this.richlistbox.firstChild);
+
+ return val;
+ ]]>
+ </setter>
+ </property>
+
+ <method name="onSearchBegin">
+ <body><![CDATA[
+ this.richlistbox.mouseSelectedIndex = -1;
+ ]]></body>
+ </method>
+
+ <method name="openAutocompletePopup">
+ <parameter name="aInput"/>
+ <parameter name="aElement"/>
+ <body>
+ <![CDATA[
+ // until we have "baseBinding", (see bug #373652) this allows
+ // us to override openAutocompletePopup(), but still call
+ // the method on the base class
+ this._openAutocompletePopup(aInput, aElement);
+ ]]>
+ </body>
+ </method>
+
+ <method name="_openAutocompletePopup">
+ <parameter name="aInput"/>
+ <parameter name="aElement"/>
+ <body>
+ <![CDATA[
+ if (!this.mPopupOpen) {
+ this.mInput = aInput;
+ // clear any previous selection, see bugs 400671 and 488357
+ this.selectedIndex = -1;
+
+ var width = aElement.getBoundingClientRect().width;
+ this.setAttribute("width", width > 100 ? width : 100);
+ // invalidate() depends on the width attribute
+ this._invalidate();
+
+ this.openPopup(aElement, "after_start", 0, 0, false, false);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="invalidate">
+ <parameter name="reason"/>
+ <body>
+ <![CDATA[
+ // Don't bother doing work if we're not even showing
+ if (!this.mPopupOpen)
+ return;
+
+ this._invalidate(reason);
+ ]]>
+ </body>
+ </method>
+
+ <method name="_invalidate">
+ <parameter name="reason"/>
+ <body>
+ <![CDATA[
+ // collapsed if no matches
+ this.richlistbox.collapsed = (this._matchCount == 0);
+
+ // Update the richlistbox height.
+ if (this._adjustHeightTimeout) {
+ clearTimeout(this._adjustHeightTimeout);
+ }
+ if (this._shrinkTimeout) {
+ clearTimeout(this._shrinkTimeout);
+ }
+ this._adjustHeightTimeout = setTimeout(() => this.adjustHeight(), 0);
+
+ this._currentIndex = 0;
+ if (this._appendResultTimeout) {
+ clearTimeout(this._appendResultTimeout);
+ }
+ this._appendCurrentResult(reason);
+ ]]>
+ </body>
+ </method>
+
+ <property name="maxResults" readonly="true">
+ <getter>
+ <![CDATA[
+ // this is how many richlistitems will be kept around
+ // (note, this getter may be overridden)
+ return 20;
+ ]]>
+ </getter>
+ </property>
+
+ <property name="_matchCount" readonly="true">
+ <getter>
+ <![CDATA[
+ return Math.min(this.mInput.controller.matchCount, this.maxResults);
+ ]]>
+ </getter>
+ </property>
+
+ <method name="_collapseUnusedItems">
+ <body>
+ <![CDATA[
+ let existingItemsCount = this.richlistbox.childNodes.length;
+ for (let i = this._matchCount; i < existingItemsCount; ++i) {
+ this.richlistbox.childNodes[i].collapsed = true;
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="adjustHeight">
+ <body>
+ <![CDATA[
+ // Figure out how many rows to show
+ let rows = this.richlistbox.childNodes;
+ let numRows = Math.min(this._matchCount, this.maxRows, rows.length);
+
+ this.removeAttribute("height");
+
+ // Default the height to 0 if we have no rows to show
+ let height = 0;
+ if (numRows) {
+ if (!this._rowHeight) {
+ let firstRowRect = rows[0].getBoundingClientRect();
+ this._rowHeight = firstRowRect.height;
+
+ let transition =
+ window.getComputedStyle(this.richlistbox).transitionProperty;
+ this._rlbAnimated = transition && transition != "none";
+
+ // Set a fixed max-height to avoid flicker when growing the panel.
+ this.richlistbox.style.maxHeight = (this._rowHeight * this.maxRows) + "px";
+ }
+
+ // Calculate the height to have the first row to last row shown
+ height = this._rowHeight * numRows;
+ }
+
+ let animate = this._rlbAnimated &&
+ this.getAttribute("dontanimate") != "true";
+ let currentHeight = this.richlistbox.getBoundingClientRect().height;
+ if (height > currentHeight) {
+ // Grow immediately.
+ if (animate) {
+ this.richlistbox.removeAttribute("height");
+ this.richlistbox.style.height = height + "px";
+ } else {
+ this.richlistbox.style.removeProperty("height");
+ this.richlistbox.height = height;
+ }
+ } else {
+ // Delay shrinking to avoid flicker.
+ this._shrinkTimeout = setTimeout(() => {
+ this._collapseUnusedItems();
+ if (animate) {
+ this.richlistbox.removeAttribute("height");
+ this.richlistbox.style.height = height + "px";
+ } else {
+ this.richlistbox.style.removeProperty("height");
+ this.richlistbox.height = height;
+ }
+ }, this.mInput.shrinkDelay);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="_appendCurrentResult">
+ <parameter name="invalidateReason"/>
+ <body>
+ <![CDATA[
+ var controller = this.mInput.controller;
+ var matchCount = this._matchCount;
+ var existingItemsCount = this.richlistbox.childNodes.length;
+
+ // Process maxRows per chunk to improve performance and user experience
+ for (let i = 0; i < this.maxRows; i++) {
+ if (this._currentIndex >= matchCount)
+ break;
+
+ var item;
+
+ // trim the leading/trailing whitespace
+ var trimmedSearchString = controller.searchString.replace(/^\s+/, "").replace(/\s+$/, "");
+
+ let url = controller.getValueAt(this._currentIndex);
+
+ if (this._currentIndex < existingItemsCount) {
+ // re-use the existing item
+ item = this.richlistbox.childNodes[this._currentIndex];
+
+ // Completely reuse the existing richlistitem for invalidation
+ // due to new results, but only when: the item is the same, *OR*
+ // we are about to replace the currently mouse-selected item, to
+ // avoid surprising the user.
+ let iface = Components.interfaces.nsIAutoCompletePopup;
+ if (item.getAttribute("text") == trimmedSearchString &&
+ invalidateReason == iface.INVALIDATE_REASON_NEW_RESULT &&
+ (item.getAttribute("url") == url ||
+ this.richlistbox.mouseSelectedIndex === this._currentIndex)) {
+ item.collapsed = false;
+ this._currentIndex++;
+ continue;
+ }
+ }
+ else {
+ // need to create a new item
+ item = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "richlistitem");
+ }
+
+ // set these attributes before we set the class
+ // so that we can use them from the constructor
+ let iconURI = controller.getImageAt(this._currentIndex);
+ item.setAttribute("image", iconURI);
+ item.setAttribute("url", url);
+ item.setAttribute("title", controller.getCommentAt(this._currentIndex));
+ item.setAttribute("type", controller.getStyleAt(this._currentIndex));
+ item.setAttribute("text", trimmedSearchString);
+
+ if (this._currentIndex < existingItemsCount) {
+ // re-use the existing item
+ item._adjustAcItem();
+ item.collapsed = false;
+ }
+ else {
+ // set the class at the end so we can use the attributes
+ // in the xbl constructor
+ item.className = "private-autocomplete-richlistitem";
+ this.richlistbox.appendChild(item);
+ }
+
+ this._currentIndex++;
+ }
+
+ if (typeof this.onResultsAdded == "function")
+ this.onResultsAdded();
+
+ if (this._currentIndex < matchCount) {
+ // yield after each batch of items so that typing the url bar is
+ // responsive
+ this._appendResultTimeout = setTimeout(() => this._appendCurrentResult(), 0);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="selectBy">
+ <parameter name="aReverse"/>
+ <parameter name="aPage"/>
+ <body>
+ <![CDATA[
+ try {
+ var amount = aPage ? 5 : 1;
+
+ // because we collapsed unused items, we can't use this.richlistbox.getRowCount(), we need to use the matchCount
+ this.selectedIndex = this.getNextIndex(aReverse, amount, this.selectedIndex, this._matchCount - 1);
+ if (this.selectedIndex == -1) {
+ this.input._focus();
+ }
+ } catch (ex) {
+ // do nothing - occasionally timer-related js errors happen here
+ // e.g. "this.selectedIndex has no properties", when you type fast and hit a
+ // navigation key before this popup has opened
+ }
+ ]]>
+ </body>
+ </method>
+
+ <field name="richlistbox">
+ document.getAnonymousElementByAttribute(this, "anonid", "richlistbox");
+ </field>
+
+ <property name="view"
+ onget="return this.mInput.controller;"
+ onset="return val;"/>
+
+ </implementation>
+ </binding>
+
+ <binding id="private-autocomplete-richlistitem" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
+ <content>
+ <xul:hbox align="center" class="ac-title-box">
+ <xul:image xbl:inherits="src=image" class="ac-site-icon"/>
+ <xul:hbox anonid="title-box" class="ac-title" flex="1"
+ onunderflow="_doUnderflow('_title');"
+ onoverflow="_doOverflow('_title');">
+ <xul:description anonid="title" class="ac-normal-text ac-comment" xbl:inherits="selected"/>
+ </xul:hbox>
+ <xul:label anonid="title-overflow-ellipsis" xbl:inherits="selected"
+ class="ac-ellipsis-after ac-comment"/>
+ <xul:hbox anonid="extra-box" class="ac-extra" align="center" hidden="true">
+ <xul:image class="ac-result-type-tag"/>
+ <xul:label class="ac-normal-text ac-comment" xbl:inherits="selected" value=":"/>
+ <xul:description anonid="extra" class="ac-normal-text ac-comment" xbl:inherits="selected"/>
+ </xul:hbox>
+ <xul:image anonid="type-image" class="ac-type-icon" xbl:inherits="selected"/>
+ </xul:hbox>
+ <xul:hbox align="center" class="ac-url-box">
+ <xul:spacer class="ac-site-icon"/>
+ <xul:image class="ac-action-icon"/>
+ <xul:hbox anonid="url-box" class="ac-url" flex="1"
+ onunderflow="_doUnderflow('_url');"
+ onoverflow="_doOverflow('_url');">
+ <xul:description anonid="url" class="ac-normal-text ac-url-text"
+ xbl:inherits="selected type"/>
+ <xul:description anonid="action" class="ac-normal-text ac-action-text"
+ xbl:inherits="selected type"/>
+ </xul:hbox>
+ <xul:label anonid="url-overflow-ellipsis" xbl:inherits="selected"
+ class="ac-ellipsis-after ac-url-text"/>
+ <xul:spacer class="ac-type-icon"/>
+ </xul:hbox>
+ </content>
+ <implementation implements="nsIDOMXULSelectControlItemElement">
+ <constructor>
+ <![CDATA[
+ let ellipsis = "\u2026";
+ try {
+ ellipsis = Components.classes["@mozilla.org/preferences-service;1"].
+ getService(Components.interfaces.nsIPrefBranch).
+ getComplexValue("intl.ellipsis",
+ Components.interfaces.nsIPrefLocalizedString).data;
+ } catch (ex) {
+ // Do nothing.. we already have a default
+ }
+
+ this._urlOverflowEllipsis = document.getAnonymousElementByAttribute(this, "anonid", "url-overflow-ellipsis");
+ this._titleOverflowEllipsis = document.getAnonymousElementByAttribute(this, "anonid", "title-overflow-ellipsis");
+
+ this._urlOverflowEllipsis.value = ellipsis;
+ this._titleOverflowEllipsis.value = ellipsis;
+
+ this._typeImage = document.getAnonymousElementByAttribute(this, "anonid", "type-image");
+
+ this._urlBox = document.getAnonymousElementByAttribute(this, "anonid", "url-box");
+ this._url = document.getAnonymousElementByAttribute(this, "anonid", "url");
+ this._action = document.getAnonymousElementByAttribute(this, "anonid", "action");
+
+ this._titleBox = document.getAnonymousElementByAttribute(this, "anonid", "title-box");
+ this._title = document.getAnonymousElementByAttribute(this, "anonid", "title");
+
+ this._extraBox = document.getAnonymousElementByAttribute(this, "anonid", "extra-box");
+ this._extra = document.getAnonymousElementByAttribute(this, "anonid", "extra");
+
+ this._adjustAcItem();
+ ]]>
+ </constructor>
+
+ <property name="label" readonly="true">
+ <getter>
+ <![CDATA[
+ // This property is a string that is read aloud by screen readers,
+ // so it must not contain anything that should not be user-facing.
+
+ let parts = [
+ this.getAttribute("title"),
+ this.getAttribute("displayurl"),
+ ];
+ let label = parts.filter(str => str).join(" ")
+
+ // allow consumers that have extended popups to override
+ // the label values for the richlistitems
+ let panel = this.parentNode.parentNode;
+ if (panel.createResultLabel) {
+ return panel.createResultLabel(this, label);
+ }
+
+ return label;
+ ]]>
+ </getter>
+ </property>
+
+ <property name="_stringBundle">
+ <getter><![CDATA[
+ if (!this.__stringBundle) {
+ this.__stringBundle = Services.strings.createBundle("chrome://global/locale/autocomplete.properties");
+ }
+ return this.__stringBundle;
+ ]]></getter>
+ </property>
+
+ <field name="_boundaryCutoff">null</field>
+
+ <property name="boundaryCutoff" readonly="true">
+ <getter>
+ <![CDATA[
+ if (!this._boundaryCutoff) {
+ this._boundaryCutoff =
+ Components.classes["@mozilla.org/preferences-service;1"].
+ getService(Components.interfaces.nsIPrefBranch).
+ getIntPref("toolkit.autocomplete.richBoundaryCutoff");
+ }
+ return this._boundaryCutoff;
+ ]]>
+ </getter>
+ </property>
+
+ <method name="_getBoundaryIndices">
+ <parameter name="aText"/>
+ <parameter name="aSearchTokens"/>
+ <body>
+ <![CDATA[
+ // Short circuit for empty search ([""] == "")
+ if (aSearchTokens == "")
+ return [0, aText.length];
+
+ // Find which regions of text match the search terms
+ let regions = [];
+ for (let search of Array.prototype.slice.call(aSearchTokens)) {
+ let matchIndex = -1;
+ let searchLen = search.length;
+
+ // Find all matches of the search terms, but stop early for perf
+ let lowerText = aText.substr(0, this.boundaryCutoff).toLowerCase();
+ while ((matchIndex = lowerText.indexOf(search, matchIndex + 1)) >= 0) {
+ regions.push([matchIndex, matchIndex + searchLen]);
+ }
+ }
+
+ // Sort the regions by start position then end position
+ regions = regions.sort((a, b) => {
+ let start = a[0] - b[0];
+ return (start == 0) ? a[1] - b[1] : start;
+ });
+
+ // Generate the boundary indices from each region
+ let start = 0;
+ let end = 0;
+ let boundaries = [];
+ let len = regions.length;
+ for (let i = 0; i < len; i++) {
+ // We have a new boundary if the start of the next is past the end
+ let region = regions[i];
+ if (region[0] > end) {
+ // First index is the beginning of match
+ boundaries.push(start);
+ // Second index is the beginning of non-match
+ boundaries.push(end);
+
+ // Track the new region now that we've stored the previous one
+ start = region[0];
+ }
+
+ // Push back the end index for the current or new region
+ end = Math.max(end, region[1]);
+ }
+
+ // Add the last region
+ boundaries.push(start);
+ boundaries.push(end);
+
+ // Put on the end boundary if necessary
+ if (end < aText.length)
+ boundaries.push(aText.length);
+
+ // Skip the first item because it's always 0
+ return boundaries.slice(1);
+ ]]>
+ </body>
+ </method>
+
+ <method name="_getSearchTokens">
+ <parameter name="aSearch"/>
+ <body>
+ <![CDATA[
+ let search = aSearch.toLowerCase();
+ return search.split(/\s+/);
+ ]]>
+ </body>
+ </method>
+
+ <method name="_setUpDescription">
+ <parameter name="aDescriptionElement"/>
+ <parameter name="aText"/>
+ <parameter name="aNoEmphasis"/>
+ <body>
+ <![CDATA[
+ // Get rid of all previous text
+ while (aDescriptionElement.hasChildNodes())
+ aDescriptionElement.removeChild(aDescriptionElement.firstChild);
+
+ // If aNoEmphasis is specified, don't add any emphasis
+ if (aNoEmphasis) {
+ aDescriptionElement.appendChild(document.createTextNode(aText));
+ return;
+ }
+
+ // Get the indices that separate match and non-match text
+ let search = this.getAttribute("text");
+ let tokens = this._getSearchTokens(search);
+ let indices = this._getBoundaryIndices(aText, tokens);
+
+ let next;
+ let start = 0;
+ let len = indices.length;
+ // Even indexed boundaries are matches, so skip the 0th if it's empty
+ for (let i = indices[0] == 0 ? 1 : 0; i < len; i++) {
+ next = indices[i];
+ let text = aText.substr(start, next - start);
+ start = next;
+
+ if (i % 2 == 0) {
+ // Emphasize the text for even indices
+ let span = aDescriptionElement.appendChild(
+ document.createElementNS("http://www.w3.org/1999/xhtml", "span"));
+ span.className = "ac-emphasize-text";
+ span.textContent = text;
+ } else {
+ // Otherwise, it's plain text
+ aDescriptionElement.appendChild(document.createTextNode(text));
+ }
+ }
+ ]]>
+ </body>
+ </method>
+
+ <!--
+ This will generate an array of emphasis pairs for use with
+ _setUpEmphasisedSections(). Each pair is a tuple (array) that
+ represents a block of text - containing the text of that block, and a
+ boolean for whether that block should have an emphasis styling applied
+ to it.
+
+ These pairs are generated by parsing a localised string (aSourceString)
+ with parameters, in the format that is used by
+ nsIStringBundle.formatStringFromName():
+
+ "textA %1$S textB textC %2$S"
+
+ Or:
+
+ "textA %S"
+
+ Where "%1$S", "%2$S", and "%S" are intended to be replaced by provided
+ replacement strings. These are specified an array of tuples
+ (aReplacements), each containing the replacement text and a boolean for
+ whether that text should have an emphasis styling applied. This is used
+ as a 1-based array - ie, "%1$S" is replaced by the item in the first
+ index of aReplacements, "%2$S" by the second, etc. "%S" will always
+ match the first index.
+ -->
+ <method name="_generateEmphasisPairs">
+ <parameter name="aSourceString"/>
+ <parameter name="aReplacements"/>
+ <body>
+ <![CDATA[
+ let pairs = [];
+
+ // Split on %S, %1$S, %2$S, etc. ie:
+ // "textA %S"
+ // becomes ["textA ", "%S"]
+ // "textA %1$S textB textC %2$S"
+ // becomes ["textA ", "%1$S", " textB textC ", "%2$S"]
+ let parts = aSourceString.split(/(%(?:[0-9]+\$)?S)/);
+
+ for (let part of parts) {
+ // The above regex will actually give us an empty string at the
+ // end - we don't want that, as we don't want to later generate an
+ // empty text node for it.
+ if (part.length === 0)
+ continue;
+
+ // Determine if this token is a replacement token or a normal text
+ // token. If it is a replacement token, we want to extract the
+ // numerical number. However, we still want to match on "$S".
+ let match = part.match(/^%(?:([0-9]+)\$)?S$/);
+
+ if (match) {
+ // "%S" doesn't have a numerical number in it, but will always
+ // be assumed to be 1. Furthermore, the input string specifies
+ // these with a 1-based index, but we want a 0-based index.
+ let index = (match[1] || 1) - 1;
+
+ if (index >= 0 && index < aReplacements.length) {
+ pairs.push([...aReplacements[index]]);
+ }
+ } else {
+ pairs.push([part]);
+ }
+ }
+
+ return pairs;
+ ]]>
+ </body>
+ </method>
+
+ <!--
+ _setUpEmphasisedSections() has the same use as _setUpDescription,
+ except instead of taking a string and highlighting given tokens, it takes
+ an array of pairs generated by _generateEmphasisPairs(). This allows
+ control over emphasising based on specific blocks of text, rather than
+ search for substrings.
+ -->
+ <method name="_setUpEmphasisedSections">
+ <parameter name="aDescriptionElement"/>
+ <parameter name="aTextPairs"/>
+ <body>
+ <![CDATA[
+ // Get rid of all previous text
+ while (aDescriptionElement.hasChildNodes())
+ aDescriptionElement.firstChild.remove();
+
+ for (let [text, emphasise] of aTextPairs) {
+ if (emphasise) {
+ let span = aDescriptionElement.appendChild(
+ document.createElementNS("http://www.w3.org/1999/xhtml", "span"));
+ span.textContent = text;
+ switch(emphasise) {
+ case "match":
+ span.className = "ac-emphasize-text";
+ break;
+ case "selected":
+ span.className = "ac-selected-text";
+ break;
+ }
+ } else {
+ aDescriptionElement.appendChild(document.createTextNode(text));
+ }
+ }
+ ]]>
+ </body>
+ </method>
+
+ <field name="_textToSubURI">null</field>
+ <method name="_unescapeUrl">
+ <parameter name="url"/>
+ <body>
+ <![CDATA[
+ if (!this._textToSubURI) {
+ this._textToSubURI =
+ Components.classes["@mozilla.org/intl/texttosuburi;1"]
+ .getService(Components.interfaces.nsITextToSubURI);
+ }
+ return this._textToSubURI.unEscapeURIForUI("UTF-8", url);
+ ]]>
+ </body>
+ </method>
+
+ <method name="_adjustAcItem">
+ <body>
+ <![CDATA[
+ let originalUrl = this.getAttribute("url");
+ let title = this.getAttribute("title");
+ let type = this.getAttribute("type");
+
+ let displayUrl;
+ let emphasiseTitle = true;
+ let emphasiseUrl = true;
+
+ // Hide the title's extra box by default, until we find out later if
+ // we need extra stuff.
+ this._extraBox.hidden = true;
+ this._titleBox.flex = 1;
+ this._typeImage.hidden = false;
+
+ this.removeAttribute("actiontype");
+ this.classList.remove("overridable-action");
+
+ // The ellipses are hidden via their visibility so that they always
+ // take up space and don't pop in on top of text when shown. For
+ // keyword searches, however, the title ellipsis should not take up
+ // space when hidden. Setting the hidden property accomplishes that.
+ this._titleOverflowEllipsis.hidden = false;
+
+ let types = new Set(type.split(/\s+/));
+
+ // Remove types that should ultimately not be in the `type` string.
+ let initialTypes = new Set(types);
+ types.delete("action");
+ types.delete("autofill");
+ types.delete("heuristic");
+ types.delete("search");
+
+ type = [...types][0] || "";
+
+ // If the type includes an action, set up the item appropriately.
+ if (initialTypes.has("action")) {
+ let action = this._parseActionUrl(originalUrl);
+ this.setAttribute("actiontype", action.type);
+
+ if (action.type == "switchtab") {
+ this.classList.add("overridable-action");
+ displayUrl = this._unescapeUrl(action.params.url);
+ let desc = this._stringBundle.GetStringFromName("switchToTab");
+ this._setUpDescription(this._action, desc, true);
+ } else if (action.type == "remotetab") {
+ displayUrl = this._unescapeUrl(action.params.url);
+ let desc = action.params.deviceName;
+ this._setUpDescription(this._action, desc, true);
+ } else if (action.type == "searchengine") {
+ emphasiseUrl = false;
+
+ // The order here is not localizable, we default to appending
+ // "- Search with Engine" to the search string, to be able to
+ // properly generate emphasis pairs. That said, no localization
+ // changed the order while it was possible, so doesn't look like
+ // there's a strong need for that.
+ let {engineName, searchSuggestion, searchQuery} = action.params;
+ let engineStr = " - " +
+ this._stringBundle.formatStringFromName("searchWithEngine",
+ [engineName], 1);
+
+ // Make the title by generating an array of pairs and its
+ // corresponding interpolation string (e.g., "%1$S") to pass to
+ // _generateEmphasisPairs.
+ let pairs;
+ if (searchSuggestion) {
+ // Check if the search query appears in the suggestion. It may
+ // not. If it does, then emphasize the query in the suggestion
+ // and otherwise just include the suggestion without emphasis.
+ let idx = searchSuggestion.indexOf(searchQuery);
+ if (idx >= 0) {
+ pairs = [
+ [searchSuggestion.substring(0, idx), ""],
+ [searchQuery, "match"],
+ [searchSuggestion.substring(idx + searchQuery.length), ""],
+ ];
+ } else {
+ pairs = [
+ [searchSuggestion, ""],
+ ];
+ }
+ } else {
+ pairs = [
+ [searchQuery, ""],
+ ];
+ }
+ pairs.push([engineStr, "selected"]);
+ let interpStr = pairs.map((pair, i) => `%${i + 1}$S`).join("");
+ title = this._generateEmphasisPairs(interpStr, pairs);
+
+ // If this is a default search match, we remove the image so we
+ // can style it ourselves with a generic search icon.
+ // We don't do this when matching an aliased search engine,
+ // because the icon helps with recognising which engine will be
+ // used (when using the default engine, we don't need that
+ // recognition).
+ if (!action.params.alias) {
+ this.removeAttribute("image");
+ }
+ } else if (action.type == "visiturl") {
+ emphasiseUrl = false;
+ displayUrl = this._unescapeUrl(action.params.url);
+ let sourceStr = this._stringBundle.GetStringFromName("visitURL");
+ title = this._generateEmphasisPairs(sourceStr, [
+ [displayUrl, "match"],
+ ]);
+ }
+ }
+
+ // Check if we have a search engine name
+ if (initialTypes.has("search")) {
+ emphasiseUrl = false;
+
+ const TITLE_SEARCH_ENGINE_SEPARATOR = " \u00B7\u2013\u00B7 ";
+
+ let searchEngine = "";
+ [title, searchEngine] = title.split(TITLE_SEARCH_ENGINE_SEPARATOR);
+ displayUrl = this._stringBundle.formatStringFromName("searchWithEngine", [searchEngine], 1);
+ }
+
+ if (!displayUrl) {
+ let input = this.parentNode.parentNode.input;
+ let url = typeof(input.trimValue) == "function" ?
+ input.trimValue(originalUrl) :
+ originalUrl;
+ displayUrl = this._unescapeUrl(url);
+ }
+ this.setAttribute("displayurl", displayUrl);
+
+ // Check if we have an auto-fill URL
+ if (initialTypes.has("autofill")) {
+ emphasiseUrl = false;
+
+ let sourceStr = this._stringBundle.GetStringFromName("visitURL");
+ title = this._generateEmphasisPairs(sourceStr, [
+ [displayUrl, "match"],
+ ]);
+ }
+
+ // If we have a tag match, show the tags and icon
+ if (type == "tag" || type == "bookmark-tag") {
+ // Configure the extra box for tags display
+ this._extraBox.hidden = false;
+ this._extraBox.childNodes[0].hidden = false;
+ this._extraBox.childNodes[1].hidden = true;
+ this._extraBox.pack = "end";
+ this._titleBox.flex = 1;
+
+ // The title is separated from the tags by an endash
+ let tags;
+ [, title, tags] = title.match(/^(.+) \u2013 (.+)$/);
+
+ // Each tag is split by a comma in an undefined order, so sort it
+ let sortedTags = tags.split(",").sort().join(", ");
+
+ // Emphasize the matching text in the tags
+ this._setUpDescription(this._extra, sortedTags);
+
+ // If we're suggesting bookmarks, then treat tagged matches as
+ // bookmarks for the star.
+ if (type == "bookmark-tag") {
+ type = "bookmark";
+ } else {
+ this._typeImage.hidden = true;
+ }
+ // keyword and favicon type results for search engines
+ // have an extra magnifying glass icon after them
+ } else if (type == "keyword" || (initialTypes.has("search") &&
+ initialTypes.has("favicon"))) {
+ // Configure the extra box for keyword display
+ this._extraBox.hidden = false;
+ this._extraBox.childNodes[0].hidden = true;
+ // The second child node is ":" and it should be hidden for non keyword types
+ this._extraBox.childNodes[1].hidden = type == "keyword" ? false : true;
+ this._extraBox.pack = "start";
+ this._titleBox.flex = 0;
+
+ // Hide the ellipsis so it doesn't take up space.
+ this._titleOverflowEllipsis.hidden = true;
+
+ if (type == "keyword") {
+ // Put the parameters next to the title if we have any
+ let search = this.getAttribute("text");
+ let params = "";
+ let paramsIndex = search.indexOf(" ");
+ if (paramsIndex != -1)
+ params = search.substr(paramsIndex + 1);
+
+ // Emphasize the keyword parameters
+ this._setUpDescription(this._extra, params);
+
+ // Don't emphasize keyword searches in the title or url
+ emphasiseUrl = false;
+ emphasiseTitle = false;
+ } else {
+ // Don't show any description for non keyword types.
+ this._setUpDescription(this._extra, "", true);
+ }
+ // If the result has the type favicon and a known search provider,
+ // customize it the same way as a keyword result.
+ type = "keyword";
+ }
+
+ // Give the image the icon style and a special one for the type
+ this._typeImage.className = "ac-type-icon" +
+ (type ? " ac-result-type-" + type : "");
+
+ // Show the domain as the title if we don't have a title.
+ if (title == "") {
+ title = displayUrl;
+ try {
+ let uri = Services.io.newURI(originalUrl, null, null);
+ // Not all valid URLs have a domain.
+ if (uri.host)
+ title = uri.host;
+ } catch (e) {}
+ }
+
+ // Emphasize the matching search terms for the description
+ if (Array.isArray(title))
+ this._setUpEmphasisedSections(this._title, title);
+ else
+ this._setUpDescription(this._title, title, !emphasiseTitle);
+
+ this._setUpDescription(this._url, displayUrl, !emphasiseUrl);
+
+ // Set up overflow on a timeout because the contents of the box
+ // might not have a width yet even though we just changed them
+ setTimeout(this._setUpOverflow, 0, this._titleBox, this._titleOverflowEllipsis);
+ setTimeout(this._setUpOverflow, 0, this._urlBox, this._urlOverflowEllipsis);
+ ]]>
+ </body>
+ </method>
+
+ <method name="_parseActionUrl">
+ <parameter name="aUrl"/>
+ <body><![CDATA[
+ if (!aUrl.startsWith("moz-action:"))
+ return null;
+
+ // URL is in the format moz-action:ACTION,PARAMS
+ // Where PARAMS is a JSON encoded object.
+ let [, type, params] = aUrl.match(/^moz-action:([^,]+),(.*)$/);
+
+ let action = {
+ type: type,
+ };
+
+ try {
+ action.params = JSON.parse(params);
+ for (let key in action.params) {
+ action.params[key] = decodeURIComponent(action.params[key]);
+ }
+ } catch (e) {
+ // If this failed, we assume that params is not a JSON object, and
+ // is instead just a flat string. This will happen when
+ // UnifiedComplete is disabled - in which case, the param is always
+ // a URL.
+ action.params = {
+ url: params,
+ }
+ }
+
+ return action;
+ ]]></body>
+ </method>
+
+ <method name="_setUpOverflow">
+ <parameter name="aParentBox"/>
+ <parameter name="aEllipsis"/>
+ <body>
+ <![CDATA[
+ // Hide the ellipsis incase there's just enough to not underflow
+ aEllipsis.style.visibility = "hidden";
+
+ // Start with the parent's width and subtract off its children
+ let tooltip = [];
+ let children = aParentBox.childNodes;
+ let widthDiff = aParentBox.boxObject.width;
+
+ for (let i = 0; i < children.length; i++) {
+ // Only consider a child if it actually takes up space
+ let childWidth = children[i].boxObject.width;
+ if (childWidth > 0) {
+ // Subtract a little less to account for subpixel rounding
+ widthDiff -= childWidth - .5;
+
+ // Add to the tooltip if it's not hidden and has text
+ let childText = children[i].textContent;
+ if (childText)
+ tooltip.push(childText);
+ }
+ }
+
+ // If the children take up more space than the parent.. overflow!
+ if (widthDiff < 0) {
+ // Re-show the ellipsis now that we know it's needed
+ aEllipsis.style.visibility = "visible";
+
+ // Separate text components with a ndash --
+ aParentBox.tooltipText = tooltip.join(" \u2013 ");
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="_doUnderflow">
+ <parameter name="aName"/>
+ <body>
+ <![CDATA[
+ // Hide the ellipsis right when we know we're underflowing instead of
+ // waiting for the timeout to trigger the _setUpOverflow calculations
+ this[aName + "Box"].tooltipText = "";
+ this[aName + "OverflowEllipsis"].style.visibility = "hidden";
+ ]]>
+ </body>
+ </method>
+
+ <method name="_doOverflow">
+ <parameter name="aName"/>
+ <body>
+ <![CDATA[
+ this._setUpOverflow(this[aName + "Box"],
+ this[aName + "OverflowEllipsis"]);
+ ]]>
+ </body>
+ </method>
+
+ </implementation>
+ </binding>
+
+ <binding id="private-autocomplete-tree" extends="chrome://global/content/bindings/tree.xml#tree">
+ <content>
+ <children includes="treecols"/>
+ <xul:treerows class="private-autocomplete-treerows tree-rows" xbl:inherits="hidescrollbar" flex="1">
+ <children/>
+ </xul:treerows>
+ </content>
+ </binding>
+
+ <binding id="private-autocomplete-richlistbox" extends="chrome://global/content/bindings/richlistbox.xml#richlistbox">
+ <implementation>
+ <field name="mLastMoveTime">Date.now()</field>
+ <field name="mouseSelectedIndex">-1</field>
+ </implementation>
+ <handlers>
+ <handler event="mouseup">
+ <![CDATA[
+ // don't call onPopupClick for the scrollbar buttons, thumb, slider, etc.
+ let item = event.originalTarget;
+ while (item && item.localName != "richlistitem") {
+ item = item.parentNode;
+ }
+
+ if (!item)
+ return;
+
+ this.parentNode.onPopupClick(event);
+ ]]>
+ </handler>
+
+ <handler event="mousemove">
+ <![CDATA[
+ if (Date.now() - this.mLastMoveTime > 30) {
+ let item = event.target;
+ while (item && item.localName != "richlistitem") {
+ item = item.parentNode;
+ }
+
+ if (!item)
+ return;
+
+ let index = this.getIndexOfItem(item);
+ if (index != this.selectedIndex) {
+ this.mouseSelectedIndex = this.selectedIndex = index;
+ }
+
+ this.mLastMoveTime = Date.now();
+ }
+ ]]>
+ </handler>
+ </handlers>
+ </binding>
+
+ <binding id="private-autocomplete-treebody">
+ <implementation>
+ <field name="mLastMoveTime">Date.now()</field>
+ </implementation>
+
+ <handlers>
+ <handler event="mouseup" action="this.parentNode.parentNode.onPopupClick(event);"/>
+
+ <handler event="mousedown"><![CDATA[
+ var rc = this.parentNode.treeBoxObject.getRowAt(event.clientX, event.clientY);
+ if (rc != this.parentNode.currentIndex)
+ this.parentNode.view.selection.select(rc);
+ ]]></handler>
+
+ <handler event="mousemove"><![CDATA[
+ if (Date.now() - this.mLastMoveTime > 30) {
+ var rc = this.parentNode.treeBoxObject.getRowAt(event.clientX, event.clientY);
+ if (rc != this.parentNode.currentIndex)
+ this.parentNode.view.selection.select(rc);
+ this.mLastMoveTime = Date.now();
+ }
+ ]]></handler>
+ </handlers>
+ </binding>
+
+ <binding id="private-autocomplete-treerows">
+ <content>
+ <xul:hbox flex="1" class="tree-bodybox">
+ <children/>
+ </xul:hbox>
+ <xul:scrollbar xbl:inherits="collapsed=hidescrollbar" orient="vertical" class="tree-scrollbar"/>
+ </content>
+ </binding>
+
+ <binding id="private-history-dropmarker" extends="chrome://global/content/bindings/general.xml#dropmarker">
+ <handlers>
+ <handler event="mousedown" button="0"><![CDATA[
+ document.getBindingParent(this).toggleHistoryPopup();
+ ]]></handler>
+ </handlers>
+ </binding>
+
+</bindings>
diff --git a/application/palemoon/base/content/autorecovery.js b/application/palemoon/base/content/autorecovery.js
index 29ccaed3f..01a092f5c 100644
--- a/application/palemoon/base/content/autorecovery.js
+++ b/application/palemoon/base/content/autorecovery.js
@@ -10,9 +10,9 @@
* have been properly initialized already.
*/
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cu = Components.utils;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
// Services = object with smart getters for common XPCOM services
Cu.import("resource://gre/modules/Services.jsm");
diff --git a/application/palemoon/base/content/baseMenuOverlay.xul b/application/palemoon/base/content/baseMenuOverlay.xul
index c6c1b16dc..f61348c9f 100644
--- a/application/palemoon/base/content/baseMenuOverlay.xul
+++ b/application/palemoon/base/content/baseMenuOverlay.xul
@@ -29,7 +29,7 @@
<menuitem id="menu_mac_show_all" label="&showAllAppsCmdMac.label;"/>
</menupopup>
<!-- Mac window menu -->
-#include ../../../toolkit/content/macWindowMenu.inc
+#include ../../../../toolkit/content/macWindowMenu.inc
#endif
#ifdef XP_WIN
diff --git a/application/palemoon/base/content/browser-addons.js b/application/palemoon/base/content/browser-addons.js
index 7993a0c9c..f5c398f33 100644
--- a/application/palemoon/base/content/browser-addons.js
+++ b/application/palemoon/base/content/browser-addons.js
@@ -226,7 +226,7 @@ const gXPInstallObserver = {
* - If an add-on was installed, incrementing the count, show the bar.
* - If an add-on was uninstalled, and no more items are left, hide the bar.
*/
-let AddonsMgrListener = {
+var AddonsMgrListener = {
get addonBar() document.getElementById("addon-bar"),
get statusBar() document.getElementById("status-bar"),
getAddonBarItemCount: function() {
@@ -461,7 +461,7 @@ var LightWeightThemeWebInstaller = {
/*
* Listen for Lightweight Theme styling changes and update the browser's theme accordingly.
*/
-let LightweightThemeListener = {
+var LightweightThemeListener = {
_modifiedStyles: [],
init: function () {
diff --git a/application/palemoon/base/content/browser-appmenu.inc b/application/palemoon/base/content/browser-appmenu.inc
index 835bf22bc..cfc855484 100644
--- a/application/palemoon/base/content/browser-appmenu.inc
+++ b/application/palemoon/base/content/browser-appmenu.inc
@@ -132,38 +132,8 @@
</splitmenu>
<menuseparator class="appmenu-menuseparator"/>
<splitmenu id="appmenu_webDeveloper"
- command="Tools:DevToolbox"
label="&appMenuWebDeveloper.label;">
<menupopup id="appmenu_webDeveloper_popup">
-#ifdef MOZ_DEVTOOLS
- <menuitem id="appmenu_devToolbox"
- observes="devtoolsMenuBroadcaster_DevToolbox"/>
- <menuseparator id="appmenu_devtools_separator"/>
- <menuitem id="appmenu_devToolbar"
- observes="devtoolsMenuBroadcaster_DevToolbar"/>
- <menuitem id="appmenu_chromeDebugger"
- observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
- <menuitem id="appmenu_browserConsole"
- observes="devtoolsMenuBroadcaster_BrowserConsole"/>
- <menuitem id="appmenu_responsiveUI"
- observes="devtoolsMenuBroadcaster_ResponsiveUI"/>
- <menuitem id="appmenu_eyedropper"
- observes="devtoolsMenuBroadcaster_Eyedropper"/>
- <menuitem id="appmenu_scratchpad"
- observes="devtoolsMenuBroadcaster_Scratchpad"/>
-#endif
- <menuitem id="appmenu_pageSource"
- observes="devtoolsMenuBroadcaster_PageSource"/>
- <menuitem id="appmenu_errorConsole"
- observes="devtoolsMenuBroadcaster_ErrorConsole"/>
-#ifdef MOZ_DEVTOOLS
- <menuitem id="appmenu_devtools_connect"
- observes="devtoolsMenuBroadcaster_connect"/>
-#endif
- <menuseparator id="appmenu_devToolsEndSeparator"/>
- <menuitem id="appmenu_getMoreDevtools"
- observes="devtoolsMenuBroadcaster_GetMoreTools"/>
- <menuseparator/>
#define ID_PREFIX appmenu_developer_
#define OMIT_ACCESSKEYS
#include browser-charsetmenu.inc
@@ -173,6 +143,11 @@
type="checkbox"
observes="workOfflineMenuitemState"
oncommand="BrowserOffline.toggleOfflineStatus();"/>
+ <menuseparator/>
+ <menuitem id="appmenu_pageSource"
+ observes="devtoolsMenuBroadcaster_PageSource"/>
+ <menuitem id="appmenu_javascriptConsole"
+ observes="devtoolsMenuBroadcaster_ErrorConsole"/>
</menupopup>
</splitmenu>
<menuseparator class="appmenu-menuseparator"/>
diff --git a/application/palemoon/base/content/browser-devtools-theme.js b/application/palemoon/base/content/browser-devtools-theme.js
new file mode 100644
index 000000000..7b21ddedc
--- /dev/null
+++ b/application/palemoon/base/content/browser-devtools-theme.js
@@ -0,0 +1,91 @@
+/* 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/. */
+
+/**
+ * Listeners for the DevTools theme.
+ */
+var DevToolsTheme = {
+ _devtoolsThemePrefName: "devtools.theme",
+ styleSheet: null,
+ initialized: false,
+
+ get isStyleSheetEnabled() {
+ return this.styleSheet && !this.styleSheet.sheet.disabled;
+ },
+
+ init: function () {
+ this.initialized = true;
+ Services.prefs.addObserver(this._devtoolsThemePrefName, this, false);
+ Services.obs.addObserver(this, "lightweight-theme-styling-update", false);
+ Services.obs.addObserver(this, "lightweight-theme-window-updated", false);
+ this._updateDevtoolsThemeAttribute();
+ },
+
+ observe: function (subject, topic, data) {
+ if (topic == "lightweight-theme-styling-update") {
+ let newTheme = JSON.parse(data);
+ this._toggleStyleSheet();
+ }
+
+ if (topic == "nsPref:changed" && data == this._devtoolsThemePrefName) {
+ this._updateDevtoolsThemeAttribute();
+ }
+ },
+
+ _inferBrightness: function() {
+ ToolbarIconColor.inferFromText();
+ // Get an inverted full screen button if the dark theme is applied.
+ if (this.isStyleSheetEnabled &&
+ document.documentElement.getAttribute("devtoolstheme") == "dark") {
+ document.documentElement.setAttribute("brighttitlebarforeground", "true");
+ } else {
+ document.documentElement.removeAttribute("brighttitlebarforeground");
+ }
+ },
+
+ _updateDevtoolsThemeAttribute: function() {
+ // Set an attribute on root element to make it possible
+ // to change colors based on the selected devtools theme.
+ let devtoolsTheme = Services.prefs.getCharPref(this._devtoolsThemePrefName);
+ if (devtoolsTheme != "dark") {
+ devtoolsTheme = "light";
+ }
+ document.documentElement.setAttribute("devtoolstheme", devtoolsTheme);
+ this._inferBrightness();
+ },
+
+ handleEvent: function(e) {
+ if (e.type === "load") {
+ this.styleSheet.removeEventListener("load", this);
+ this.refreshBrowserDisplay();
+ }
+ },
+
+ refreshBrowserDisplay: function() {
+ // Don't touch things on the browser if gBrowserInit.onLoad hasn't
+ // yet fired.
+ if (this.initialized) {
+ gBrowser.tabContainer._positionPinnedTabs();
+ this._inferBrightness();
+ }
+ },
+
+ _toggleStyleSheet: function() {
+ let wasEnabled = this.isStyleSheetEnabled;
+ if (wasEnabled) {
+ this.styleSheet.sheet.disabled = true;
+ this.refreshBrowserDisplay();
+ }
+ },
+
+ uninit: function () {
+ Services.prefs.removeObserver(this._devtoolsThemePrefName, this);
+ Services.obs.removeObserver(this, "lightweight-theme-styling-update", false);
+ Services.obs.removeObserver(this, "lightweight-theme-window-updated", false);
+ if (this.styleSheet) {
+ this.styleSheet.removeEventListener("load", this);
+ }
+ this.styleSheet = null;
+ }
+};
diff --git a/application/palemoon/base/content/browser-fullScreen.js b/application/palemoon/base/content/browser-fullScreen.js
index b8a29199e..73b10ae85 100644
--- a/application/palemoon/base/content/browser-fullScreen.js
+++ b/application/palemoon/base/content/browser-fullScreen.js
@@ -304,7 +304,7 @@ var FullScreen = {
},
_cancelAnimation: function() {
- window.mozCancelAnimationFrame(this._animationHandle);
+ window.cancelAnimationFrame(this._animationHandle);
this._animationHandle = 0;
clearTimeout(this._animationTimeout);
this._isAnimating = false;
@@ -354,11 +354,10 @@ var FullScreen = {
"fullscreen",
Services.perms.ALLOW_ACTION,
Services.perms.EXPIRE_SESSION);
- let host = uri.host;
var onFullscreenchange = function onFullscreenchange(event) {
if (event.target == document && document.mozFullScreenElement == null) {
// The chrome document has left fullscreen. Remove the temporary permission grant.
- Services.perms.remove(host, "fullscreen");
+ Services.perms.remove(uri, "fullscreen");
document.removeEventListener("mozfullscreenchange", onFullscreenchange);
}
}
diff --git a/application/palemoon/base/content/browser-fullZoom.js b/application/palemoon/base/content/browser-fullZoom.js
index 0837bf7c2..890cd8440 100644
--- a/application/palemoon/base/content/browser-fullZoom.js
+++ b/application/palemoon/base/content/browser-fullZoom.js
@@ -1,14 +1,6 @@
-/*
-#ifdef 0
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
-#endif
- */
-
-// One of the possible values for the mousewheel.* preferences.
-// From nsEventStateManager.cpp.
-const MOUSE_SCROLL_ZOOM = 3;
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Controls the "full zoom" setting and its site-specific preferences.
@@ -36,7 +28,6 @@ var FullZoom = {
return this._siteSpecificPref;
},
- //**************************************************************************//
// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener,
@@ -45,12 +36,10 @@ var FullZoom = {
Ci.nsISupportsWeakReference,
Ci.nsISupports]),
- //**************************************************************************//
// Initialization & Destruction
init: function FullZoom_init() {
- // Listen for scrollwheel events so we can save scrollwheel-based changes.
- window.addEventListener("DOMMouseScroll", this, false);
+ gBrowser.addEventListener("ZoomChangeUsingMouseWheel", this);
// Register ourselves with the service so we know when our pref changes.
this._cps2 = Cc["@mozilla.org/content-pref/service;1"].
@@ -74,76 +63,30 @@ var FullZoom = {
}
// This should be nulled after initialization.
- this._initialLocations.clear();
this._initialLocations = null;
},
destroy: function FullZoom_destroy() {
gPrefService.removeObserver("browser.zoom.", this);
this._cps2.removeObserverForName(this.name, this);
- window.removeEventListener("DOMMouseScroll", this, false);
+ gBrowser.removeEventListener("ZoomChangeUsingMouseWheel", this);
},
- //**************************************************************************//
// Event Handlers
// nsIDOMEventListener
handleEvent: function FullZoom_handleEvent(event) {
switch (event.type) {
- case "DOMMouseScroll":
- this._handleMouseScrolled(event);
+ case "ZoomChangeUsingMouseWheel":
+ let browser = this._getTargetedBrowser(event);
+ this._ignorePendingZoomAccesses(browser);
+ this._applyZoomToPref(browser);
break;
}
},
- _handleMouseScrolled: function FullZoom__handleMouseScrolled(event) {
- // Construct the "mousewheel action" pref key corresponding to this event.
- // Based on nsEventStateManager::WheelPrefs::GetBasePrefName().
- var pref = "mousewheel.";
-
- var pressedModifierCount = event.shiftKey + event.ctrlKey + event.altKey +
- event.metaKey + event.getModifierState("OS");
- if (pressedModifierCount != 1) {
- pref += "default.";
- } else if (event.shiftKey) {
- pref += "with_shift.";
- } else if (event.ctrlKey) {
- pref += "with_control.";
- } else if (event.altKey) {
- pref += "with_alt.";
- } else if (event.metaKey) {
- pref += "with_meta.";
- } else {
- pref += "with_win.";
- }
-
- pref += "action";
-
- // Don't do anything if this isn't a "zoom" scroll event.
- var isZoomEvent = false;
- try {
- isZoomEvent = (gPrefService.getIntPref(pref) == MOUSE_SCROLL_ZOOM);
- } catch (e) {}
- if (!isZoomEvent)
- return;
-
- // XXX Lazily cache all the possible action prefs so we don't have to get
- // them anew from the pref service for every scroll event? We'd have to
- // make sure to observe them so we can update the cache when they change.
-
- // We have to call _applyZoomToPref in a timeout because we handle the
- // event before the event state manager has a chance to apply the zoom
- // during nsEventStateManager::PostHandleEvent.
- let browser = gBrowser.selectedBrowser;
- let token = this._getBrowserToken(browser);
- window.setTimeout(function () {
- if (token.isCurrent)
- this._applyZoomToPref(browser);
- }.bind(this), 0);
- },
-
// nsIObserver
observe: function (aSubject, aTopic, aData) {
@@ -165,12 +108,12 @@ var FullZoom = {
// nsIContentPrefObserver
- onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue) {
- this._onContentPrefChanged(aGroup, aValue);
+ onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue, aIsPrivate) {
+ this._onContentPrefChanged(aGroup, aValue, aIsPrivate);
},
- onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) {
- this._onContentPrefChanged(aGroup, undefined);
+ onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName, aIsPrivate) {
+ this._onContentPrefChanged(aGroup, undefined, aIsPrivate);
},
/**
@@ -181,7 +124,7 @@ var FullZoom = {
* @param aValue The new value of the changed preference. Pass undefined to
* indicate the preference's removal.
*/
- _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue) {
+ _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue, aIsPrivate) {
if (this._isNextContentPrefChangeInternal) {
// Ignore changes that FullZoom itself makes. This works because the
// content pref service calls callbacks before notifying observers, and it
@@ -194,9 +137,10 @@ var FullZoom = {
if (!browser.currentURI)
return;
+ let ctxt = this._loadContextFromBrowser(browser);
let domain = this._cps2.extractDomain(browser.currentURI.spec);
if (aGroup) {
- if (aGroup == domain)
+ if (aGroup == domain && ctxt.usePrivateBrowsing == aIsPrivate)
this._applyPrefToZoom(aValue, browser);
return;
}
@@ -208,10 +152,9 @@ var FullZoom = {
// zoom should be set to the new global preference now that the global
// preference has changed.
let hasPref = false;
- let ctxt = this._loadContextFromBrowser(browser);
let token = this._getBrowserToken(browser);
this._cps2.getByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
- handleResult: function () hasPref = true,
+ handleResult: function () { hasPref = true; },
handleCompletion: function () {
if (!hasPref && token.isCurrent)
this._applyPrefToZoom(undefined, browser);
@@ -234,6 +177,7 @@ var FullZoom = {
*/
onLocationChange: function FullZoom_onLocationChange(aURI, aIsTabSwitch, aBrowser) {
let browser = aBrowser || gBrowser.selectedBrowser;
+
// If we haven't been initialized yet but receive an onLocationChange
// notification then let's store and replay it upon initialization.
if (this._initialLocations) {
@@ -247,14 +191,14 @@ var FullZoom = {
this._ignorePendingZoomAccesses(browser);
if (!aURI || (aIsTabSwitch && !this.siteSpecific)) {
- this._notifyOnLocationChange();
+ this._notifyOnLocationChange(browser);
return;
}
// Avoid the cps roundtrip and apply the default/global pref.
if (aURI.spec == "about:blank") {
this._applyPrefToZoom(undefined, browser,
- this._notifyOnLocationChange.bind(this));
+ this._notifyOnLocationChange.bind(this, browser));
return;
}
@@ -262,7 +206,7 @@ var FullZoom = {
if (!aIsTabSwitch && browser.isSyntheticDocument) {
ZoomManager.setZoomForBrowser(browser, 1);
// _ignorePendingZoomAccesses already called above, so no need here.
- this._notifyOnLocationChange();
+ this._notifyOnLocationChange(browser);
return;
}
@@ -271,7 +215,7 @@ var FullZoom = {
let pref = this._cps2.getCachedByDomainAndName(aURI.spec, this.name, ctxt);
if (pref) {
this._applyPrefToZoom(pref.value, browser,
- this._notifyOnLocationChange.bind(this));
+ this._notifyOnLocationChange.bind(this, browser));
return;
}
@@ -279,14 +223,14 @@ var FullZoom = {
let value = undefined;
let token = this._getBrowserToken(browser);
this._cps2.getByDomainAndName(aURI.spec, this.name, ctxt, {
- handleResult: function (resultPref) value = resultPref.value,
+ handleResult: function (resultPref) { value = resultPref.value; },
handleCompletion: function () {
if (!token.isCurrent) {
- this._notifyOnLocationChange();
+ this._notifyOnLocationChange(browser);
return;
}
this._applyPrefToZoom(value, browser,
- this._notifyOnLocationChange.bind(this));
+ this._notifyOnLocationChange.bind(this, browser));
}.bind(this)
});
},
@@ -299,7 +243,6 @@ var FullZoom = {
menuItem.setAttribute("checked", !ZoomManager.useFullZoom);
},
- //**************************************************************************//
// Setting & Pref Manipulation
/**
@@ -323,19 +266,32 @@ var FullZoom = {
},
/**
- * Sets the zoom level of the page in the current browser to the global zoom
+ * Sets the zoom level for the given browser to the given floating
+ * point value, where 1 is the default zoom level.
+ */
+ setZoom: function (value, browser = gBrowser.selectedBrowser) {
+ ZoomManager.setZoomForBrowser(browser, value);
+ this._ignorePendingZoomAccesses(browser);
+ this._applyZoomToPref(browser);
+ },
+
+ /**
+ * Sets the zoom level of the page in the given browser to the global zoom
* level.
+ *
+ * @return A promise which resolves when the zoom reset has been applied.
*/
- reset: function FullZoom_reset() {
- let browser = gBrowser.selectedBrowser;
+ reset: function FullZoom_reset(browser = gBrowser.selectedBrowser) {
let token = this._getBrowserToken(browser);
- this._getGlobalValue(browser, function (value) {
+ let result = this._getGlobalValue(browser).then(value => {
if (token.isCurrent) {
ZoomManager.setZoomForBrowser(browser, value === undefined ? 1 : value);
this._ignorePendingZoomAccesses(browser);
+ Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset", "");
}
});
this._removePref(browser);
+ return result;
},
/**
@@ -383,7 +339,7 @@ var FullZoom = {
}
let token = this._getBrowserToken(aBrowser);
- this._getGlobalValue(aBrowser, function (value) {
+ this._getGlobalValue(aBrowser).then(value => {
if (token.isCurrent) {
ZoomManager.setZoomForBrowser(aBrowser, value === undefined ? 1 : value);
this._ignorePendingZoomAccesses(aBrowser);
@@ -399,6 +355,7 @@ var FullZoom = {
* @param browser The zoom of this browser will be saved. Required.
*/
_applyZoomToPref: function FullZoom__applyZoomToPref(browser) {
+ Services.obs.notifyObservers(browser, "browser-fullZoom:zoomChange", "");
if (!this.siteSpecific ||
gInPrintPreviewMode ||
browser.isSyntheticDocument)
@@ -419,6 +376,7 @@ var FullZoom = {
* @param browser The zoom of this browser will be removed. Required.
*/
_removePref: function FullZoom__removePref(browser) {
+ Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset", "");
if (browser.isSyntheticDocument)
return;
let ctxt = this._loadContextFromBrowser(browser);
@@ -429,7 +387,6 @@ var FullZoom = {
});
},
- //**************************************************************************//
// Utilities
/**
@@ -462,6 +419,30 @@ var FullZoom = {
},
/**
+ * Returns the browser that the supplied zoom event is associated with.
+ * @param event The ZoomChangeUsingMouseWheel event.
+ * @return The associated browser element, if one exists, otherwise null.
+ */
+ _getTargetedBrowser: function FullZoom__getTargetedBrowser(event) {
+ let target = event.originalTarget;
+
+ // With remote content browsers, the event's target is the browser
+ // we're looking for.
+ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ if (target instanceof window.XULElement &&
+ target.localName == "browser" &&
+ target.namespaceURI == XUL_NS)
+ return target;
+
+ // With in-process content browsers, the event's target is the content
+ // document.
+ if (target.nodeType == Node.DOCUMENT_NODE)
+ return gBrowser.getBrowserForDocument(target);
+
+ throw new Error("Unexpected ZoomChangeUsingMouseWheel event source");
+ },
+
+ /**
* Increments the zoom change token for the given browser so that pending
* async operations know that it may be unsafe to access they zoom when they
* finish.
@@ -491,54 +472,49 @@ var FullZoom = {
/**
* Gets the global browser.content.full-zoom content preference.
*
- * WARNING: callback may be called synchronously or asynchronously. The
- * reason is that it's usually desirable to avoid turns of the event loop
- * where possible, since they can lead to visible, jarring jumps in zoom
- * level. It's not always possible to avoid them, though. As a convenience,
- * then, this method takes a callback and returns nothing.
- *
- * @param browser The content browser pertaining to the zoom.
- * @param callback Synchronously or asynchronously called when done. It's
- * bound to this object (FullZoom) and called as:
- * callback(prefValue)
+ * @param browser The browser pertaining to the zoom.
+ * @returns Promise<prefValue>
+ * Resolves to the preference value when done.
*/
- _getGlobalValue: function FullZoom__getGlobalValue(browser, callback) {
+ _getGlobalValue: function FullZoom__getGlobalValue(browser) {
// * !("_globalValue" in this) => global value not yet cached.
// * this._globalValue === undefined => global value known not to exist.
// * Otherwise, this._globalValue is a number, the global value.
- if ("_globalValue" in this) {
- callback.call(this, this._globalValue, true);
- return;
- }
- let value = undefined;
- this._cps2.getGlobal(this.name, this._loadContextFromBrowser(browser), {
- handleResult: function (pref) value = pref.value,
- handleCompletion: function (reason) {
- this._globalValue = this._ensureValid(value);
- callback.call(this, this._globalValue);
- }.bind(this)
+ return new Promise(resolve => {
+ if ("_globalValue" in this) {
+ resolve(this._globalValue);
+ return;
+ }
+ let value = undefined;
+ this._cps2.getGlobal(this.name, this._loadContextFromBrowser(browser), {
+ handleResult: function (pref) { value = pref.value; },
+ handleCompletion: (reason) => {
+ this._globalValue = this._ensureValid(value);
+ resolve(this._globalValue);
+ }
+ });
});
},
/**
- * Gets the load context from the given content browser.
+ * Gets the load context from the given Browser.
*
* @param Browser The Browser whose load context will be returned.
- * @return The nsILoadContext of the given Browser.
+ * @return The nsILoadContext of the given Browser.
*/
_loadContextFromBrowser: function FullZoom__loadContextFromBrowser(browser) {
return browser.loadContext;
},
/**
- * Asynchronously broadcasts a "browser-fullZoom:locationChange" notification
- * so that tests can select tabs, load pages, etc. and be notified when the
- * zoom levels on those pages change. The notification is always asynchronous
- * so that observers are guaranteed a consistent behavior.
+ * Asynchronously broadcasts "browser-fullZoom:location-change" so that
+ * listeners can be notified when the zoom levels on those pages change.
+ * The notification is always asynchronous so that observers are guaranteed a
+ * consistent behavior.
*/
- _notifyOnLocationChange: function FullZoom__notifyOnLocationChange() {
+ _notifyOnLocationChange: function FullZoom__notifyOnLocationChange(browser) {
this._executeSoon(function () {
- Services.obs.notifyObservers(null, "browser-fullZoom:locationChange", "");
+ Services.obs.notifyObservers(browser, "browser-fullZoom:location-change", "");
});
},
diff --git a/application/palemoon/base/content/browser-gestureSupport.js b/application/palemoon/base/content/browser-gestureSupport.js
index d88f47c79..13eb71b99 100644
--- a/application/palemoon/base/content/browser-gestureSupport.js
+++ b/application/palemoon/base/content/browser-gestureSupport.js
@@ -13,7 +13,7 @@
// chrome-only, we must listen for the simple gesture events during
// the capturing phase and call stopPropagation on every event.
-let gGestureSupport = {
+var gGestureSupport = {
_currentRotation: 0,
_lastRotateDelta: 0,
_rotateMomentumThreshold: .75,
@@ -532,7 +532,7 @@ let gGestureSupport = {
};
// History Swipe Animation Support (bug 678392)
-let gHistorySwipeAnimation = {
+var gHistorySwipeAnimation = {
active: false,
isLTR: false,
diff --git a/application/palemoon/base/content/browser-menubar.inc b/application/palemoon/base/content/browser-menubar.inc
index fa9d7f0f4..fc6bc7694 100644
--- a/application/palemoon/base/content/browser-menubar.inc
+++ b/application/palemoon/base/content/browser-menubar.inc
@@ -534,43 +534,12 @@
label="&webDeveloperMenu.label;"
accesskey="&webDeveloperMenu.accesskey;">
<menupopup id="menuWebDeveloperPopup">
-#ifdef MOZ_DEVTOOLS
- <menuitem id="menu_devToolbox"
- observes="devtoolsMenuBroadcaster_DevToolbox"
- accesskey="&devToolboxMenuItem.accesskey;"/>
- <menuseparator id="menu_devtools_separator"/>
- <menuitem id="menu_devToolbar"
- observes="devtoolsMenuBroadcaster_DevToolbar"
- accesskey="&devToolbarMenu.accesskey;"/>
- <menuitem id="menu_chromeDebugger"
- observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
- <menuitem id="menu_browserConsole"
- observes="devtoolsMenuBroadcaster_BrowserConsole"
- accesskey="&browserConsoleCmd.accesskey;"/>
- <menuitem id="menu_responsiveUI"
- observes="devtoolsMenuBroadcaster_ResponsiveUI"
- accesskey="&responsiveDesignTool.accesskey;"/>
- <menuitem id="menu_eyedropper"
- observes="devtoolsMenuBroadcaster_Eyedropper"
- accesskey="&eyedropper.accesskey;"/>
- <menuitem id="menu_scratchpad"
- observes="devtoolsMenuBroadcaster_Scratchpad"
- accesskey="&scratchpad.accesskey;"/>
-#endif
<menuitem id="menu_pageSource"
observes="devtoolsMenuBroadcaster_PageSource"
accesskey="&pageSourceCmd.accesskey;"/>
<menuitem id="javascriptConsole"
observes="devtoolsMenuBroadcaster_ErrorConsole"
accesskey="&errorConsoleCmd.accesskey;"/>
-#ifdef MOZ_DEVTOOLS
- <menuitem id="menu_devtools_connect"
- observes="devtoolsMenuBroadcaster_connect"/>
-#endif
- <menuseparator id="devToolsEndSeparator"/>
- <menuitem id="getMoreDevtools"
- observes="devtoolsMenuBroadcaster_GetMoreTools"
- accesskey="&getMoreDevtoolsCmd.accesskey;"/>
</menupopup>
</menu>
<menuitem id="menu_pageInfo"
diff --git a/application/palemoon/base/content/browser-places.js b/application/palemoon/base/content/browser-places.js
index cf9c28597..590fe7ecd 100644
--- a/application/palemoon/base/content/browser-places.js
+++ b/application/palemoon/base/content/browser-places.js
@@ -189,11 +189,24 @@ var StarUI = {
this._itemId = aItemId !== undefined ? aItemId : this._itemId;
this.beginBatch();
- this.panel.openPopup(aAnchorElement, aPosition);
-
+ let onPanelReady = fn => {
+ let target = this.panel;
+ if (target.parentNode) {
+ // By targeting the panel's parent and using a capturing listener, we
+ // can have our listener called before others waiting for the panel to
+ // be shown (which probably expect the panel to be fully initialized)
+ target = target.parentNode;
+ }
+ target.addEventListener("popupshown", function(event) {
+ fn();
+ }, {"capture": true, "once": true});
+ };
gEditItemOverlay.initPanel(this._itemId,
- { hiddenRows: ["description", "location",
+ { onPanelReady,
+ hiddenRows: ["description", "location",
"loadInSidebar", "keyword"] });
+
+ this.panel.openPopup(aAnchorElement, aPosition);
},
panelShown:
@@ -959,7 +972,7 @@ var PlacesMenuDNDHandler = {
* This object handles the initialization and uninitialization of the bookmarks
* toolbar.
*/
-let PlacesToolbarHelper = {
+var PlacesToolbarHelper = {
_place: "place:folder=TOOLBAR",
get _viewElt() {
@@ -1006,7 +1019,7 @@ let PlacesToolbarHelper = {
* menu button.
*/
-let BookmarkingUI = {
+var BookmarkingUI = {
get button() {
if (!this._button) {
this._button = document.getElementById("bookmarks-menu-button");
diff --git a/application/palemoon/base/content/browser-plugins.js b/application/palemoon/base/content/browser-plugins.js
index 769ac6d8a..838268203 100644
--- a/application/palemoon/base/content/browser-plugins.js
+++ b/application/palemoon/base/content/browser-plugins.js
@@ -470,28 +470,12 @@ var gPluginHandler = {
}
},
- // Match the behaviour of nsPermissionManager
- _getHostFromPrincipal: function PH_getHostFromPrincipal(principal) {
- if (!principal.URI || principal.URI.schemeIs("moz-nullprincipal")) {
- return "(null)";
- }
-
- try {
- if (principal.URI.host)
- return principal.URI.host;
- } catch (e) {}
-
- return principal.origin;
- },
-
_makeCenterActions: function PH_makeCenterActions(notification) {
let contentWindow = notification.browser.contentWindow;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let principal = contentWindow.document.nodePrincipal;
- // This matches the behavior of nsPermssionManager, used for display purposes only
- let principalHost = this._getHostFromPrincipal(principal);
let centerActions = [];
let pluginsFound = new Set();
@@ -517,11 +501,11 @@ var gPluginHandler = {
let permissionObj = Services.perms.
getPermissionObject(principal, pluginInfo.permissionString, false);
if (permissionObj) {
- pluginInfo.pluginPermissionHost = permissionObj.host;
+ pluginInfo.pluginPermissionPrePath = permissionObj.principal.originNoSuffix;
pluginInfo.pluginPermissionType = permissionObj.expireType;
}
else {
- pluginInfo.pluginPermissionHost = principalHost;
+ pluginInfo.pluginPermissionPrePath = principal.originNoSuffix;
pluginInfo.pluginPermissionType = undefined;
}
diff --git a/application/palemoon/base/content/browser-sets.inc b/application/palemoon/base/content/browser-sets.inc
index 78cfb7faa..64228678e 100644
--- a/application/palemoon/base/content/browser-sets.inc
+++ b/application/palemoon/base/content/browser-sets.inc
@@ -92,24 +92,9 @@
<command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
-#ifdef MOZ_DEVTOOLS
- <command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/>
- <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
- <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/>
- <command id="Tools:DevAppMgr" oncommand="gDevToolsBrowser.openAppManager(gBrowser);" disabled="true" hidden="true"/>
- <command id="Tools:WebIDE" oncommand="gDevToolsBrowser.openWebIDE();" disabled="true" hidden="true"/>
- <command id="Tools:ChromeDebugger" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/>
- <command id="Tools:BrowserConsole" oncommand="HUDService.openBrowserConsoleOrFocus();"/>
- <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
- <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
- <command id="Tools:Eyedropper" oncommand="openEyedropper();"/>
-#endif
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
<command id="Tools:Permissions" oncommand="BrowserOpenPermissionsMgr();"/>
<command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
-#ifdef MOZ_DEVTOOLS
- <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
-#endif
<command id="Tools:Sanitize"
oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
<command id="Tools:PrivateBrowsing"
@@ -170,46 +155,6 @@
#endif
<broadcaster id="workOfflineMenuitemState"/>
-#ifdef MOZ_DEVTOOLS
- <!-- DevTools broadcasters -->
- <broadcaster id="devtoolsMenuBroadcaster_DevToolbox"
- label="&devToolboxMenuItem.label;"
- type="checkbox" autocheck="false"
- command="Tools:DevToolbox"
- key="key_devToolbox"/>
- <broadcaster id="devtoolsMenuBroadcaster_DevToolbar"
- label="&devToolbarMenu.label;"
- type="checkbox" autocheck="false"
- command="Tools:DevToolbar"
- key="key_devToolbar"/>
- <broadcaster id="devtoolsMenuBroadcaster_DevAppMgr"
- label="&devAppMgrMenu.label;"
- command="Tools:DevAppMgr"/>
- <broadcaster id="devtoolsMenuBroadcaster_webide"
- label="&webide.label;"
- command="Tools:WebIDE"
- key="key_webide"/>
- <broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger"
- label="&chromeDebuggerMenu.label;"
- command="Tools:ChromeDebugger"/>
- <broadcaster id="devtoolsMenuBroadcaster_BrowserConsole"
- label="&browserConsoleCmd.label;"
- key="key_browserConsole"
- command="Tools:BrowserConsole"/>
- <broadcaster id="devtoolsMenuBroadcaster_Scratchpad"
- label="&scratchpad.label;"
- command="Tools:Scratchpad"
- key="key_scratchpad"/>
- <broadcaster id="devtoolsMenuBroadcaster_ResponsiveUI"
- label="&responsiveDesignTool.label;"
- type="checkbox" autocheck="false"
- command="Tools:ResponsiveUI"
- key="key_responsiveUI"/>
- <broadcaster id="devtoolsMenuBroadcaster_Eyedropper"
- label="&eyedropper.label;"
- type="checkbox" autocheck="false"
- command="Tools:Eyedropper"/>
-#endif
<broadcaster id="devtoolsMenuBroadcaster_PageSource"
label="&pageSourceCmd.label;"
key="key_viewSource"
@@ -217,14 +162,6 @@
<broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
label="&errorConsoleCmd.label;"
command="Tools:ErrorConsole"/>
- <broadcaster id="devtoolsMenuBroadcaster_GetMoreTools"
- label="&getMoreDevtoolsCmd.label;"
- oncommand="openUILinkIn(gPrefService.getCharPref('browser.getdevtools.url'), 'tab');"/>
-#ifdef MOZ_DEVTOOLS
- <broadcaster id="devtoolsMenuBroadcaster_connect"
- label="&devtoolsConnect.label;"
- command="Tools:DevToolsConnect"/>
-#endif
</broadcasterset>
<keyset id="mainKeyset">
@@ -271,21 +208,6 @@
<key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
#endif
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
-#ifdef MOZ_DEVTOOLS
- <key id="key_browserConsole" key="&browserConsoleCmd.commandkey;" command="Tools:BrowserConsole" modifiers="accel,shift"/>
- <key id="key_devToolbox" keycode="VK_F12" keytext="F12" command="Tools:DevToolbox"/>
- <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
- keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
- <key id="key_responsiveUI" key="&responsiveDesignTool.commandkey;" command="Tools:ResponsiveUI"
-#ifdef XP_MACOSX
- modifiers="accel,alt"
-#else
- modifiers="accel,shift"
-#endif
- />
- <key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift"
- keytext="&scratchpad.keytext;" command="Tools:Scratchpad"/>
-#endif
<key id="openFileKb" key="&openFileCmd.commandkey;" command="Browser:OpenFile" modifiers="accel"/>
<key id="key_savePage" key="&savePageCmd.commandkey;" command="Browser:SavePage" modifiers="accel"/>
<key id="printKb" key="&printCmd.commandkey;" command="cmd_print" modifiers="accel"/>
diff --git a/application/palemoon/base/content/browser-syncui.js b/application/palemoon/base/content/browser-syncui.js
index fc8c7f016..67056e221 100644
--- a/application/palemoon/base/content/browser-syncui.js
+++ b/application/palemoon/base/content/browser-syncui.js
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
// gSyncUI handles updating the tools menu
-let gSyncUI = {
+var gSyncUI = {
_obs: ["weave:service:sync:start",
"weave:service:sync:delayed",
"weave:service:quota:remaining",
diff --git a/application/palemoon/base/content/browser-thumbnails.js b/application/palemoon/base/content/browser-thumbnails.js
index dbe33e3ed..079b0ac1b 100644
--- a/application/palemoon/base/content/browser-thumbnails.js
+++ b/application/palemoon/base/content/browser-thumbnails.js
@@ -7,7 +7,7 @@
/**
* Keeps thumbnails of open web pages up-to-date.
*/
-let gBrowserThumbnails = {
+var gBrowserThumbnails = {
/**
* Pref that controls whether we can store SSL content on disk
*/
@@ -92,7 +92,12 @@ let gBrowserThumbnails = {
filterForThumbnailExpiration:
function Thumbnails_filterForThumbnailExpiration(aCallback) {
- aCallback([browser.currentURI.spec for (browser of gBrowser.browsers)]);
+ // Tycho: aCallback([browser.currentURI.spec for (browser of gBrowser.browsers)]);
+ let result = [];
+ for (let browser of gBrowser.browsers) {
+ result.push(browser.currentURI.spec);
+ }
+ aCallback(result);
},
/**
@@ -137,7 +142,7 @@ let gBrowserThumbnails = {
// FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as
// that currently regresses Talos SVG tests.
- if (doc instanceof SVGDocument || doc instanceof XMLDocument)
+ if (doc instanceof XMLDocument)
return false;
// There's no point in taking screenshot of loading pages.
diff --git a/application/palemoon/base/content/browser-uacompat.js b/application/palemoon/base/content/browser-uacompat.js
new file mode 100644
index 000000000..933aa55d1
--- /dev/null
+++ b/application/palemoon/base/content/browser-uacompat.js
@@ -0,0 +1,45 @@
+/* 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/. */
+
+var UserAgentCompatibility = {
+ PREF_UA_COMPAT: "general.useragent.compatMode",
+ PREF_UA_COMPAT_GECKO: "general.useragent.compatMode.gecko",
+ PREF_UA_COMPAT_FIREFOX: "general.useragent.compatMode.firefox",
+
+ init: function() {
+ this.checkPreferences();
+ Services.prefs.addObserver(this.PREF_UA_COMPAT, this, false);
+ Services.prefs.addObserver(this.PREF_UA_COMPAT_GECKO, this, false);
+ Services.prefs.addObserver(this.PREF_UA_COMPAT_FIREFOX, this, false);
+ },
+
+ uninit: function() {
+ Services.prefs.removeObserver(this.PREF_UA_COMPAT, this, false);
+ Services.prefs.removeObserver(this.PREF_UA_COMPAT_GECKO, this, false);
+ Services.prefs.removeObserver(this.PREF_UA_COMPAT_FIREFOX, this, false);
+ },
+
+ observe: function() {
+ this.checkPreferences();
+ },
+
+ checkPreferences: function() {
+ var compatMode = Services.prefs.getIntPref(this.PREF_UA_COMPAT);
+
+ switch(compatMode) {
+ case 0:
+ Services.prefs.setBoolPref(this.PREF_UA_COMPAT_GECKO, false);
+ Services.prefs.setBoolPref(this.PREF_UA_COMPAT_FIREFOX, false);
+ break;
+ case 1:
+ Services.prefs.setBoolPref(this.PREF_UA_COMPAT_GECKO, true);
+ Services.prefs.setBoolPref(this.PREF_UA_COMPAT_FIREFOX, false);
+ break;
+ case 2:
+ Services.prefs.setBoolPref(this.PREF_UA_COMPAT_GECKO, true);
+ Services.prefs.setBoolPref(this.PREF_UA_COMPAT_FIREFOX, true);
+ break;
+ }
+ }
+};
diff --git a/application/palemoon/base/content/browser-webrtcUI.js b/application/palemoon/base/content/browser-webrtcUI.js
index a6c9008ca..d59134ce5 100644
--- a/application/palemoon/base/content/browser-webrtcUI.js
+++ b/application/palemoon/base/content/browser-webrtcUI.js
@@ -3,7 +3,7 @@
# 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/.
-let WebrtcIndicator = {
+var WebrtcIndicator = {
init: function () {
let temp = {};
Cu.import("resource:///modules/webrtcUI.jsm", temp);
diff --git a/application/palemoon/base/content/browser.css b/application/palemoon/base/content/browser.css
index 2c8ba3e69..658655970 100644
--- a/application/palemoon/base/content/browser.css
+++ b/application/palemoon/base/content/browser.css
@@ -115,8 +115,17 @@ toolbar[printpreview="true"] {
#titlebar {
-moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
+ -moz-window-dragging: drag;
}
+%ifdef XP_WIN
+#main-window[tabsontop="true"] #TabsToolbar,
+#main-window[tabsontop="true"] #toolbar-menubar,
+#main-window[tabsontop="true"] #navigator-toolbox > toolbar:-moz-lwtheme {
+ -moz-window-dragging: drag;
+}
+%endif
+
#titlebar-spacer {
pointer-events: none;
}
@@ -271,6 +280,10 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#urlbar-rich-result-popup");
}
+#DateTimePickerPanel[active="true"] {
+ -moz-binding: url("chrome://global/content/bindings/datetimepopup.xml#datetime-popup");
+}
+
/* Pale Moon: Address bar: Feeds */
#ub-feed-button > .button-box > .box-inherit > .button-text,
#ub-feed-button > .button-box > .button-menu-dropmarker {
@@ -315,6 +328,66 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a
visibility: hidden;
}
+/* Private Autocomplete */
+textbox[type="private-autocomplete"] {
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#autocomplete");
+}
+
+panel[type="private-autocomplete"] {
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#autocomplete-result-popup");
+}
+
+panel[type="private-autocomplete-richlistbox"] {
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#private-autocomplete-rich-result-popup");
+}
+
+.private-autocomplete-tree {
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#private-autocomplete-tree");
+ -moz-user-focus: ignore;
+}
+
+.private-autocomplete-treebody {
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#private-autocomplete-treebody");
+}
+
+.private-autocomplete-richlistbox {
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#private-autocomplete-richlistbox");
+ -moz-user-focus: ignore;
+}
+
+.private-autocomplete-richlistbox > scrollbox {
+ overflow-x: hidden !important;
+}
+
+.private-autocomplete-richlistitem {
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#private-autocomplete-richlistitem");
+ -moz-box-orient: vertical;
+ overflow: -moz-hidden-unscrollable;
+}
+
+.private-autocomplete-treerows {
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#private-autocomplete-treerows");
+}
+
+.private-autocomplete-history-dropmarker {
+ display: none;
+}
+
+.private-autocomplete-history-dropmarker[enablehistory="true"] {
+ display: -moz-box;
+ -moz-binding: url("chrome://browser/content/autocomplete.xml#private-history-dropmarker");
+}
+
+.ac-ellipsis-after {
+ visibility: hidden;
+}
+
+.ac-url-text[type~="action"],
+.ac-action-text:not([type~="action"]) {
+ visibility: collapse;
+}
+
+
/* ::::: Unified Back-/Forward Button ::::: */
#back-button > .toolbarbutton-menu-dropmarker,
#forward-button > .toolbarbutton-menu-dropmarker {
@@ -533,11 +606,11 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(#nav-bar):not(
max-width: 280px;
}
-.form-validation-anchor {
+.popup-anchor {
/* should occupy space but not be visible */
opacity: 0;
- visibility: hidden;
pointer-events: none;
+ -moz-stack-sizing: ignore;
}
#addon-progress-notification {
@@ -618,10 +691,6 @@ statuspanel[inactive][previoustype=overLink] {
-moz-box-align: end;
}
-.panel-inner-arrowcontentfooter[footertype="promobox"] {
- -moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
-}
-
/* highlighter */
%include highlighter.css
@@ -681,7 +750,7 @@ toolbarbutton[type="badged"] {
}
/* Strict icon size for PMkit 'ui/button' */
-toolbarbutton[pmkit-button="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
+toolbarbutton[pmkit-button="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
diff --git a/application/palemoon/base/content/browser.js b/application/palemoon/base/content/browser.js
index 34b91b6cb..9f4d66c07 100644
--- a/application/palemoon/base/content/browser.js
+++ b/application/palemoon/base/content/browser.js
@@ -3,12 +3,16 @@
# 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/.
-let Ci = Components.interfaces;
-let Cu = Components.utils;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/RecentWindow.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+ "resource://gre/modules/Task.jsm");
+
XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
"resource:///modules/CharsetMenu.jsm");
@@ -65,6 +69,9 @@ XPCOMUtils.defineLazyGetter(window, "gFindBar", function() {
return findbar;
});
+XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
+ "resource://gre/modules/BrowserUtils.jsm");
+
XPCOMUtils.defineLazyGetter(this, "gPrefService", function() {
return Services.prefs;
});
@@ -79,14 +86,8 @@ this.__defineSetter__("AddonManager", function (val) {
return this.AddonManager = val;
});
-this.__defineGetter__("PluralForm", function() {
- Cu.import("resource://gre/modules/PluralForm.jsm");
- return this.PluralForm;
-});
-this.__defineSetter__("PluralForm", function (val) {
- delete this.PluralForm;
- return this.PluralForm = val;
-});
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+ "resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils",
"resource:///modules/AboutHomeUtils.jsm");
@@ -109,20 +110,6 @@ XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
}
});
-#ifdef MOZ_DEVTOOLS
-XPCOMUtils.defineLazyGetter(this, "DeveloperToolbar", function() {
- let tmp = {};
- Cu.import("resource://gre/modules/devtools/DeveloperToolbar.jsm", tmp);
- return new tmp.DeveloperToolbar(window, document.getElementById("developer-toolbar"));
-});
-
-XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function() {
- let tmp = {};
- Cu.import("resource://gre/modules/devtools/ToolboxProcess.jsm", tmp);
- return tmp.BrowserToolboxProcess;
-});
-#endif
-
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
@@ -135,7 +122,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
XPCOMUtils.defineLazyModuleGetter(this, "FormValidationHandler",
"resource:///modules/FormValidationHandler.jsm");
-let gInitialPages = [
+var gInitialPages = [
"about:blank",
"about:newtab",
"about:home",
@@ -152,7 +139,12 @@ let gInitialPages = [
#include browser-plugins.js
#include browser-tabPreviews.js
#include browser-thumbnails.js
+#include browser-uacompat.js
+
+#ifdef MOZ_WEBRTC
#include browser-webrtcUI.js
+#endif
+
#include browser-gestureSupport.js
#ifdef MOZ_SERVICES_SYNC
@@ -336,6 +328,48 @@ const gSessionHistoryObserver = {
}
};
+var gURLBarSettings = {
+ prefSuggest: "browser.urlbar.suggest.",
+ /*
+ For searching in the source code:
+ browser.urlbar.suggest.bookmark
+ browser.urlbar.suggest.history
+ browser.urlbar.suggest.openpage
+ */
+ prefSuggests: [
+ "bookmark",
+ "history",
+ "openpage"
+ ],
+ prefKeyword: "keyword.enabled",
+
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic != "nsPref:changed")
+ return;
+
+ this.writePlaceholder();
+ },
+
+ writePlaceholder: function() {
+ let attribute = "placeholder";
+ let prefs = this.prefSuggests.map(pref => {
+ return this.prefSuggest + pref;
+ });
+ prefs.push(this.prefKeyword);
+ let placeholderDefault = prefs.some(pref => {
+ return gPrefService.getBoolPref(pref);
+ });
+
+ if (placeholderDefault) {
+ gURLBar.setAttribute(
+ attribute, gNavigatorBundle.getString("urlbar.placeholder"));
+ } else {
+ gURLBar.setAttribute(
+ attribute, gNavigatorBundle.getString("urlbar.placeholderURLOnly"));
+ }
+ }
+};
+
/**
* Given a starting docshell and a URI to look up, find the docshell the URI
* is loaded in.
@@ -663,6 +697,8 @@ const gXSSObserver = {
};
var gBrowserInit = {
+ delayedStartupFinished: false,
+
onLoad: function() {
gMultiProcessBrowser = gPrefService.getBoolPref("browser.tabs.remote");
@@ -685,6 +721,14 @@ var gBrowserInit = {
window.addEventListener("AppCommand", HandleAppCommandEvent, true);
+ // These routines add message listeners. They must run before
+ // loading the frame script to ensure that we don't miss any
+ // message sent between when the frame script is loaded and when
+ // the listener is registered.
+#ifdef MOZ_DEVTOOLS
+ DevToolsTheme.init();
+#endif
+
messageManager.loadFrameScript("chrome://browser/content/content.js", true);
messageManager.loadFrameScript("chrome://browser/content/content-sessionStore.js", true);
@@ -872,6 +916,7 @@ var gBrowserInit = {
TabsInTitlebar.init();
retrieveToolbarIconsizesFromTheme();
ToolbarIconColor.init();
+ UserAgentCompatibility.init();
#ifdef XP_WIN
if (window.matchMedia("(-moz-os-version: windows-win8)").matches &&
@@ -945,12 +990,23 @@ var gBrowserInit = {
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);
}
- // window.arguments[2]: referrer (nsIURI)
+ // window.arguments[2]: referrer (nsIURI | string)
// [3]: postData (nsIInputStream)
// [4]: allowThirdPartyFixup (bool)
+ // [5]: referrerPolicy (int)
else if (window.arguments.length >= 3) {
- loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
- window.arguments[4] || false);
+ let referrerURI = window.arguments[2];
+ if (typeof(referrerURI) == "string") {
+ try {
+ referrerURI = makeURI(referrerURI);
+ } catch (e) {
+ referrerURI = null;
+ }
+ }
+ let referrerPolicy = (window.arguments[5] != undefined ?
+ window.arguments[5] : Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT);
+ loadURI(uriToLoad, referrerURI, window.arguments[3] || null,
+ window.arguments[4] || false, referrerPolicy);
window.focus();
}
// Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
@@ -968,11 +1024,18 @@ var gBrowserInit = {
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
Services.obs.addObserver(gXSSObserver, "xss-on-violate-policy", false);
+ gPrefService.addObserver(gURLBarSettings.prefSuggest, gURLBarSettings, false);
+ gPrefService.addObserver(gURLBarSettings.prefKeyword, gURLBarSettings, false);
+
+ gURLBarSettings.writePlaceholder();
+
BrowserOffline.init();
OfflineApps.init();
IndexedDBPromptHelper.init();
AddonManager.addAddonListener(AddonsMgrListener);
+#ifdef MOZ_WEBRTC
WebrtcIndicator.init();
+#endif
// Ensure login manager is up and running.
Services.logins;
@@ -1114,27 +1177,6 @@ var gBrowserInit = {
setUrlAndSearchBarWidthForConditionalForwardButton();
});
-#ifdef MOZ_DEVTOOLS
- // Enable Chrome Debugger?
- let chromeEnabled = gPrefService.getBoolPref("devtools.chrome.enabled");
- let remoteEnabled = chromeEnabled &&
- gPrefService.getBoolPref("devtools.debugger.chrome-enabled") &&
- gPrefService.getBoolPref("devtools.debugger.remote-enabled");
- if (remoteEnabled) {
- let cmd = document.getElementById("Tools:ChromeDebugger");
- cmd.removeAttribute("disabled");
- cmd.removeAttribute("hidden");
- }
-
- // Enable Scratchpad in the UI, if the preference allows this.
- let scratchpadEnabled = gPrefService.getBoolPref(Scratchpad.prefEnabledName);
- if (scratchpadEnabled) {
- let cmd = document.getElementById("Tools:Scratchpad");
- cmd.removeAttribute("disabled");
- cmd.removeAttribute("hidden");
- }
-#endif
-
// Enable Error Console?
let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled");
if (consoleEnabled) {
@@ -1152,19 +1194,6 @@ var gBrowserInit = {
document.getElementById("appmenu_charsetMenu").hidden = true;
#endif
-#ifdef MOZ_DEVTOOLS
- // Enable Responsive UI?
- let responsiveUIEnabled = gPrefService.getBoolPref("devtools.responsiveUI.enabled");
- if (responsiveUIEnabled) {
- let cmd = document.getElementById("Tools:ResponsiveUI");
- cmd.removeAttribute("disabled");
- cmd.removeAttribute("hidden");
- }
-
- // Add Devtools menuitems and listeners
- gDevToolsBrowser.registerBrowserWindow(window);
-#endif
-
let appMenuButton = document.getElementById("appmenu-button");
let appMenuPopup = document.getElementById("appmenu-popup");
if (appMenuButton && appMenuPopup) {
@@ -1205,6 +1234,8 @@ var gBrowserInit = {
setTimeout(function () { BrowserChromeTest.markAsReady(); }, 0);
});
+ this.delayedStartupFinished = true;
+
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
},
@@ -1240,15 +1271,6 @@ var gBrowserInit = {
if (!this._loadHandled)
return;
-#ifdef MOZ_DEVTOOLS
- gDevToolsBrowser.forgetBrowserWindow(window);
-
- let desc = Object.getOwnPropertyDescriptor(window, "DeveloperToolbar");
- if (desc && !desc.get) {
- DeveloperToolbar.destroy();
- }
-#endif
-
// First clean up services initialized in gBrowserInit.onLoad (or those whose
// uninit methods don't depend on the services having been initialized).
@@ -1278,6 +1300,12 @@ var gBrowserInit = {
ToolbarIconColor.uninit();
+#ifdef MOZ_DEVTOOLS
+ DevToolsTheme.uninit();
+#endif
+
+ UserAgentCompatibility.uninit();
+
var enumerator = Services.wm.getEnumerator(null);
enumerator.getNext();
if (!enumerator.hasMoreElements()) {
@@ -1314,6 +1342,13 @@ var gBrowserInit = {
Services.obs.removeObserver(gXSSObserver, "xss-on-violate-policy");
try {
+ gPrefService.removeObserver(gURLBarSettings.prefSuggest, gURLBarSettings);
+ gPrefService.removeObserver(gURLBarSettings.prefKeyword, gURLBarSettings);
+ } catch (ex) {
+ Cu.reportError(ex);
+ }
+
+ try {
gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton);
} catch (ex) {
Cu.reportError(ex);
@@ -1859,7 +1894,7 @@ function BrowserTryToCloseWindow()
window.close(); // WindowIsClosing does all the necessary checks
}
-function loadURI(uri, referrer, postData, allowThirdPartyFixup) {
+function loadURI(uri, referrer, postData, allowThirdPartyFixup, referrerPolicy) {
if (postData === undefined)
postData = null;
@@ -1870,92 +1905,135 @@ function loadURI(uri, referrer, postData, allowThirdPartyFixup) {
}
try {
- gBrowser.loadURIWithFlags(uri, flags, referrer, null, postData);
+ gBrowser.loadURIWithFlags(uri, {
+ flags: flags,
+ referrerURI: referrer,
+ referrerPolicy: referrerPolicy,
+ postData: postData,
+ });
} catch (e) {}
}
-function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) {
- // Initialize outparam to false
- if (aMayInheritPrincipal)
- aMayInheritPrincipal.value = false;
+/**
+ * Given a urlbar value, discerns between URIs, keywords and aliases.
+ *
+ * @param url
+ * The urlbar value.
+ * @param callback (optional, deprecated)
+ * The callback function invoked when done. This parameter is
+ * deprecated, please use the Promise that is returned.
+ *
+ * @return Promise<{ postData, url, mayInheritPrincipal }>
+ */
+function getShortcutOrURIAndPostData(url, callback = null) {
+ if (callback) {
+ Deprecated.warning("Please use the Promise returned by " +
+ "getShortcutOrURIAndPostData() instead of passing a " +
+ "callback",
+ "https://bugzilla.mozilla.org/show_bug.cgi?id=1100294");
+ }
- var shortcutURL = null;
- var keyword = aURL;
- var param = "";
+ return Task.spawn(function* () {
+ let mayInheritPrincipal = false;
+ let postData = null;
+ let shortcutURL = null;
+ let keyword = url;
+ let param = "";
- var offset = aURL.indexOf(" ");
- if (offset > 0) {
- keyword = aURL.substr(0, offset);
- param = aURL.substr(offset + 1);
- }
+ let offset = url.indexOf(" ");
+ if (offset > 0) {
+ keyword = url.substr(0, offset);
+ param = url.substr(offset + 1);
+ }
- if (!aPostDataRef)
- aPostDataRef = {};
+ let engine = Services.search.getEngineByAlias(keyword);
+ if (engine) {
+ let submission = engine.getSubmission(param, null, "keyword");
+ postData = submission.postData;
+ return { postData: submission.postData, url: submission.uri.spec,
+ mayInheritPrincipal };
+ }
- var engine = Services.search.getEngineByAlias(keyword);
- if (engine) {
- var submission = engine.getSubmission(param);
- aPostDataRef.value = submission.postData;
- return submission.uri.spec;
- }
+ let entry = yield PlacesUtils.keywords.fetch(keyword);
+ if (entry) {
+ shortcutURL = entry.url.href;
+ postData = entry.postData;
+ }
- [shortcutURL, aPostDataRef.value] =
- PlacesUtils.getURLAndPostDataForKeyword(keyword);
+ if (!shortcutURL) {
+ return { postData, url, mayInheritPrincipal };
+ }
- if (!shortcutURL)
- return aURL;
+ let escapedPostData = "";
+ if (postData)
+ escapedPostData = unescape(postData);
- var postData = "";
- if (aPostDataRef.value)
- postData = unescape(aPostDataRef.value);
+ if (/%s/i.test(shortcutURL) || /%s/i.test(escapedPostData)) {
+ let charset = "";
+ const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
+ let matches = shortcutURL.match(re);
- if (/%s/i.test(shortcutURL) || /%s/i.test(postData)) {
- var charset = "";
- const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
- var matches = shortcutURL.match(re);
- if (matches)
- [, shortcutURL, charset] = matches;
- else {
- // Try to get the saved character-set.
- try {
- // makeURI throws if URI is invalid.
- // Will return an empty string if character-set is not found.
- charset = PlacesUtils.history.getCharsetForURI(makeURI(shortcutURL));
- } catch (e) {}
- }
+ if (matches) {
+ [, shortcutURL, charset] = matches;
+ } else {
+ let uri;
+ try {
+ // makeURI() throws if URI is invalid.
+ uri = makeURI(shortcutURL);
+ } catch (ex) {}
+
+ if (uri) {
+ // Try to get the saved character-set.
+ // Will return an empty string if character-set is not found.
+ charset = yield PlacesUtils.getCharsetForURI(uri);
+ }
+ }
- // encodeURIComponent produces UTF-8, and cannot be used for other charsets.
- // escape() works in those cases, but it doesn't uri-encode +, @, and /.
- // Therefore we need to manually replace these ASCII characters by their
- // encodeURIComponent result, to match the behavior of nsEscape() with
- // url_XPAlphas
- var encodedParam = "";
- if (charset && charset != "UTF-8")
- encodedParam = escape(convertFromUnicode(charset, param)).
- replace(/[+@\/]+/g, encodeURIComponent);
- else // Default charset is UTF-8
- encodedParam = encodeURIComponent(param);
+ // encodeURIComponent produces UTF-8, and cannot be used for other charsets.
+ // escape() works in those cases, but it doesn't uri-encode +, @, and /.
+ // Therefore we need to manually replace these ASCII characters by their
+ // encodeURIComponent result, to match the behavior of nsEscape() with
+ // url_XPAlphas
+ let encodedParam = "";
+ if (charset && charset != "UTF-8")
+ encodedParam = escape(convertFromUnicode(charset, param)).
+ replace(/[+@\/]+/g, encodeURIComponent);
+ else // Default charset is UTF-8
+ encodedParam = encodeURIComponent(param);
- shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
+ shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
- if (/%s/i.test(postData)) // POST keyword
- aPostDataRef.value = getPostDataStream(postData, param, encodedParam,
- "application/x-www-form-urlencoded");
- }
- else if (param) {
- // This keyword doesn't take a parameter, but one was provided. Just return
- // the original URL.
- aPostDataRef.value = null;
+ if (/%s/i.test(escapedPostData)) // POST keyword
+ postData = getPostDataStream(escapedPostData, param, encodedParam,
+ "application/x-www-form-urlencoded");
- return aURL;
- }
+ // This URL came from a bookmark, so it's safe to let it inherit the current
+ // document's principal.
+ mayInheritPrincipal = true;
+
+ return { postData, url: shortcutURL, mayInheritPrincipal };
+ }
+
+ if (param) {
+ // This keyword doesn't take a parameter, but one was provided. Just return
+ // the original URL.
+ postData = null;
+
+ return { postData, url, mayInheritPrincipal };
+ }
+
+ // This URL came from a bookmark, so it's safe to let it inherit the current
+ // document's principal.
+ mayInheritPrincipal = true;
- // This URL came from a bookmark, so it's safe to let it inherit the current
- // document's principal.
- if (aMayInheritPrincipal)
- aMayInheritPrincipal.value = true;
+ return { postData, url: shortcutURL, mayInheritPrincipal };
+ }).then(data => {
+ if (callback) {
+ callback(data);
+ }
- return shortcutURL;
+ return data;
+ });
}
function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType) {
@@ -2010,49 +2088,43 @@ function readFromClipboard()
return url;
}
-function BrowserViewSourceOfDocument(aDocument)
+function BrowserViewSourceOfDocument(aArgsOrDocument)
{
- var pageCookie;
- var webNav;
+ let args;
+
+ if (aArgsOrDocument instanceof Document) {
+ let doc = aArgsOrDocument;
+
+ let requestor = doc.defaultView
+ .QueryInterface(Ci.nsIInterfaceRequestor);
+ let browser = requestor.getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell)
+ .chromeEventHandler;
+ let outerWindowID = requestor.getInterface(Ci.nsIDOMWindowUtils)
+ .outerWindowID;
+ let URL = browser.currentURI.spec;
+ args = { browser, outerWindowID, URL };
+ } else {
+ args = aArgsOrDocument;
+ }
- // Get the document charset
- var docCharset = "charset=" + aDocument.characterSet;
+ let viewInternal = () => {
+ top.gViewSourceUtils.viewSource(args);
+ }
- // Get the nsIWebNavigation associated with the document
- try {
- var win;
- var ifRequestor;
-
- // Get the DOMWindow for the requested document. If the DOMWindow
- // cannot be found, then just use the content window...
- //
- // XXX: This is a bit of a hack...
- win = aDocument.defaultView;
- if (win == window) {
- win = content;
+ // Check if external view source is enabled. If so, try it. If it fails,
+ // fallback to internal view source.
+ if (Services.prefs.getBoolPref("view_source.editor.external")) {
+ top.gViewSourceUtils
+ .openInExternalEditor(args, null, null, null, result => {
+ if (!result) {
+ viewInternal();
}
- ifRequestor = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
-
- webNav = ifRequestor.getInterface(nsIWebNavigation);
- } catch(err) {
- // If nsIWebNavigation cannot be found, just get the one for the whole
- // window...
- webNav = gBrowser.webNavigation;
- }
- //
- // Get the 'PageDescriptor' for the current document. This allows the
- // view-source to access the cached copy of the content rather than
- // refetching it from the network...
- //
- try{
- var PageLoader = webNav.QueryInterface(Components.interfaces.nsIWebPageDescriptor);
-
- pageCookie = PageLoader.currentDescriptor;
- } catch(err) {
- // If no page descriptor is available, just use the view-source URL...
+ });
+ } else {
+ // Display using internal view source
+ viewInternal();
}
-
- top.gViewSourceUtils.viewSource(webNav.currentURI.spec, pageCookie, aDocument);
}
// doc - document to use for source, or null for this window's document
@@ -2313,7 +2385,7 @@ function BrowserOnAboutPageLoad(doc) {
/**
* Handle command events bubbling up from error page content
*/
-let BrowserOnClick = {
+var BrowserOnClick = {
handleEvent: function BrowserOnClick_handleEvent(aEvent) {
if (!aEvent.isTrusted || // Don't trust synthetic events
aEvent.button == 2 || aEvent.target.localName != "button") {
@@ -2620,8 +2692,8 @@ var browserDragAndDrop = {
}
},
- drop: function (aEvent, aName, aDisallowInherit) {
- return Services.droppedLinkHandler.dropLink(aEvent, aName, aDisallowInherit);
+ dropLinks: function (aEvent, aDisallowInherit) {
+ return Services.droppedLinkHandler.dropLinks(aEvent, aDisallowInherit);
}
};
@@ -2629,8 +2701,10 @@ var homeButtonObserver = {
onDrop: function (aEvent)
{
// disallow setting home pages that inherit the principal
- let url = browserDragAndDrop.drop(aEvent, {}, true);
- setTimeout(openHomeDialog, 0, url);
+ let links = browserDragAndDrop.dropLinks(aEvent, true);
+ if (links.length) {
+ setTimeout(openHomeDialog, 0, links.map(link => link.url).join("|"));
+ }
},
onDragOver: function (aEvent)
@@ -2646,18 +2720,24 @@ var homeButtonObserver = {
function openHomeDialog(aURL)
{
var promptTitle = gNavigatorBundle.getString("droponhometitle");
- var promptMsg = gNavigatorBundle.getString("droponhomemsg");
+ var promptMsg;
+ if (aURL.includes("|")) {
+ promptMsg = gNavigatorBundle.getString("droponhomemsgMultiple");
+ } else {
+ promptMsg = gNavigatorBundle.getString("droponhomemsg");
+ }
+
var pressedVal = Services.prompt.confirmEx(window, promptTitle, promptMsg,
Services.prompt.STD_YES_NO_BUTTONS,
null, null, null, null, {value:0});
if (pressedVal == 0) {
try {
- var str = Components.classes["@mozilla.org/supports-string;1"]
- .createInstance(Components.interfaces.nsISupportsString);
- str.data = aURL;
+ var homepageStr = Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(Components.interfaces.nsISupportsString);
+ homepageStr.data = aURL;
gPrefService.setComplexValue("browser.startup.homepage",
- Components.interfaces.nsISupportsString, str);
+ Components.interfaces.nsISupportsString, homepageStr);
} catch (ex) {
dump("Failed to set the home page.\n"+ex+"\n");
}
@@ -2705,13 +2785,16 @@ var newTabButtonObserver = {
onDrop: function (aEvent)
{
- let url = browserDragAndDrop.drop(aEvent, { });
- var postData = {};
- url = getShortcutOrURI(url, postData);
- if (url) {
- // allow third-party services to fixup this URL
- openNewTabWith(url, null, postData.value, aEvent, true);
- }
+ let links = browserDragAndDrop.dropLinks(aEvent);
+ Task.spawn(function*() {
+ for (let link of links) {
+ let data = yield getShortcutOrURIAndPostData(link.url);
+ if (data.url) {
+ // allow third-party services to fixup this URL
+ openNewTabWith(data.url, null, data.postData, aEvent, true);
+ }
+ }
+ });
}
}
@@ -2725,13 +2808,16 @@ var newWindowButtonObserver = {
},
onDrop: function (aEvent)
{
- let url = browserDragAndDrop.drop(aEvent, { });
- var postData = {};
- url = getShortcutOrURI(url, postData);
- if (url) {
- // allow third-party services to fixup this URL
- openNewWindowWith(url, null, postData.value, true);
- }
+ let links = browserDragAndDrop.dropLinks(aEvent);
+ Task.spawn(function*() {
+ for (let link of links) {
+ let data = yield getShortcutOrURIAndPostData(link.url);
+ if (data.url) {
+ // allow third-party services to fixup this URL
+ openNewWindowWith(data.url, null, data.postData, true);
+ }
+ }
+ });
}
}
@@ -2833,7 +2919,7 @@ const DOMLinkHandler = {
break;
let tab = gBrowser.tabs[browserIndex];
- gBrowser.setIcon(tab, uri.spec);
+ gBrowser.setIcon(tab, uri.spec, link.ownerDocument.nodePrincipal);
iconAdded = true;
}
break;
@@ -3425,26 +3511,6 @@ function updateCharacterEncodingMenuState()
}
}
-/**
- * Returns true if |aMimeType| is text-based, false otherwise.
- *
- * @param aMimeType
- * The MIME type to check.
- *
- * If adding types to this function, please also check the similar
- * function in findbar.xml
- */
-function mimeTypeIsTextBased(aMimeType)
-{
- return aMimeType.startsWith("text/") ||
- aMimeType.endsWith("+xml") ||
- aMimeType == "application/x-javascript" ||
- aMimeType == "application/javascript" ||
- aMimeType == "application/json" ||
- aMimeType == "application/xml" ||
- aMimeType == "mozilla.application/cached-xul";
-}
-
var XULBrowserWindow = {
// Stored Status, Link and Loading values
status: "",
@@ -3668,7 +3734,7 @@ var XULBrowserWindow = {
this.setDefaultStatus(msg);
// Disable menu entries for images, enable otherwise
- if (!gMultiProcessBrowser && content.document && mimeTypeIsTextBased(content.document.contentType))
+ if (!gMultiProcessBrowser && content.document && BrowserUtils.mimeTypeIsTextBased(content.document.contentType))
this.isImage.removeAttribute('disabled');
else
this.isImage.setAttribute('disabled', 'true');
@@ -3716,7 +3782,7 @@ var XULBrowserWindow = {
}
// Disable menu entries for images, enable otherwise
- if (!gMultiProcessBrowser && content.document && mimeTypeIsTextBased(content.document.contentType))
+ if (!gMultiProcessBrowser && content.document && BrowserUtils.mimeTypeIsTextBased(content.document.contentType))
this.isImage.removeAttribute('disabled');
else
this.isImage.setAttribute('disabled', 'true');
@@ -3814,11 +3880,16 @@ var XULBrowserWindow = {
gFindBar.close();
}
+ // XXX
+ // See: https://github.com/MoonchildProductions/Pale-Moon/issues/364
+ // An actual preference: findbar.highlightAll
+ /*
if (!(gPrefService.getBoolPref("accessibility.typeaheadfind.highlightallremember") ||
gPrefService.getBoolPref("accessibility.typeaheadfind.highlightallbydefault"))) {
// fix bug 253793 - turn off highlight when page changes
gFindBar.getElement("highlight").checked = false;
}
+ */
}
}
UpdateBackForwardCommands(gBrowser.webNavigation);
@@ -4233,6 +4304,13 @@ nsBrowserAccess.prototype = {
else
aWhere = gPrefService.getIntPref("browser.link.open_newwindow");
}
+
+ let referrer = aOpener ? makeURI(aOpener.location.href) : null;
+ let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT;
+ if (aOpener && aOpener.document) {
+ referrerPolicy = aOpener.document.referrerPolicy;
+ }
+
switch (aWhere) {
case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
// FIXME: Bug 408379. So how come this doesn't send the
@@ -4271,6 +4349,7 @@ nsBrowserAccess.prototype = {
let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", {
referrerURI: referrer,
+ referrerPolicy: referrerPolicy,
fromExternal: isExternal,
inBackground: loadInBackground});
let browser = win.gBrowser.getBrowserForTab(tab);
@@ -4286,11 +4365,14 @@ nsBrowserAccess.prototype = {
default : // OPEN_CURRENTWINDOW or an illegal value
newWindow = content;
if (aURI) {
- let referrer = aOpener ? makeURI(aOpener.location.href) : null;
let loadflags = isExternal ?
Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
- gBrowser.loadURIWithFlags(aURI.spec, loadflags, referrer, null, null);
+ gBrowser.loadURIWithFlags(aURI.spec, {
+ flags: loadflags,
+ referrerURI: referrer,
+ referrerPolicy: referrerPolicy,
+ });
}
if (!gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground"))
window.focus();
@@ -5020,7 +5102,8 @@ function handleLinkClick(event, href, linkNode) {
urlSecurityCheck(href, doc.nodePrincipal);
openLinkIn(href, where, { referrerURI: doc.documentURIObject,
- charset: doc.characterSet });
+ charset: doc.characterSet,
+ referrerPolicy: doc.referrerPolicy });
event.preventDefault();
return true;
}
@@ -5034,36 +5117,81 @@ function middleMousePaste(event) {
// bar's behavior (stripsurroundingwhitespace)
clipboard = clipboard.replace(/\s*\n\s*/g, "");
- let mayInheritPrincipal = { value: false };
- let url = getShortcutOrURI(clipboard, mayInheritPrincipal);
- try {
- makeURI(url);
- } catch (ex) {
- // Not a valid URI.
- return;
+ // if it's not the current tab, we don't need to do anything because the
+ // browser doesn't exist.
+ let where = whereToOpenLink(event, true, false);
+ let lastLocationChange;
+ if (where == "current") {
+ lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
}
- try {
- addToUrlbarHistory(url);
- } catch (ex) {
- // Things may go wrong when adding url to session history,
- // but don't let that interfere with the loading of the url.
- Cu.reportError(ex);
- }
+ getShortcutOrURIAndPostData(clipboard).then(data => {
+ try {
+ makeURI(data.url);
+ } catch (ex) {
+ // Not a valid URI.
+ return;
+ }
+
+ try {
+ addToUrlbarHistory(data.url);
+ } catch (ex) {
+ // Things may go wrong when adding url to session history,
+ // but don't let that interfere with the loading of the url.
+ Cu.reportError(ex);
+ }
- openUILink(url, event,
- { ignoreButton: true,
- disallowInheritPrincipal: !mayInheritPrincipal.value });
+ if (where != "current" ||
+ lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
+ openUILink(data.url, event,
+ { ignoreButton: true,
+ disallowInheritPrincipal: !data.mayInheritPrincipal,
+ initiatingDoc: event ? event.target.ownerDocument : null });
+ }
+ });
event.stopPropagation();
}
-function handleDroppedLink(event, url, name)
+// handleDroppedLink has the following 2 overloads:
+// handleDroppedLink(event, url, name)
+// handleDroppedLink(event, links)
+function handleDroppedLink(event, urlOrLinks, name)
{
- let postData = { };
- let uri = getShortcutOrURI(url, postData);
- if (uri)
- loadURI(uri, null, postData.value, false);
+ let links;
+ if (Array.isArray(urlOrLinks)) {
+ links = urlOrLinks;
+ } else {
+ links = [{ url: urlOrLinks, name, type: "" }];
+ }
+
+ let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
+
+ let userContextId = gBrowser.selectedBrowser
+ .getAttribute("usercontextid") || 0;
+
+ let inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
+ if (event.shiftKey)
+ inBackground = !inBackground;
+
+ Task.spawn(function*() {
+ let urls = [];
+ let postDatas = [];
+ for (let link of links) {
+ let data = yield getShortcutOrURIAndPostData(link.url);
+ urls.push(data.url);
+ postDatas.push(data.postData);
+ }
+ if (lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
+ gBrowser.loadTabs(urls, {
+ inBackground,
+ replace: true,
+ allowThirdPartyFixup: false,
+ postDatas,
+ userContextId,
+ });
+ }
+ });
// Keep the event from being handled by the dragDrop listeners
// built-in to goanna if they happen to be above us.
@@ -5178,7 +5306,6 @@ function charsetLoadListener() {
}
}
-
var gPageStyleMenu = {
_getAllStyleSheets: function (frameset) {
@@ -6825,20 +6952,9 @@ var TabContextMenu = {
};
#ifdef MOZ_DEVTOOLS
+// Note: Do not delete! It is used for: base/content/nsContextMenu.js
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
- "resource://gre/modules/devtools/gDevTools.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "gDevToolsBrowser",
- "resource://gre/modules/devtools/gDevTools.jsm");
-
-Object.defineProperty(this, "HUDService", {
- get: function HUDService_getter() {
- let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
- return devtools.require("devtools/webconsole/hudservice").HUDService;
- },
- configurable: true,
- enumerable: true
-});
+ "resource://devtools/client/framework/gDevTools.jsm");
#endif
// Prompt user to restart the browser in safe mode or normally
@@ -6929,49 +7045,6 @@ function toggleAddonBar() {
setToolbarVisibility(addonBar, addonBar.collapsed);
}
-#ifdef MOZ_DEVTOOLS
-var Scratchpad = {
- prefEnabledName: "devtools.scratchpad.enabled",
-
- openScratchpad: function SP_openScratchpad() {
- return this.ScratchpadManager.openScratchpad();
- }
-};
-
-XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() {
- let tmp = {};
- Cu.import("resource://gre/modules/devtools/scratchpad-manager.jsm", tmp);
- return tmp.ScratchpadManager;
-});
-
-var ResponsiveUI = {
- toggle: function RUI_toggle() {
- this.ResponsiveUIManager.toggle(window, gBrowser.selectedTab);
- }
-};
-
-XPCOMUtils.defineLazyGetter(ResponsiveUI, "ResponsiveUIManager", function() {
- let tmp = {};
- Cu.import("resource://gre/modules/devtools/responsivedesign.jsm", tmp);
- return tmp.ResponsiveUIManager;
-});
-
-function openEyedropper() {
- var eyedropper = new this.Eyedropper(this, { context: "menu",
- copyOnSelect: true });
- eyedropper.open();
-}
-
-Object.defineProperty(this, "Eyedropper", {
- get: function() {
- let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
- return devtools.require("devtools/eyedropper/eyedropper").Eyedropper;
- },
- configurable: true,
- enumerable: true
-});
-#endif
-
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
#ifdef XP_WIN
// Only show resizers on Windows 2000 and XP
@@ -7051,7 +7124,8 @@ function focusNextFrame(event) {
if (element.ownerDocument == document)
focusAndSelectUrlBar();
}
-let BrowserChromeTest = {
+
+var BrowserChromeTest = {
_cb: null,
_ready: false,
markAsReady: function () {
@@ -7069,7 +7143,7 @@ let BrowserChromeTest = {
}
};
-let ToolbarIconColor = {
+var ToolbarIconColor = {
init: function () {
this._initialized = true;
diff --git a/application/palemoon/base/content/browser.xul b/application/palemoon/base/content/browser.xul
index f83010023..c2553f295 100644
--- a/application/palemoon/base/content/browser.xul
+++ b/application/palemoon/base/content/browser.xul
@@ -13,7 +13,7 @@
<?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
#ifdef MOZ_DEVTOOLS
-<?xml-stylesheet href="chrome://global/skin/devtools/common.css" type="text/css"?>
+<?xml-stylesheet href="chrome://devtools/skin/devtools-browser.css" type="text/css"?>
#endif
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
@@ -65,6 +65,9 @@
# wishes to include *must* go into the global-scripts.inc file
# so that they can be shared by macBrowserOverlay.xul.
#include global-scripts.inc
+#ifdef MOZ_DEVTOOLS
+#include global-devtools-theme-scripts.inc
+#endif
<script type="application/javascript" src="chrome://browser/content/nsContextMenu.js"/>
<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
@@ -125,9 +128,25 @@
<!-- for search and content formfill/pw manager -->
<panel type="autocomplete" id="PopupAutoComplete" noautofocus="true" hidden="true"/>
+ <panel type="private-autocomplete" id="PopupAutoComplete" noautofocus="true" hidden="true"/>
<!-- for url bar autocomplete -->
<panel type="autocomplete-richlistbox" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
+ <panel type="private-autocomplete-richlistbox" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
+
+ <!-- for date/time picker. consumeoutsideclicks is set to never, so that
+ clicks on the anchored input box are never consumed. -->
+ <panel id="DateTimePickerPanel"
+ type="arrow"
+ hidden="true"
+ orient="vertical"
+ noautofocus="true"
+ norolluponanchor="true"
+ consumeoutsideclicks="never"
+ level="parent"
+ tabspecific="true">
+ <iframe id="dateTimePopupFrame"/>
+ </panel>
<!-- for invalid form error message -->
<panel id="invalid-form-popup" type="arrow" orient="vertical" noautofocus="true" hidden="true" level="parent">
@@ -136,7 +155,6 @@
<panel id="editBookmarkPanel"
type="arrow"
- footertype="promobox"
orient="vertical"
ignorekeys="true"
consumeoutsideclicks="true"
@@ -410,8 +428,8 @@
<toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
title="&locationItem.title;" class="chromeclass-location" removable="true">
<textbox id="urlbar" flex="1"
- placeholder="&urlbar.placeholder2;"
- type="autocomplete"
+ placeholder=""
+ type="private-autocomplete"
autocompletesearch="urlinline history"
autocompletesearchparam="enable-actions"
autocompletepopup="PopupAutoCompleteRichResult"
@@ -440,8 +458,10 @@
<image id="alert-plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="blocked-plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="mixed-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/>
+#ifdef MOZ_WEBRTC
<image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/>
+#endif
<image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/>
</box>
@@ -513,7 +533,7 @@
flex="100" persist="width" removable="true">
<searchbar id="searchbar" flex="1"/>
</toolbaritem>
-
+#ifdef MOZ_WEBRTC
<toolbarbutton id="webrtc-status-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
type="menu"
@@ -525,7 +545,7 @@
onpopuphiding="WebrtcIndicator.clearPopup(this);"
oncommand="WebrtcIndicator.menuCommand(event.target);"/>
</toolbarbutton>
-
+#endif
<toolbarbutton id="bookmarks-menu-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
persist="class"
@@ -941,7 +961,8 @@
flex="1" contenttooltip="aHTMLTooltip"
tabcontainer="tabbrowser-tabs"
contentcontextmenu="contentAreaContextMenu"
- autocompletepopup="PopupAutoComplete"/>
+ autocompletepopup="PopupAutoComplete"
+ datetimepicker="DateTimePickerPanel"/>
<chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
<statuspanel id="statusbar-display" inactive="true"/>
</vbox>
@@ -971,33 +992,6 @@
<vbox id="browser-bottombox" layer="true">
<notificationbox id="global-notificationbox"/>
-#ifdef MOZ_DEVTOOLS
- <toolbar id="developer-toolbar"
- class="devtools-toolbar"
- hidden="true">
-#ifdef XP_MACOSX
- <toolbarbutton id="developer-toolbar-closebutton"
- class="devtools-closebutton"
- oncommand="DeveloperToolbar.hide();"
- tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
-#endif
- <stack class="gclitoolbar-stack-node" flex="1">
- <textbox class="gclitoolbar-input-node" rows="1"/>
- <hbox class="gclitoolbar-complete-node"/>
- </stack>
- <toolbarbutton id="developer-toolbar-toolbox-button"
- class="developer-toolbar-button"
- observes="devtoolsMenuBroadcaster_DevToolbox"
- tooltiptext="&devToolbarToolsButton.tooltip;"/>
-#ifndef XP_MACOSX
- <toolbarbutton id="developer-toolbar-closebutton"
- class="devtools-closebutton"
- oncommand="DeveloperToolbar.hide();"
- tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
-#endif
- </toolbar>
-#endif
-
<toolbar id="addon-bar"
toolbarname="&statusBar.label;" accesskey="&statusBar.accesskey;"
collapsed="true"
diff --git a/application/palemoon/base/content/content.js b/application/palemoon/base/content/content.js
index 19032eb84..653dac3e3 100644
--- a/application/palemoon/base/content/content.js
+++ b/application/palemoon/base/content/content.js
@@ -3,9 +3,9 @@
* 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/. */
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cu = Components.utils;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -13,6 +13,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
"resource://gre/modules/LoginManagerContent.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "LoginFormFactory",
+ "resource://gre/modules/LoginManagerContent.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "InsecurePasswordUtils",
"resource://gre/modules/InsecurePasswordUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FormSubmitObserver",
@@ -47,8 +49,9 @@ addMessageListener("Browser:HideSessionRestoreButton", function (message) {
});
addEventListener("DOMFormHasPassword", function(event) {
- InsecurePasswordUtils.checkForInsecurePasswords(event.target);
- LoginManagerContent.onFormPassword(event);
+ LoginManagerContent.onDOMFormHasPassword(event, content);
+ let formLike = LoginFormFactory.createFromForm(event.target);
+ InsecurePasswordUtils.reportInsecurePasswords(formLike);
});
addEventListener("DOMAutoComplete", function(event) {
LoginManagerContent.onUsernameInput(event);
@@ -57,8 +60,120 @@ addEventListener("blur", function(event) {
LoginManagerContent.onUsernameInput(event);
});
+// Provide gContextMenuContentData for 'sdk/context-menu'
+var handleContentContextMenu = function (event) {
+ let defaultPrevented = event.defaultPrevented;
+ if (!Services.prefs.getBoolPref("dom.event.contextmenu.enabled")) {
+ let plugin = null;
+ try {
+ plugin = event.target.QueryInterface(Ci.nsIObjectLoadingContent);
+ } catch (e) {}
+ if (plugin && plugin.displayedType == Ci.nsIObjectLoadingContent.TYPE_PLUGIN) {
+ // Don't open a context menu for plugins.
+ return;
+ }
+
+ defaultPrevented = false;
+ }
+
+ if (defaultPrevented)
+ return;
+
+ let addonInfo = {};
+ let subject = {
+ event: event,
+ addonInfo: addonInfo,
+ };
+ subject.wrappedJSObject = subject;
+ Services.obs.notifyObservers(subject, "content-contextmenu", null);
+
+ let doc = event.target.ownerDocument;
+ let docLocation = doc.mozDocumentURIIfNotForErrorPages;
+ docLocation = docLocation && docLocation.spec;
+ let charSet = doc.characterSet;
+ let baseURI = doc.baseURI;
+ let referrer = doc.referrer;
+ let referrerPolicy = doc.referrerPolicy;
+ let frameOuterWindowID = doc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .outerWindowID;
+ let loginFillInfo = LoginManagerContent.getFieldContext(event.target);
+
+ // The same-origin check will be done in nsContextMenu.openLinkInTab.
+ let parentAllowsMixedContent = !!docShell.mixedContentChannel;
+
+ // get referrer attribute from clicked link and parse it
+ // if per element referrer is enabled, the element referrer overrules
+ // the document wide referrer
+ if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer")) {
+ let referrerAttrValue = Services.netUtils.parseAttributePolicyString(event.target.
+ getAttribute("referrerpolicy"));
+ if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_UNSET) {
+ referrerPolicy = referrerAttrValue;
+ }
+ }
+
+ // Media related cache info parent needs for saving
+ let contentType = null;
+ let contentDisposition = null;
+ if (event.target.nodeType == Ci.nsIDOMNode.ELEMENT_NODE &&
+ event.target instanceof Ci.nsIImageLoadingContent &&
+ event.target.currentURI) {
+
+ try {
+ let imageCache =
+ Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
+ .getImgCacheForDocument(doc);
+ let props =
+ imageCache.findEntryProperties(event.target.currentURI, doc);
+ try {
+ contentType = props.get("type", Ci.nsISupportsCString).data;
+ } catch (e) {}
+ try {
+ contentDisposition =
+ props.get("content-disposition", Ci.nsISupportsCString).data;
+ } catch (e) {}
+ } catch (e) {}
+ }
+
+ let selectionInfo = BrowserUtils.getSelectionDetails(content);
+
+ let loadContext = docShell.QueryInterface(Ci.nsILoadContext);
+ let userContextId = loadContext.originAttributes.userContextId;
+
+ let browser = docShell.chromeEventHandler;
+ let mainWin = browser.ownerGlobal;
+
+ mainWin.gContextMenuContentData = {
+ isRemote: false,
+ event: event,
+ popupNode: event.target,
+ browser: browser,
+ addonInfo: addonInfo,
+ documentURIObject: doc.documentURIObject,
+ docLocation: docLocation,
+ charSet: charSet,
+ referrer: referrer,
+ referrerPolicy: referrerPolicy,
+ contentType: contentType,
+ contentDisposition: contentDisposition,
+ selectionInfo: selectionInfo,
+ loginFillInfo,
+ parentAllowsMixedContent,
+ userContextId,
+ };
+}
+
+Cc["@mozilla.org/eventlistenerservice;1"]
+ .getService(Ci.nsIEventListenerService)
+ .addSystemEventListener(global, "contextmenu", handleContentContextMenu, false);
+
// Lazily load the finder code
addMessageListener("Finder:Initialize", function () {
let {RemoteFinderListener} = Cu.import("resource://gre/modules/RemoteFinder.jsm", {});
new RemoteFinderListener(global);
-}); \ No newline at end of file
+});
+
+addEventListener("DOMWebNotificationClicked", function(event) {
+ sendAsyncMessage("DOMWebNotificationClicked", {});
+}, false);
diff --git a/application/palemoon/base/content/global-devtools-theme-scripts.inc b/application/palemoon/base/content/global-devtools-theme-scripts.inc
new file mode 100644
index 000000000..408728ed5
--- /dev/null
+++ b/application/palemoon/base/content/global-devtools-theme-scripts.inc
@@ -0,0 +1,6 @@
+# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+# 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/.
+
+<script type="application/javascript" src="chrome://browser/content/browser-devtools-theme.js"/>
diff --git a/application/palemoon/base/content/macBrowserOverlay.xul b/application/palemoon/base/content/macBrowserOverlay.xul
index a4d583e16..b1ae838d0 100644
--- a/application/palemoon/base/content/macBrowserOverlay.xul
+++ b/application/palemoon/base/content/macBrowserOverlay.xul
@@ -24,6 +24,9 @@
# wishes to include *must* go into the global-scripts.inc file
# so that they can be shared by this overlay.
#include global-scripts.inc
+#ifdef MOZ_DEVTOOLS
+#include global-devtools-theme-scripts.inc
+#endif
<script type="application/javascript">
function OpenBrowserWindowFromDockMenu(options) {
diff --git a/application/palemoon/base/content/newtab/drag.js b/application/palemoon/base/content/newtab/drag.js
index 8f0bf674e..fbd688faa 100644
--- a/application/palemoon/base/content/newtab/drag.js
+++ b/application/palemoon/base/content/newtab/drag.js
@@ -7,7 +7,7 @@
/**
* This singleton implements site dragging functionality.
*/
-let gDrag = {
+var gDrag = {
/**
* The site offset to the drag start point.
*/
diff --git a/application/palemoon/base/content/newtab/dragDataHelper.js b/application/palemoon/base/content/newtab/dragDataHelper.js
index a66e4e87e..54348ab14 100644
--- a/application/palemoon/base/content/newtab/dragDataHelper.js
+++ b/application/palemoon/base/content/newtab/dragDataHelper.js
@@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#endif
-let gDragDataHelper = {
+var gDragDataHelper = {
get mimeType() {
return "text/x-moz-url";
},
diff --git a/application/palemoon/base/content/newtab/drop.js b/application/palemoon/base/content/newtab/drop.js
index d7bf30506..748652455 100644
--- a/application/palemoon/base/content/newtab/drop.js
+++ b/application/palemoon/base/content/newtab/drop.js
@@ -11,7 +11,7 @@ const DELAY_REARRANGE_MS = 100;
/**
* This singleton implements site dropping functionality.
*/
-let gDrop = {
+var gDrop = {
/**
* The last drop target.
*/
diff --git a/application/palemoon/base/content/newtab/dropPreview.js b/application/palemoon/base/content/newtab/dropPreview.js
index 903762345..fd7587a35 100644
--- a/application/palemoon/base/content/newtab/dropPreview.js
+++ b/application/palemoon/base/content/newtab/dropPreview.js
@@ -9,7 +9,7 @@
* indicate the transformation that results from dropping a cell at a certain
* position.
*/
-let gDropPreview = {
+var gDropPreview = {
/**
* Rearranges the sites currently contained in the grid when a site would be
* dropped onto the given cell.
diff --git a/application/palemoon/base/content/newtab/dropTargetShim.js b/application/palemoon/base/content/newtab/dropTargetShim.js
index a85a6ccd6..046dbea1e 100644
--- a/application/palemoon/base/content/newtab/dropTargetShim.js
+++ b/application/palemoon/base/content/newtab/dropTargetShim.js
@@ -9,7 +9,7 @@
* the default DnD target detection relies on the cursor's position. We want
* to pick a drop target based on the dragged site's position.
*/
-let gDropTargetShim = {
+var gDropTargetShim = {
/**
* Cache for the position of all cells, cleaned after drag finished.
*/
diff --git a/application/palemoon/base/content/newtab/grid.js b/application/palemoon/base/content/newtab/grid.js
index 37559a063..a614d0396 100644
--- a/application/palemoon/base/content/newtab/grid.js
+++ b/application/palemoon/base/content/newtab/grid.js
@@ -7,7 +7,7 @@
/**
* This singleton represents the grid that contains all sites.
*/
-let gGrid = {
+var gGrid = {
/**
* The DOM node of the grid.
*/
@@ -59,8 +59,13 @@ let gGrid = {
* Refreshes the grid and re-creates all sites.
*/
refresh: function Grid_refresh() {
+ let cells = this.cells;
+ if (!cells) {
+ return;
+ }
+
// Remove all sites.
- this.cells.forEach(function (cell) {
+ cells.forEach(function (cell) {
let node = cell.node;
let child = node.firstElementChild;
@@ -109,7 +114,12 @@ let gGrid = {
// (Re-)initialize all cells.
let cellElements = this.node.querySelectorAll(".newtab-cell");
- this._cells = [new Cell(this, cell) for (cell of cellElements)];
+ // Tycho: this._cells = [new Cell(this, cell) for (cell of cellElements)];
+ this.cells = [];
+
+ for (let cellItem of cellElements) {
+ this.cells.push(new Cell(this, cellItem));
+ }
},
/**
diff --git a/application/palemoon/base/content/newtab/newTab.js b/application/palemoon/base/content/newtab/newTab.js
index 77c929125..bba73fd7a 100644
--- a/application/palemoon/base/content/newtab/newTab.js
+++ b/application/palemoon/base/content/newtab/newTab.js
@@ -4,8 +4,8 @@
"use strict";
-let Cu = Components.utils;
-let Ci = Components.interfaces;
+var Cu = Components.utils;
+var Ci = Components.interfaces;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@@ -18,7 +18,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Rect",
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
-let {
+var {
links: gLinks,
allPages: gAllPages,
linkChecker: gLinkChecker,
diff --git a/application/palemoon/base/content/newtab/page.js b/application/palemoon/base/content/newtab/page.js
index afe5bfba8..fc836a55e 100644
--- a/application/palemoon/base/content/newtab/page.js
+++ b/application/palemoon/base/content/newtab/page.js
@@ -8,7 +8,7 @@
* This singleton represents the whole 'New Tab Page' and takes care of
* initializing all its components.
*/
-let gPage = {
+var gPage = {
/**
* Initializes the page.
*/
diff --git a/application/palemoon/base/content/newtab/transformations.js b/application/palemoon/base/content/newtab/transformations.js
index 6d1554f5f..0711d7d0a 100644
--- a/application/palemoon/base/content/newtab/transformations.js
+++ b/application/palemoon/base/content/newtab/transformations.js
@@ -9,7 +9,7 @@
* in the DOM and by showing or hiding the node. It additionally provides
* convenience methods to work with a site's DOM node.
*/
-let gTransformation = {
+var gTransformation = {
/**
* Returns the width of the left and top border of a cell. We need to take it
* into account when measuring and comparing site and cell positions.
diff --git a/application/palemoon/base/content/newtab/undo.js b/application/palemoon/base/content/newtab/undo.js
index 5f619e980..b856914d2 100644
--- a/application/palemoon/base/content/newtab/undo.js
+++ b/application/palemoon/base/content/newtab/undo.js
@@ -8,7 +8,7 @@
* Dialog allowing to undo the removal of single site or to completely restore
* the grid's original state.
*/
-let gUndoDialog = {
+var gUndoDialog = {
/**
* The undo dialog's timeout in miliseconds.
*/
diff --git a/application/palemoon/base/content/newtab/updater.js b/application/palemoon/base/content/newtab/updater.js
index 7b483e037..e6da37f87 100644
--- a/application/palemoon/base/content/newtab/updater.js
+++ b/application/palemoon/base/content/newtab/updater.js
@@ -8,7 +8,7 @@
* This singleton provides functionality to update the current grid to a new
* set of pinned and blocked sites. It adds, moves and removes sites.
*/
-let gUpdater = {
+var gUpdater = {
/**
* Updates the current grid according to its pinned and blocked sites.
* This removes old, moves existing and creates new sites to fill gaps.
diff --git a/application/palemoon/base/content/nsContextMenu.js b/application/palemoon/base/content/nsContextMenu.js
index 8e6bc96c2..f389491d3 100644
--- a/application/palemoon/base/content/nsContextMenu.js
+++ b/application/palemoon/base/content/nsContextMenu.js
@@ -4,6 +4,8 @@
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
+var gContextMenuContentData = null;
+
function nsContextMenu(aXulMenu, aIsShift) {
this.shouldDisplay = true;
this.initMenu(aXulMenu, aIsShift);
@@ -39,6 +41,7 @@ nsContextMenu.prototype = {
},
hiding: function CM_hiding() {
+ gContextMenuContentData = null;
InlineSpellCheckerUI.clearSuggestionsFromMenu();
InlineSpellCheckerUI.clearDictionaryListFromMenu();
InlineSpellCheckerUI.uninit();
@@ -265,7 +268,7 @@ nsContextMenu.prototype = {
// Hide menu entries for images, show otherwise
if (this.inFrame) {
- if (mimeTypeIsTextBased(this.target.ownerDocument.contentType))
+ if (BrowserUtils.mimeTypeIsTextBased(this.target.ownerDocument.contentType))
this.isFrameImage.removeAttribute('hidden');
else
this.isFrameImage.setAttribute('hidden', 'true');
@@ -422,12 +425,17 @@ nsContextMenu.prototype = {
},
inspectNode: function CM_inspectNode() {
- let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+ let {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
let gBrowser = this.browser.ownerDocument.defaultView.gBrowser;
- let tt = devtools.TargetFactory.forTab(gBrowser.selectedTab);
- return gDevTools.showToolbox(tt, "inspector").then(function(toolbox) {
+ let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
+
+ return gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
let inspector = toolbox.getCurrentPanel();
- inspector.selection.setNode(this.target, "browser-context-menu");
+
+ this.browser.messageManager.sendAsyncMessage("debug:inspect", {}, {node: this.target});
+ inspector.walker.findInspectingNode().then(nodeFront => {
+ inspector.selection.setNodeFront(nodeFront, "browser-context-menu");
+ });
}.bind(this));
},
@@ -745,7 +753,8 @@ nsContextMenu.prototype = {
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
openLinkIn(this.linkURL, "window",
{ charset: doc.characterSet,
- referrerURI: doc.documentURIObject });
+ referrerURI: doc.documentURIObject,
+ referrerPolicy: doc.referrerPolicy });
},
// Open linked-to URL in a new private window.
@@ -755,6 +764,7 @@ nsContextMenu.prototype = {
openLinkIn(this.linkURL, "window",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject,
+ referrerPolicy: doc.referrerPolicy,
private: true });
},
@@ -764,7 +774,8 @@ nsContextMenu.prototype = {
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
openLinkIn(this.linkURL, "tab",
{ charset: doc.characterSet,
- referrerURI: doc.documentURIObject });
+ referrerURI: doc.documentURIObject,
+ referrerPolicy: doc.referrerPolicy });
},
// open URL in current tab
@@ -901,11 +912,15 @@ nsContextMenu.prototype = {
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
let doc = this.target.ownerDocument;
openUILink(viewURL, e, { disallowInheritPrincipal: true,
- referrerURI: doc.documentURIObject });
+ referrerURI: doc.documentURIObject,
+ forceAllowDataURI: true });
}
},
saveVideoFrameAsImage: function () {
+ let referrerURI = document.documentURIObject;
+ let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
+
urlSecurityCheck(this.mediaURL, this.browser.contentPrincipal,
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
let name = "";
@@ -923,7 +938,9 @@ nsContextMenu.prototype = {
canvas.height = video.videoHeight;
var ctxDraw = canvas.getContext("2d");
ctxDraw.drawImage(video, 0, 0);
- saveImageURL(canvas.toDataURL("image/jpeg", ""), name, "SaveImageTitle", true, false, document.documentURIObject, this.target.ownerDocument);
+ saveImageURL(canvas.toDataURL("image/jpeg", ""), name, "SaveImageTitle",
+ true, false, referrerURI, null, null, null,
+ isPrivate);
},
fullScreenVideo: function () {
@@ -1106,10 +1123,17 @@ nsContextMenu.prototype = {
}
}
- // set up a channel to do the saving
- var ioService = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
- var channel = ioService.newChannelFromURI(makeURI(linkURL));
+ // setting up a new channel for 'right click - save link as ...'
+ // ideally we should use:
+ // * doc - as the loadingNode, and/or
+ // * this.principal - as the loadingPrincipal
+ // for now lets use systemPrincipal to bypass mixedContentBlocker
+ // checks after redirects, see bug: 1136055
+ var channel = NetUtil.newChannel({
+ uri: makeURI(linkURL),
+ loadUsingSystemPrincipal: true
+ });
+
if (linkDownload)
channel.contentDispositionFilename = linkDownload;
if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
@@ -1142,7 +1166,7 @@ nsContextMenu.prototype = {
timer.TYPE_ONE_SHOT);
// kick off the channel with our proxy object as the listener
- channel.asyncOpen(new saveAsListener(), null);
+ channel.asyncOpen2(new saveAsListener());
},
// Save URL of clicked-on link.
@@ -1174,6 +1198,8 @@ nsContextMenu.prototype = {
// Save URL of the clicked upon image, video, or audio.
saveMedia: function() {
var doc = this.target.ownerDocument;
+ let referrerURI = doc.documentURIObject;
+ let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
if (this.onCanvas) {
// Bypass cache, since it's a blob: URL.
var target = this.target;
@@ -1189,14 +1215,16 @@ nsContextMenu.prototype = {
resolve(win.URL.createObjectURL(blob));
})
}}).then(function (blobURL) {
- saveImageURL(blobURL, "canvas.png", "SaveImageTitle", true,
- false, doc.documentURIObject, doc);
+ saveImageURL(blobURL, "canvas.png", "SaveImageTitle",
+ true, false, referrerURI, null, null, null,
+ isPrivate);
}, Components.utils.reportError);
}
} else if (this.onImage) {
urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
- saveImageURL(this.mediaURL, null, "SaveImageTitle", false,
- false, doc.documentURIObject, doc);
+ saveImageURL(this.mediaURL, null, "SaveImageTitle",
+ false, false, referrerURI, doc, null, null,
+ isPrivate);
} else if (this.onVideo || this.onAudio) {
urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
var dialogTitle = this.onVideo ? "SaveVideoTitle" : "SaveAudioTitle";
@@ -1373,9 +1401,8 @@ nsContextMenu.prototype = {
isDisabledForEvents: function(aNode) {
let ownerDoc = aNode.ownerDocument;
- return
- ownerDoc.defaultView &&
- ownerDoc.defaultView
+ return ownerDoc.defaultView &&
+ ownerDoc.defaultView
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.isNodeDisabledForEvents(aNode);
diff --git a/application/palemoon/base/content/openLocation.js b/application/palemoon/base/content/openLocation.js
index 5b731c7e8..1a10334c7 100644
--- a/application/palemoon/base/content/openLocation.js
+++ b/application/palemoon/base/content/openLocation.js
@@ -7,7 +7,7 @@
var browser;
var dialog = {};
var pref = null;
-let openLocationModule = {};
+var openLocationModule = {};
try {
pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
@@ -16,7 +16,7 @@ try {
}
Components.utils.import("resource:///modules/openLocationLastURL.jsm", openLocationModule);
-let gOpenLocationLastURL = new openLocationModule.OpenLocationLastURL(window.opener);
+var gOpenLocationLastURL = new openLocationModule.OpenLocationLastURL(window.opener);
function onLoad()
{
@@ -61,45 +61,52 @@ function doEnabling()
function open()
{
- var url;
- var postData = {};
- var mayInheritPrincipal = {value: false};
- if (browser)
- url = browser.getShortcutOrURI(dialog.input.value, postData, mayInheritPrincipal);
- else
- url = dialog.input.value;
+ getShortcutOrURIAndPostData(dialog.input.value).then(data => {
+ let url;
+ let postData = null;
+ let mayInheritPrincipal = false;
+
+ if (browser) {
+ url = data.url;
+ postData = data.postData;
+ mayInheritPrincipal = data.mayInheritPrincipal;
+ } else {
+ url = dialog.input.value;
+ }
- try {
- // Whichever target we use for the load, we allow third-party services to
- // fixup the URI
- switch (dialog.openWhereList.value) {
- case "0":
- var webNav = Components.interfaces.nsIWebNavigation;
- var flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
- webNav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
- if (!mayInheritPrincipal.value)
- flags |= webNav.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
- browser.gBrowser.loadURIWithFlags(url, flags, null, null, postData.value);
- break;
- case "1":
- window.opener.delayedOpenWindow(getBrowserURL(), "all,dialog=no",
- url, postData.value, null, null, true);
- break;
- case "3":
- browser.delayedOpenTab(url, null, null, postData.value, true);
- break;
+ try {
+ // Whichever target we use for the load, we allow third-party services to
+ // fixup the URI
+ switch (dialog.openWhereList.value) {
+ case "0":
+ var webNav = Components.interfaces.nsIWebNavigation;
+ var flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
+ webNav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
+ if (!mayInheritPrincipal)
+ flags |= webNav.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
+ browser.gBrowser.loadURIWithFlags(url, flags, null, null, postData);
+ break;
+ case "1":
+ window.opener.delayedOpenWindow(getBrowserURL(), "all,dialog=no",
+ url, postData, null, null, true);
+ break;
+ case "3":
+ browser.delayedOpenTab(url, null, null, postData, true);
+ break;
+ }
+ }
+ catch(exception) {
}
- }
- catch(exception) {
- }
- if (pref) {
- gOpenLocationLastURL.value = dialog.input.value;
- pref.setIntPref("general.open_location.last_window_choice", dialog.openWhereList.value);
- }
+ if (pref) {
+ gOpenLocationLastURL.value = dialog.input.value;
+ pref.setIntPref("general.open_location.last_window_choice", dialog.openWhereList.value);
+ }
+
+ // Delay closing slightly to avoid timing bug on Linux.
+ window.close();
+ });
- // Delay closing slightly to avoid timing bug on Linux.
- window.close();
return false;
}
diff --git a/application/palemoon/base/content/padlock.js b/application/palemoon/base/content/padlock.js
index 53477fd17..9c29524ce 100644
--- a/application/palemoon/base/content/padlock.js
+++ b/application/palemoon/base/content/padlock.js
@@ -1,6 +1,6 @@
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cu = Components.utils;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var padlock_PadLock =
diff --git a/application/palemoon/base/content/pageinfo/pageInfo.js b/application/palemoon/base/content/pageinfo/pageInfo.js
index ba93ee817..6b02bc370 100644
--- a/application/palemoon/base/content/pageinfo/pageInfo.js
+++ b/application/palemoon/base/content/pageinfo/pageInfo.js
@@ -359,7 +359,7 @@ function loadPageInfo()
makeTabs(gDocument, gWindow);
initFeedTab();
- onLoadPermission();
+ onLoadPermission(gDocument.nodePrincipal);
/* Call registered overlay init functions */
onLoadRegistry.forEach(function(func) { func(); });
@@ -857,7 +857,7 @@ function onBlockImage()
if (checkbox.checked)
permissionManager.add(uri, "image", nsIPermissionManager.DENY_ACTION);
else
- permissionManager.remove(uri.host, "image");
+ permissionManager.remove(uri, "image");
}
function onImageSelect()
@@ -1112,8 +1112,9 @@ var imagePermissionObserver = {
var row = getSelectedRow(imageTree);
var item = gImageView.data[row][COL_IMAGE_NODE];
var url = gImageView.data[row][COL_IMAGE_ADDRESS];
- if (makeURI(url).host == permission.host)
+ if (permission.matchesURI(makeURI(url), true)) {
makeBlockImage(url);
+ }
}
}
}
diff --git a/application/palemoon/base/content/pageinfo/permissions.js b/application/palemoon/base/content/pageinfo/permissions.js
index 7a0006b61..68261ce6e 100644
--- a/application/palemoon/base/content/pageinfo/permissions.js
+++ b/application/palemoon/base/content/pageinfo/permissions.js
@@ -12,9 +12,10 @@ const IMAGE_DENY = 2;
const COOKIE_DENY = 2;
const COOKIE_SESSION = 2;
-const nsIQuotaManager = Components.interfaces.nsIQuotaManager;
+const nsIQuotaManagerService = Components.interfaces.nsIQuotaManagerService;
var gPermURI;
+var gPermPrincipal;
var gPrefs;
var gUsageRequest;
@@ -97,7 +98,7 @@ var permissionObserver = {
if (aTopic == "perm-changed") {
var permission = aSubject.QueryInterface(
Components.interfaces.nsIPermission);
- if (permission.host == gPermURI.host) {
+ if (permission.matchesURI(gPermURI, true)) {
if (permission.type in gPermObj)
initRow(permission.type);
else if (permission.type.startsWith("plugin"))
@@ -107,7 +108,7 @@ var permissionObserver = {
}
};
-function onLoadPermission()
+function onLoadPermission(principal)
{
gPrefs = Components.classes[PREFERENCES_CONTRACTID]
.getService(Components.interfaces.nsIPrefBranch);
@@ -116,8 +117,9 @@ function onLoadPermission()
var permTab = document.getElementById("permTab");
if (/^https?$/.test(uri.scheme)) {
gPermURI = uri;
+ gPermPrincipal = principal;
var hostText = document.getElementById("hostText");
- hostText.value = gPermURI.host;
+ hostText.value = gPermURI.prePath;
for (var i in gPermObj)
initRow(i);
@@ -187,7 +189,7 @@ function onCheckboxClick(aPartId)
var command = document.getElementById("cmd_" + aPartId + "Toggle");
var checkbox = document.getElementById(aPartId + "Def");
if (checkbox.checked) {
- permissionManager.remove(gPermURI.host, aPartId);
+ permissionManager.remove(gPermURI, aPartId);
command.setAttribute("disabled", "true");
var perm = gPermObj[aPartId]();
setRadioState(aPartId, perm);
@@ -211,7 +213,7 @@ function onRadioClick(aPartId)
var id = radioGroup.selectedItem.id;
var permission = id.split('#')[1];
if (permission == UNKNOWN) {
- permissionManager.remove(gPermURI.host, aPartId);
+ permissionManager.remove(gPermURI, aPartId);
} else {
permissionManager.add(gPermURI, aPartId, permission);
}
@@ -230,10 +232,13 @@ function initIndexedDBRow()
row.appendChild(extras);
- var quotaManager = Components.classes["@mozilla.org/dom/quota/manager;1"]
- .getService(nsIQuotaManager);
+ var quotaManagerService =
+ Components.classes["@mozilla.org/dom/quota-manager-service;1"]
+ .getService(nsIQuotaManagerService);
+
gUsageRequest =
- quotaManager.getUsageForURI(gPermURI, onIndexedDBUsageCallback);
+ quotaManagerService.getUsageForPrincipal(gPermPrincipal,
+ onIndexedDBUsageCallback);
var status = document.getElementById("indexedDBStatus");
var button = document.getElementById("indexedDBClear");
@@ -245,22 +250,24 @@ function initIndexedDBRow()
function onIndexedDBClear()
{
- Components.classes["@mozilla.org/dom/quota/manager;1"]
- .getService(nsIQuotaManager)
- .clearStoragesForURI(gPermURI);
+ Components.classes["@mozilla.org/dom/quota-manager-service;1"]
+ .getService(nsIQuotaManagerService)
+ .clearStoragesForPrincipal(gPermPrincipal);
var permissionManager = Components.classes[PERMISSION_CONTRACTID]
.getService(nsIPermissionManager);
- permissionManager.remove(gPermURI.host, "indexedDB");
+ permissionManager.remove(gPermURI, "indexedDB");
initIndexedDBRow();
}
-function onIndexedDBUsageCallback(uri, usage, fileUsage)
+function onIndexedDBUsageCallback(request)
{
+ let uri = request.principal.URI;
if (!uri.equals(gPermURI)) {
- throw new Error("Callback received for bad URI: " + uri);
+ throw new Error("Callback received for bad URI: " + uri.spec);
}
+ let usage = request.result.usage;
if (usage) {
if (!("DownloadUtils" in window)) {
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
@@ -355,20 +362,33 @@ function initPluginsRow() {
}
}
- let entries = [
- {
+ // Tycho:
+ // let entries = [
+ // {
+ // "permission": item[0],
+ // "obj": item[1],
+ // }
+ // for (item of permissionMap)
+ // ];
+ let entries = [];
+ for (let item of permissionMap) {
+ entries.push({
"permission": item[0],
- "obj": item[1],
- }
- for (item of permissionMap)
- ];
+ "obj": item[1]
+ });
+ }
entries.sort(function(a, b) {
return ((a.obj.name < b.obj.name) ? -1 : (a.obj.name == b.obj.name ? 0 : 1));
});
- let permissionEntries = [
- fillInPluginPermissionTemplate(p.permission, p.obj) for (p of entries)
- ];
+ // Tycho:
+ // let permissionEntries = [
+ // fillInPluginPermissionTemplate(p.permission, p.obj) for (p of entries)
+ // ];
+ let permissionEntries = [];
+ entries.forEach(function (p) {
+ permissionEntries.push(fillInPluginPermissionTemplate(p.permission, p.obj));
+ });
let permPluginsRow = document.getElementById("permPluginsRow");
clearPluginPermissionTemplate();
diff --git a/application/palemoon/base/content/popup-notifications.inc b/application/palemoon/base/content/popup-notifications.inc
index 04f4cb5b7..31a72b489 100644
--- a/application/palemoon/base/content/popup-notifications.inc
+++ b/application/palemoon/base/content/popup-notifications.inc
@@ -2,7 +2,6 @@
<panel id="notification-popup"
type="arrow"
- footertype="promobox"
position="after_start"
hidden="true"
orient="vertical"
@@ -54,7 +53,7 @@
</hbox>
</panel>
-
+#ifdef MOZ_WEBRTC
<popupnotification id="webRTC-shareDevices-notification" hidden="true">
<popupnotificationcontent id="webRTC-selectCamera" orient="vertical">
<separator class="thin"/>
@@ -75,7 +74,7 @@
</menulist>
</popupnotificationcontent>
</popupnotification>
-
+#endif
<popupnotification id="servicesInstall-notification" hidden="true">
<popupnotificationcontent orient="vertical" align="start">
<!-- XXX bug 974146, tests are looking for this, can't remove yet. -->
@@ -89,6 +88,14 @@
</popupnotificationcontent>
</popupnotification>
+ <popupnotification id="password-notification" hidden="true">
+ <popupnotificationcontent orient="vertical">
+ <textbox id="password-notification-username"/>
+ <textbox id="password-notification-password" type="password" show-content=""/>
+ <checkbox id="password-notification-visibilityToggle" hidden="true"/>
+ </popupnotificationcontent>
+ </popupnotification>
+
<popupnotification id="mixed-content-blocked-notification" hidden="true">
<popupnotificationcontent orient="vertical" align="start">
<separator/>
diff --git a/application/palemoon/base/content/sanitize.js b/application/palemoon/base/content/sanitize.js
index 89843c86d..f2eb24a55 100644
--- a/application/palemoon/base/content/sanitize.js
+++ b/application/palemoon/base/content/sanitize.js
@@ -15,7 +15,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
- "resource://gre/modules/devtools/Console.jsm");
+ "resource://gre/modules/Console.jsm");
function Sanitizer() {}
Sanitizer.prototype = {
@@ -148,7 +148,8 @@ Sanitizer.prototype = {
if (cookie.creationTime > this.range[0])
// This cookie was created after our cutoff, clear it
- cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
+ cookieMgr.remove(cookie.host, cookie.name, cookie.path,
+ false, cookie.originAttributes);
}
}
else {
@@ -213,10 +214,16 @@ Sanitizer.prototype = {
history: {
clear: function ()
{
- if (this.range)
- PlacesUtils.history.removeVisitsByTimeframe(this.range[0], this.range[1]);
- else
- PlacesUtils.history.removeAllPages();
+ if (this.range) {
+ PlacesUtils.history.removeVisitsByFilter({
+ beginDate: new Date(this.range[0] / 1000),
+ endDate: new Date(this.range[1] / 1000)
+ }).catch(Components.utils.reportError);;
+ } else {
+ // Remove everything.
+ PlacesUtils.history.clear()
+ .catch(Components.utils.reportError);
+ }
try {
var os = Components.classes["@mozilla.org/observer-service;1"]
diff --git a/application/palemoon/base/content/sync/aboutSyncTabs.js b/application/palemoon/base/content/sync/aboutSyncTabs.js
index 535c43e56..bc624a459 100644
--- a/application/palemoon/base/content/sync/aboutSyncTabs.js
+++ b/application/palemoon/base/content/sync/aboutSyncTabs.js
@@ -11,7 +11,7 @@ Cu.import("resource://gre/modules/PlacesUtils.jsm", this);
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-let RemoteTabViewer = {
+var RemoteTabViewer = {
_tabsList: null,
init: function () {
diff --git a/application/palemoon/base/content/sync/addDevice.js b/application/palemoon/base/content/sync/addDevice.js
index 556e75768..40862a791 100644
--- a/application/palemoon/base/content/sync/addDevice.js
+++ b/application/palemoon/base/content/sync/addDevice.js
@@ -15,7 +15,7 @@ const ADD_DEVICE_PAGE = 0;
const SYNC_KEY_PAGE = 1;
const DEVICE_CONNECTED_PAGE = 2;
-let gSyncAddDevice = {
+var gSyncAddDevice = {
init: function init() {
this.pin1.setAttribute("maxlength", PIN_PART_LENGTH);
diff --git a/application/palemoon/base/content/sync/genericChange.js b/application/palemoon/base/content/sync/genericChange.js
index 6d1ce9485..0c6dc145e 100644
--- a/application/palemoon/base/content/sync/genericChange.js
+++ b/application/palemoon/base/content/sync/genericChange.js
@@ -8,7 +8,7 @@ const Cc = Components.classes;
Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://gre/modules/Services.jsm");
-let Change = {
+var Change = {
_dialog: null,
_dialogType: null,
_status: null,
diff --git a/application/palemoon/base/content/sync/progress.js b/application/palemoon/base/content/sync/progress.js
index 2063f612a..101160fa8 100644
--- a/application/palemoon/base/content/sync/progress.js
+++ b/application/palemoon/base/content/sync/progress.js
@@ -6,8 +6,8 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://services-sync/main.js");
-let gProgressBar;
-let gCounter = 0;
+var gProgressBar;
+var gCounter = 0;
function onLoad(event) {
Services.obs.addObserver(onEngineSync, "weave:engine:sync:finish", false);
diff --git a/application/palemoon/base/content/sync/quota.js b/application/palemoon/base/content/sync/quota.js
index 7117a2ddf..454052754 100644
--- a/application/palemoon/base/content/sync/quota.js
+++ b/application/palemoon/base/content/sync/quota.js
@@ -10,7 +10,7 @@ const Cu = Components.utils;
Cu.import("resource://services-sync/main.js");
Cu.import("resource://gre/modules/DownloadUtils.jsm");
-let gSyncQuota = {
+var gSyncQuota = {
init: function init() {
this.bundle = document.getElementById("quotaStrings");
@@ -86,7 +86,7 @@ let gSyncQuota = {
};
-let gUsageTreeView = {
+var gUsageTreeView = {
_ignored: {keys: true,
meta: true,
diff --git a/application/palemoon/base/content/sync/utils.js b/application/palemoon/base/content/sync/utils.js
index 0c02b5bc0..d41ecf18a 100644
--- a/application/palemoon/base/content/sync/utils.js
+++ b/application/palemoon/base/content/sync/utils.js
@@ -8,7 +8,7 @@
const PERMISSIONS_RWUSR = 0x180;
// Weave should always exist before before this file gets included.
-let gSyncUtils = {
+var gSyncUtils = {
get bundle() {
delete this.bundle;
return this.bundle = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties");
diff --git a/application/palemoon/base/content/tabbrowser.xml b/application/palemoon/base/content/tabbrowser.xml
index b8d5f3e41..1b8099785 100644
--- a/application/palemoon/base/content/tabbrowser.xml
+++ b/application/palemoon/base/content/tabbrowser.xml
@@ -30,7 +30,7 @@
<xul:vbox flex="1" class="browserContainer">
<xul:stack flex="1" class="browserStack" anonid="browserStack">
<xul:browser anonid="initialBrowser" type="content-primary" message="true" disablehistory="true"
- xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup"/>
+ xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,datetimepicker"/>
</xul:stack>
</xul:vbox>
</xul:hbox>
@@ -138,19 +138,19 @@
]]></getter>
</property>
- <property name="formValidationAnchor" readonly="true">
+ <property name="popupAnchor" readonly="true">
<getter><![CDATA[
- if (this.mCurrentTab._formValidationAnchor) {
- return this.mCurrentTab._formValidationAnchor;
+ if (this.mCurrentTab._popupAnchor) {
+ return this.mCurrentTab._popupAnchor;
}
let stack = this.mCurrentBrowser.parentNode;
- // Create an anchor for the form validation popup
+ // Create an anchor for the popup
const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
- let formValidationAnchor = document.createElementNS(NS_XUL, "hbox");
- formValidationAnchor.className = "form-validation-anchor";
- formValidationAnchor.hidden = true;
- stack.appendChild(formValidationAnchor);
- return this.mCurrentTab._formValidationAnchor = formValidationAnchor;
+ let popupAnchor = document.createElementNS(NS_XUL, "hbox");
+ popupAnchor.className = "popup-anchor";
+ popupAnchor.hidden = true;
+ stack.appendChild(popupAnchor);
+ return this.mCurrentTab._popupAnchor = popupAnchor;
]]></getter>
</property>
@@ -302,6 +302,16 @@
</body>
</method>
+ <method name="getBrowserForContentWindow">
+ <parameter name="aWindow"/>
+ <body>
+ <![CDATA[
+ var tab = this._getTabForContentWindow(aWindow);
+ return tab ? tab.linkedBrowser : null;
+ ]]>
+ </body>
+ </method>
+
<method name="getBrowserForOuterWindowID">
<parameter name="aID"/>
<body>
@@ -560,6 +570,12 @@
const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
const nsIChannel = Components.interfaces.nsIChannel;
+ let location, originalLocation;
+ try {
+ aRequest.QueryInterface(nsIChannel)
+ location = aRequest.URI;
+ originalLocation = aRequest.originalURI;
+ } catch (ex) {}
if (aStateFlags & nsIWebProgressListener.STATE_START) {
this.mRequestCount++;
@@ -578,16 +594,8 @@
if (aStateFlags & nsIWebProgressListener.STATE_START &&
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
- // It's okay to clear what the user typed when we start
- // loading a document. If the user types, this counter gets
- // set to zero, if the document load ends without an
- // onLocationChange, this counter gets decremented
- // (so we keep it while switching tabs after failed loads)
- // We need to add 2 because loadURIWithFlags may have
- // cancelled a pending load which would have cleared
- // its anchor scroll detection temporary increment.
if (aWebProgress.isTopLevel)
- this.mBrowser.userTypedClear += 2;
+ this.mBrowser.urlbarChangeTracker.startedLoad();
if (this._shouldShowProgress(aRequest)) {
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
@@ -615,8 +623,8 @@
this.mTab.removeAttribute("progress");
if (aWebProgress.isTopLevel) {
- if (!Components.isSuccessCode(aStatus) &&
- !isTabEmpty(this.mTab)) {
+ let isSuccessful = Components.isSuccessCode(aStatus);
+ if (!isSuccessful && !isTabEmpty(this.mTab)) {
// Restore the current document's location in case the
// request was stopped (possibly from a content script)
// before the location changed.
@@ -625,14 +633,8 @@
if (this.mTab.selected && gURLBar)
URLBarSetURI();
- } else {
- // The document is done loading, we no longer want the
- // value cleared.
-
- if (this.mBrowser.userTypedClear > 1)
- this.mBrowser.userTypedClear -= 2;
- else if (this.mBrowser.userTypedClear > 0)
- this.mBrowser.userTypedClear--;
+ } else if (isSuccessful) {
+ this.mBrowser.urlbarChangeTracker.finishedLoad();
}
if (!this.mBrowser.mIconURL)
@@ -642,8 +644,6 @@
if (this.mBlank)
this.mBlank = false;
- var location = aRequest.QueryInterface(nsIChannel).URI;
-
// For keyword URIs clear the user typed value since they will be changed into real URIs
if (location.scheme == "keyword")
this.mBrowser.userTypedValue = null;
@@ -686,13 +686,12 @@
let topLevel = aWebProgress.isTopLevel;
if (topLevel) {
- // If userTypedClear > 0, the document loaded correctly and we should be
- // clearing the user typed value. We also need to clear the typed value
+ // We need to clear the typed value
// if the document failed to load, to make sure the urlbar reflects the
// failed URI (particularly for SSL errors). However, don't clear the value
// if the error page's URI is about:blank, because that causes complete
// loss of urlbar contents for invalid URI errors (see bug 867957).
- if (this.mBrowser.userTypedClear > 0 ||
+ if (this.mBrowser.didStartLoadSinceLastUserTyping() ||
((aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) &&
aLocation.spec != "about:blank"))
this.mBrowser.userTypedValue = null;
@@ -707,7 +706,8 @@
let autocomplete = this.mTabBrowser._placesAutocomplete;
if (this.mBrowser.registeredOpenURI) {
- autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI);
+ autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI,
+ this.mBrowser.getAttribute("usercontextid") || 0);
delete this.mBrowser.registeredOpenURI;
}
// Tabs in private windows aren't registered as "Open" so
@@ -715,7 +715,8 @@
if (!isBlankPageURL(aLocation.spec) &&
(!PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.permanentPrivateBrowsing)) {
- autocomplete.registerOpenPage(aLocation);
+ autocomplete.registerOpenPage(aLocation,
+ this.mBrowser.getAttribute("usercontextid") || 0);
this.mBrowser.registeredOpenURI = aLocation;
}
}
@@ -726,8 +727,10 @@
aFlags]);
}
- if (topLevel)
+ if (topLevel) {
this.mBrowser.lastURI = aLocation;
+ this.mBrowser.lastLocationChange = Date.now();
+ }
},
onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
@@ -766,19 +769,28 @@
<method name="setIcon">
<parameter name="aTab"/>
<parameter name="aURI"/>
+ <parameter name="aLoadingPrincipal"/>
<body>
<![CDATA[
- var browser = this.getBrowserForTab(aTab);
+ let browser = this.getBrowserForTab(aTab);
browser.mIconURL = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
if (aURI && this.mFaviconService) {
- if (!(aURI instanceof Ci.nsIURI))
+ if (!(aURI instanceof Ci.nsIURI)) {
aURI = makeURI(aURI);
- this.mFaviconService.setAndFetchFaviconForPage(browser.currentURI,
- aURI, false,
- PrivateBrowsingUtils.isWindowPrivate(window) ?
- this.mFaviconService.FAVICON_LOAD_PRIVATE :
- this.mFaviconService.FAVICON_LOAD_NON_PRIVATE);
+ }
+ // We do not serialize the principal from within SessionStore.jsm,
+ // hence if aLoadingPrincipal is null we default to the
+ // systemPrincipal which will allow the favicon to load.
+ let loadingPrincipal = aLoadingPrincipal
+ ? aLoadingPrincipal
+ : Services.scriptSecurityManager.getSystemPrincipal();
+ let loadType = PrivateBrowsingUtils.isWindowPrivate(window)
+ ? this.mFaviconService.FAVICON_LOAD_PRIVATE
+ : this.mFaviconService.FAVICON_LOAD_NON_PRIVATE;
+
+ this.mFaviconService.setAndFetchFaviconForPage(
+ browser.currentURI, aURI, false, loadType, null, loadingPrincipal);
}
let sizedIconUrl = browser.mIconURL || "";
@@ -874,7 +886,7 @@
if (!this.isFailedIcon(url))
icon = url;
}
- this.setIcon(aTab, icon);
+ this.setIcon(aTab, icon, browser.contentPrincipal);
]]>
</body>
</method>
@@ -1252,6 +1264,7 @@
<parameter name="aAllowThirdPartyFixup"/>
<body>
<![CDATA[
+ var aReferrerPolicy;
var aFromExternal;
var aRelatedToCurrent;
if (arguments.length == 2 &&
@@ -1259,6 +1272,7 @@
!(arguments[1] instanceof Ci.nsIURI)) {
let params = arguments[1];
aReferrerURI = params.referrerURI;
+ aReferrerPolicy = params.referrerPolicy;
aCharset = params.charset;
aPostData = params.postData;
aLoadInBackground = params.inBackground;
@@ -1272,6 +1286,7 @@
var owner = bgLoad ? null : this.selectedTab;
var tab = this.addTab(aURI, {
referrerURI: aReferrerURI,
+ referrerPolicy: aReferrerPolicy,
charset: aCharset,
postData: aPostData,
ownerTab: owner,
@@ -1291,6 +1306,24 @@
<parameter name="aLoadInBackground"/>
<parameter name="aReplace"/>
<body><![CDATA[
+ let aAllowThirdPartyFixup;
+ let aTargetTab;
+ let aNewIndex = -1;
+ let aPostDatas = [];
+ let aUserContextId;
+ if (arguments.length == 2 &&
+ typeof arguments[1] == "object") {
+ let params = arguments[1];
+ aLoadInBackground = params.inBackground;
+ aReplace = params.replace;
+ aAllowThirdPartyFixup = params.allowThirdPartyFixup;
+ aTargetTab = params.targetTab;
+ aNewIndex = typeof params.newIndex === "number" ?
+ params.newIndex : aNewIndex;
+ aPostDatas = params.postDatas || aPostDatas;
+ aUserContextId = params.userContextId;
+ }
+
if (!aURIs.length)
return;
@@ -1308,22 +1341,53 @@
var multiple = aURIs.length > 1;
var owner = multiple || aLoadInBackground ? null : this.selectedTab;
var firstTabAdded = null;
+ var targetTabIndex = -1;
if (aReplace) {
+ let browser;
+ if (aTargetTab) {
+ browser = this.getBrowserForTab(aTargetTab);
+ targetTabIndex = aTargetTab._tPos;
+ } else {
+ browser = this.mCurrentBrowser;
+ targetTabIndex = this.tabContainer.selectedIndex;
+ }
+ let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
+ if (aAllowThirdPartyFixup) {
+ flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
+ Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
+ }
try {
- this.loadURI(aURIs[0], null, null);
+ browser.loadURIWithFlags(aURIs[0], {
+ flags, postData: aPostDatas[0]
+ });
} catch (e) {
// Ignore failure in case a URI is wrong, so we can continue
// opening the next ones.
}
+ } else {
+ firstTabAdded = this.addTab(aURIs[0], {
+ ownerTab: owner,
+ skipAnimation: multiple,
+ allowThirdPartyFixup: aAllowThirdPartyFixup,
+ postData: aPostDatas[0],
+ userContextId: aUserContextId
+ });
+ if (aNewIndex !== -1) {
+ this.moveTabTo(firstTabAdded, aNewIndex);
+ targetTabIndex = firstTabAdded._tPos;
+ }
}
- else
- firstTabAdded = this.addTab(aURIs[0], {ownerTab: owner, skipAnimation: multiple});
- var tabNum = this.tabContainer.selectedIndex;
+ let tabNum = targetTabIndex;
for (let i = 1; i < aURIs.length; ++i) {
- let tab = this.addTab(aURIs[i], {skipAnimation: true});
- if (aReplace)
+ let tab = this.addTab(aURIs[i], {
+ skipAnimation: true,
+ allowThirdPartyFixup: aAllowThirdPartyFixup,
+ postData: aPostDatas[i],
+ userContextId: aUserContextId
+ });
+ if (targetTabIndex !== -1)
this.moveTabTo(tab, ++tabNum);
}
@@ -1348,6 +1412,7 @@
<body>
<![CDATA[
const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ var aReferrerPolicy;
var aFromExternal;
var aRelatedToCurrent;
var aSkipAnimation;
@@ -1356,6 +1421,7 @@
!(arguments[1] instanceof Ci.nsIURI)) {
let params = arguments[1];
aReferrerURI = params.referrerURI;
+ aReferrerPolicy = params.referrerPolicy;
aCharset = params.charset;
aPostData = params.postData;
aOwner = params.ownerTab;
@@ -1430,6 +1496,10 @@
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
+ if (this.hasAttribute("datetimepicker")) {
+ b.setAttribute("datetimepicker", this.getAttribute("datetimepicker"));
+ }
+
// Create the browserStack container
var stack = document.createElementNS(NS_XUL, "stack");
stack.className = "browserStack";
@@ -1523,7 +1593,13 @@
if (aFromExternal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
try {
- b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
+ b.loadURIWithFlags(aURI, {
+ flags: flags,
+ referrerURI: aReferrerURI,
+ referrerPolicy: aReferrerPolicy,
+ charset: aCharset,
+ postData: aPostData,
+ });
} catch (ex) {
Cu.reportError(ex);
}
@@ -1566,7 +1642,7 @@
}
if (animate) {
- mozRequestAnimationFrame(function () {
+ requestAnimationFrame(function () {
this.tabContainer._handleTabTelemetryStart(t, aURI);
// kick the animation off
@@ -1865,7 +1941,8 @@
this.mTabListeners[aTab._tPos].destroy();
if (browser.registeredOpenURI && !aTabWillBeMoved) {
- this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI);
+ this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI,
+ browser.getAttribute("usercontextid") || 0);
delete browser.registeredOpenURI;
}
@@ -2133,7 +2210,7 @@
// Workarounds for bug 458697
// Icon might have been set on DOMLinkAdded, don't override that.
if (!ourBrowser.mIconURL && otherBrowser.mIconURL)
- this.setIcon(aOurTab, otherBrowser.mIconURL);
+ this.setIcon(aOurTab, otherBrowser.mIconURL, otherBrowser.contentPrincipal);
var isBusy = aOtherTab.hasAttribute("busy");
if (isBusy) {
aOurTab.setAttribute("busy", "true");
@@ -2209,7 +2286,8 @@
<![CDATA[
// If the current URI is registered as open remove it from the list.
if (aOurBrowser.registeredOpenURI) {
- this._placesAutocomplete.unregisterOpenPage(aOurBrowser.registeredOpenURI);
+ this._placesAutocomplete.unregisterOpenPage(aOurBrowser.registeredOpenURI,
+ aOurBrowser.getAttribute("usercontextid") || 0);
delete aOurBrowser.registeredOpenURI;
}
@@ -2633,6 +2711,11 @@
<parameter name="aPostData"/>
<body>
<![CDATA[
+ // Note - the callee understands both:
+ // (a) loadURIWithFlags(aURI, aFlags, ...)
+ // (b) loadURIWithFlags(aURI, { flags: aFlags, ... })
+ // Forwarding it as (a) here actually supports both (a) and (b),
+ // so you can call us either way too.
return this.mCurrentBrowser.loadURIWithFlags(aURI, aFlags, aReferrerURI, aCharset, aPostData);
]]>
</body>
@@ -2716,6 +2799,9 @@
get finder() {
return this.mTabBrowser.mCurrentBrowser.finder;
},
+ destroy: function() {
+ this.finder.destroy();
+ },
addResultListener: function(aListener) {
this.mListeners.add(aListener);
this.finder.addResultListener(aListener);
@@ -2736,21 +2822,33 @@
set caseSensitive(val) {
return this.finder.caseSensitive = val;
},
- fastFind: function(aSearchString, aLinksOnly, aDrawOutline) {
- this.finder.fastFind(aSearchString, aLinksOnly, aDrawOutline);
+ set entireWord(val) {
+ return this.finder.entireWord = val;
+ },
+ get highlighter() {
+ return this.finder.highlighter;
},
- findAgain: function(aFindBackwards, aLinksOnly, aDrawOutline) {
- this.finder.findAgain(aFindBackwards, aLinksOnly, aDrawOutline);
+ get matchesCountLimit() {
+ return this.finder.matchesCountLimit;
+ },
+ fastFind: function(...args) {
+ this.finder.fastFind(...args);
+ },
+ findAgain: function(...args) {
+ this.finder.findAgain(...args);
},
setSearchStringToSelection: function() {
return this.finder.setSearchStringToSelection();
},
- highlight: function(aHighlight, aWord) {
- this.finder.highlight(aHighlight, aWord);
+ highlight: function(...args) {
+ this.finder.highlight(...args);
},
getInitialSelection: function() {
this.finder.getInitialSelection();
},
+ getActiveSelectionText: function() {
+ return this.finder.getActiveSelectionText();
+ },
enableSelection: function() {
this.finder.enableSelection();
},
@@ -2760,11 +2858,38 @@
focusContent: function() {
this.finder.focusContent();
},
+ onFindbarClose: function() {
+ this.finder.onFindbarClose();
+ },
+ onFindbarOpen: function() {
+ this.finder.onFindbarOpen();
+ },
+ onModalHighlightChange: function(...args) {
+ return this.finder.onModalHighlightChange(...args);
+ },
+ onHighlightAllChange: function(...args) {
+ return this.finder.onHighlightAllChange(...args);
+ },
keyPress: function(aEvent) {
this.finder.keyPress(aEvent);
},
- requestMatchesCount: function(aWord, aMatchLimit, aLinksOnly) {
- this.finder.requestMatchesCount(aWord, aMatchLimit, aLinksOnly);
+ requestMatchesCount: function(...args) {
+ this.finder.requestMatchesCount(...args);
+ },
+ onIteratorRangeFound: function(...args) {
+ this.finder.onIteratorRangeFound(...args);
+ },
+ onIteratorReset: function() {
+ this.finder.onIteratorReset();
+ },
+ onIteratorRestart: function(...args) {
+ this.finder.onIteratorRestart(...args);
+ },
+ onIteratorStart: function(...args) {
+ this.finder.onIteratorStart(...args);
+ },
+ onLocationChange: function(...args) {
+ this.finder.onLocationChange(...args);
}
})
]]></field>
@@ -2773,6 +2898,19 @@
onget="return this.mCurrentBrowser.docShell"
readonly="true"/>
+ <property name="messageManager"
+ readonly="true">
+ <getter>
+ <![CDATA[
+ let frameLoader = this.mCurrentBrowser.frameLoader;
+ if (!frameLoader) {
+ return null;
+ }
+ return frameLoader.messageManager;
+ ]]>
+ </getter>
+ </property>
+
<property name="webNavigation"
onget="return this.mCurrentBrowser.webNavigation"
readonly="true"/>
@@ -2789,6 +2927,10 @@
readonly="true"
onget="return this.mCurrentBrowser.contentWindow"/>
+ <property name="contentWindowAsCPOW"
+ readonly="true"
+ onget="return this.mCurrentBrowser.contentWindow;"/>
+
<property name="sessionHistory"
onget="return this.mCurrentBrowser.sessionHistory;"
readonly="true"/>
@@ -2809,6 +2951,10 @@
onget="return this.mCurrentBrowser.contentDocument;"
readonly="true"/>
+ <property name="contentDocumentAsCPOW"
+ onget="return this.mCurrentBrowser.contentDocument;"
+ readonly="true"/>
+
<property name="contentTitle"
onget="return this.mCurrentBrowser.contentTitle;"
readonly="true"/>
@@ -2859,23 +3005,6 @@
}
}
- // We need to take care of FAYT-watching as long as the findbar
- // isn't initialized. The checks on aEvent are copied from
- // _shouldFastFind (see findbar.xml).
- if (!gFindBarInitialized &&
- !(aEvent.ctrlKey || aEvent.metaKey) &&
- !aEvent.defaultPrevented) {
- let charCode = aEvent.charCode;
- if (charCode) {
- let char = String.fromCharCode(charCode);
- if (char == "'" || char == "/" ||
- Services.prefs.getBoolPref("accessibility.typeaheadfind")) {
- gFindBar._onBrowserKeypress(aEvent);
- return;
- }
- }
- }
-
#ifdef XP_MACOSX
if (!aEvent.metaKey)
return;
@@ -2903,10 +3032,6 @@
]]></body>
</method>
- <property name="userTypedClear"
- onget="return this.mCurrentBrowser.userTypedClear;"
- onset="return this.mCurrentBrowser.userTypedClear = val;"/>
-
<property name="userTypedValue"
onget="return this.mCurrentBrowser.userTypedValue;"
onset="return this.mCurrentBrowser.userTypedValue = val;"/>
@@ -2950,13 +3075,31 @@
let browser = aMessage.target;
switch (aMessage.name) {
- case "DOMTitleChanged":
+ case "DOMTitleChanged": {
let tab = this.getTabForBrowser(browser);
if (!tab)
return;
let titleChanged = this.setTabTitle(tab);
if (titleChanged && !tab.selected && !tab.hasAttribute("busy"))
tab.setAttribute("titlechanged", "true");
+ break;
+ }
+ case "DOMWebNotificationClicked": {
+ let tab = this.getTabForBrowser(browser);
+ if (!tab)
+ return;
+ this.selectedTab = tab;
+ window.focus();
+ break;
+ }
+ case "Findbar:Keypress":
+ if (!gFindBarInitialized) {
+ // If the find bar for this tab is not yet alive, change that,
+ // and make sure we return the result:
+ return gFindBar.receiveMessage(aMessage);
+ }
+ break;
+
}
]]></body>
</method>
@@ -3022,6 +3165,8 @@
this._outerWindowIDBrowserMap.set(this.mCurrentBrowser.outerWindowID,
this.mCurrentBrowser);
}
+ messageManager.addMessageListener("DOMWebNotificationClicked", this);
+ messageManager.addMessageListener("Findbar:Keypress", this);
]]>
</constructor>
@@ -3055,7 +3200,8 @@
for (var i = 0; i < this.mTabListeners.length; ++i) {
let browser = this.getBrowserAtIndex(i);
if (browser.registeredOpenURI) {
- this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI);
+ this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI,
+ browser.getAttribute("usercontextid") || 0);
delete browser.registeredOpenURI;
}
browser.webProgress.removeProgressListener(this.mTabFilters[i]);
@@ -4362,40 +4508,35 @@
this.tabbrowser.updateCurrentBrowser(true);
} else {
// Pass true to disallow dropping javascript: or data: urls
- let url;
+ let links;
try {
- url = browserDragAndDrop.drop(event, { }, true);
+ links = browserDragAndDrop.dropLinks(event, true);
} catch (ex) {}
// // valid urls don't contain spaces ' '; if we have a space it isn't a valid url.
// if (!url || url.includes(" ")) //PMed
- if (!url) //FF
+ if (!links || links.length === 0) //FF
return;
- let bgLoad = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
+ let inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
if (event.shiftKey)
- bgLoad = !bgLoad;
+ inBackground = !inBackground;
- let tab = this._getDragTargetTab(event);
- if (!tab || dropEffect == "copy") {
- // We're adding a new tab.
- let newIndex = this._getDropIndex(event);
- let newTab = this.tabbrowser.loadOneTab(url, {inBackground: bgLoad, allowThirdPartyFixup: true});
- this.tabbrowser.moveTabTo(newTab, newIndex);
- } else {
- // Load in an existing tab.
- try {
- let webNav = Ci.nsIWebNavigation;
- let flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
- webNav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
- this.tabbrowser.getBrowserForTab(tab).loadURIWithFlags(url, flags);
- if (!bgLoad)
- this.selectedItem = tab;
- } catch(ex) {
- // Just ignore invalid urls
- }
- }
+ let targetTab = this._getDragTargetTab(event);
+ let userContextId = this.selectedItem
+ .getAttribute("usercontextid") || 0;
+ let replace = !(!targetTab || dropEffect == "copy");
+ let newIndex = this._getDropIndex(event);
+ let urls = links.map(link => link.url);
+ this.tabbrowser.loadTabs(urls, {
+ inBackground,
+ replace,
+ allowThirdPartyFixup: true,
+ targetTab,
+ newIndex,
+ userContextId,
+ });
}
if (draggedTab) {
diff --git a/application/palemoon/base/content/urlbarBindings.xml b/application/palemoon/base/content/urlbarBindings.xml
index c99819f0d..985769ec2 100644
--- a/application/palemoon/base/content/urlbarBindings.xml
+++ b/application/palemoon/base/content/urlbarBindings.xml
@@ -17,32 +17,32 @@
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
- <binding id="urlbar" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
+ <binding id="urlbar" extends="chrome://browser/content/autocomplete.xml#private-autocomplete">
<content sizetopopup="pref">
<xul:hbox anonid="textbox-container"
- class="autocomplete-textbox-container urlbar-textbox-container"
+ class="private-autocomplete-textbox-container urlbar-textbox-container"
flex="1" xbl:inherits="focused">
<children includes="image|deck|stack|box">
- <xul:image class="autocomplete-icon" allowevents="true"/>
+ <xul:image class="private-autocomplete-icon" allowevents="true"/>
</children>
<xul:hbox anonid="textbox-input-box"
class="textbox-input-box urlbar-input-box"
flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
<children/>
<html:input anonid="input"
- class="autocomplete-textbox urlbar-input textbox-input uri-element-right-align"
+ class="private-autocomplete-textbox urlbar-input textbox-input uri-element-right-align"
allowevents="true"
xbl:inherits="tooltiptext=inputtooltiptext,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
</xul:hbox>
<children includes="hbox"/>
</xul:hbox>
<xul:dropmarker anonid="historydropmarker"
- class="autocomplete-history-dropmarker urlbar-history-dropmarker"
+ class="private-autocomplete-history-dropmarker urlbar-history-dropmarker"
allowevents="true"
xbl:inherits="open,enablehistory,parentfocused=focused"/>
<xul:popupset anonid="popupset"
- class="autocomplete-result-popupset"/>
+ class="private-autocomplete-result-popupset"/>
<children includes="toolbarbutton"/>
</content>
@@ -263,6 +263,9 @@
var postData = null;
var action = this._parseActionUrl(url);
+ let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
+
+ let matchLastLocationChange = true;
if (action) {
url = action.param;
if (this.hasAttribute("actiontype")) {
@@ -275,82 +278,94 @@
}
return;
}
+ continueOperation.call(this);
}
else {
- [url, postData, mayInheritPrincipal] = this._canonizeURL(aTriggeringEvent);
- if (!url)
- return;
- }
-
- this.value = url;
- gBrowser.userTypedValue = url;
- try {
- addToUrlbarHistory(url);
- } catch (ex) {
- // Things may go wrong when adding url to session history,
- // but don't let that interfere with the loading of the url.
- Cu.reportError(ex);
+ this._canonizeURL(aTriggeringEvent, response => {
+ [url, postData, mayInheritPrincipal] = response;
+ if (url) {
+ matchLastLocationChange = (lastLocationChange ==
+ gBrowser.selectedBrowser.lastLocationChange);
+ continueOperation.call(this);
+ }
+ });
}
- function loadCurrent() {
- let webnav = Ci.nsIWebNavigation;
- let flags = webnav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
- webnav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
- // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
- // inheriting the currently loaded document's principal, unless this
- // URL is marked as safe to inherit (e.g. came from a bookmark
- // keyword).
- if (!mayInheritPrincipal)
- flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
- gBrowser.loadURIWithFlags(url, flags, null, null, postData);
- }
+ function continueOperation()
+ {
+ this.value = url;
+ gBrowser.userTypedValue = url;
+ try {
+ addToUrlbarHistory(url);
+ } catch (ex) {
+ // Things may go wrong when adding url to session history,
+ // but don't let that interfere with the loading of the url.
+ Cu.reportError(ex);
+ }
- // Focus the content area before triggering loads, since if the load
- // occurs in a new tab, we want focus to be restored to the content
- // area when the current tab is re-selected.
- gBrowser.selectedBrowser.focus();
+ function loadCurrent() {
+ let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
+ // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
+ // inheriting the currently loaded document's principal, unless this
+ // URL is marked as safe to inherit (e.g. came from a bookmark
+ // keyword).
+ if (!mayInheritPrincipal)
+ flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
+ // If the value wasn't typed, we know that we decoded the value as
+ // UTF-8 (see losslessDecodeURI)
+ if (!this.valueIsTyped)
+ flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
+ gBrowser.loadURIWithFlags(url, flags, null, null, postData);
+ }
- let isMouseEvent = aTriggeringEvent instanceof MouseEvent;
- let altEnter = !isMouseEvent && aTriggeringEvent && aTriggeringEvent.altKey;
+ // Focus the content area before triggering loads, since if the load
+ // occurs in a new tab, we want focus to be restored to the content
+ // area when the current tab is re-selected.
+ gBrowser.selectedBrowser.focus();
- if (altEnter) {
- // XXX This was added a long time ago, and I'm not sure why it is
- // necessary. Alt+Enter's default action might cause a system beep,
- // or something like that?
- aTriggeringEvent.preventDefault();
- aTriggeringEvent.stopPropagation();
- }
+ let isMouseEvent = aTriggeringEvent instanceof MouseEvent;
- // If the current tab is empty, ignore Alt+Enter (just reuse this tab)
- altEnter = altEnter && !isTabEmpty(gBrowser.selectedTab);
+ // If the current tab is empty, ignore Alt+Enter (just reuse this tab)
+ let altEnter = !isMouseEvent && aTriggeringEvent &&
+ aTriggeringEvent.altKey && !isTabEmpty(gBrowser.selectedTab);
- if (isMouseEvent || altEnter) {
- // Use the standard UI link behaviors for clicks or Alt+Enter
- let where = "tab";
- if (isMouseEvent)
- where = whereToOpenLink(aTriggeringEvent, false, false);
+ if (isMouseEvent || altEnter) {
+ // Use the standard UI link behaviors for clicks or Alt+Enter
+ let where = "tab";
+ if (isMouseEvent)
+ where = whereToOpenLink(aTriggeringEvent, false, false);
- if (where == "current") {
- loadCurrent();
+ if (where == "current") {
+ if (matchLastLocationChange) {
+ loadCurrent();
+ }
+ } else {
+ this.handleRevert();
+ let params = { allowThirdPartyFixup: true,
+ postData: postData,
+ initiatingDoc: document };
+ if (!this.valueIsTyped)
+ params.isUTF8 = true;
+ openUILinkIn(url, where, params);
+ }
} else {
- this.handleRevert();
- let params = { allowThirdPartyFixup: true,
- postData: postData,
- initiatingDoc: document };
- openUILinkIn(url, where, params);
+ if (matchLastLocationChange) {
+ loadCurrent();
+ }
}
- } else {
- loadCurrent();
}
]]></body>
</method>
<method name="_canonizeURL">
<parameter name="aTriggeringEvent"/>
+ <parameter name="aCallback"/>
<body><![CDATA[
var url = this.value;
- if (!url)
- return ["", null, false];
+ if (!url) {
+ aCallback(["", null, false]);
+ return;
+ }
// Only add the suffix when the URL bar value isn't already "URL-like",
// and only if we get a keyboard event, to match user expectations.
@@ -403,11 +418,9 @@
}
}
- var postData = {};
- var mayInheritPrincipal = { value: false };
- url = getShortcutOrURI(url, postData, mayInheritPrincipal);
-
- return [url, postData.value, mayInheritPrincipal.value];
+ getShortcutOrURIAndPostData(url).then(data => {
+ aCallback([data.url, data.postData, data.mayInheritPrincipal]);
+ });
]]></body>
</method>
@@ -442,11 +455,12 @@
<method name="onDrop">
<parameter name="aEvent"/>
<body><![CDATA[
- let url = browserDragAndDrop.drop(aEvent, { })
+ let links = browserDragAndDrop.dropLinks(aEvent);
// The URL bar automatically handles inputs with newline characters,
// so we can get away with treating text/x-moz-url flavours as text/plain.
- if (url) {
+ if (links.length > 0 && links[0].url) {
+ let url = links[0].url;
aEvent.preventDefault();
this.value = url;
SetPageProxyState("invalid");
@@ -823,7 +837,7 @@
</implementation>
</binding>
- <binding id="urlbar-rich-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup">
+ <binding id="urlbar-rich-result-popup" extends="chrome://browser/content/autocomplete.xml#private-autocomplete-rich-result-popup">
<implementation>
<field name="_maxResults">0</field>
@@ -990,9 +1004,11 @@
document.getAnonymousElementByAttribute(this, "anonid", "cancel");
</field>
<field name="DownloadUtils" readonly="true">
- let utils = {};
- Components.utils.import("resource://gre/modules/DownloadUtils.jsm", utils);
- utils.DownloadUtils;
+ {
+ let utils = {};
+ Components.utils.import("resource://gre/modules/DownloadUtils.jsm", utils);
+ utils.DownloadUtils;
+ }
</field>
<method name="destroy">
@@ -1354,8 +1370,8 @@
return;
}
- let host = gPluginHandler._getHostFromPrincipal(this.notification.browser.contentWindow.document.nodePrincipal);
- this._setupDescription("pluginActivateMultiple.message", null, host);
+ let prePath = this.notification.browser.contentWindow.document.nodePrincipal.URI.prePath;
+ this._setupDescription("pluginActivateMultiple.message", null, prePath);
var showBox = document.getAnonymousElementByAttribute(this, "anonid", "plugin-notification-showbox");
@@ -1394,7 +1410,7 @@
<method name="_setupSingleState">
<body><![CDATA[
var action = this.notification.options.centerActions[0];
- var host = action.pluginPermissionHost;
+ var prePath = action.pluginPermissionPrePath;
let label, linkLabel, linkUrl, button1, button2;
@@ -1489,7 +1505,7 @@
Cu.reportError(Error("Unexpected blocklist state"));
}
}
- this._setupDescription(label, action.pluginName, host);
+ this._setupDescription(label, action.pluginName, prePath);
this._setupLink(linkLabel, action.detailsLink);
this._primaryButton.label = gNavigatorBundle.getString(button1.label);
@@ -1510,7 +1526,7 @@
<method name="_setupDescription">
<parameter name="baseString" />
<parameter name="pluginName" /> <!-- null for the multiple-plugin case -->
- <parameter name="host" />
+ <parameter name="prePath" />
<body><![CDATA[
var bsn = this._brandShortName;
var span = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-description");
@@ -1518,17 +1534,17 @@
span.removeChild(span.lastChild);
}
- var args = ["__host__", this._brandShortName];
+ var args = ["__prepath__", this._brandShortName];
if (pluginName) {
args.unshift(pluginName);
}
var bases = gNavigatorBundle.getFormattedString(baseString, args).
- split("__host__", 2);
+ split("__prepath__", 2);
span.appendChild(document.createTextNode(bases[0]));
- var hostSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "em");
- hostSpan.appendChild(document.createTextNode(host));
- span.appendChild(hostSpan);
+ var prePathSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "em");
+ prePathSpan.appendChild(document.createTextNode(prePath));
+ span.appendChild(prePathSpan);
span.appendChild(document.createTextNode(bases[1] + " "));
]]></body>
</method>
@@ -1764,203 +1780,14 @@
</implementation>
</binding>
- <binding id="promobox">
- <content>
- <xul:hbox class="panel-promo-box" align="start" flex="1">
- <xul:hbox align="center" flex="1">
- <xul:image class="panel-promo-icon"/>
- <xul:description anonid="promo-message" class="panel-promo-message" flex="1">
- <xul:description anonid="promo-link"
- class="plain text-link inline-link"
- onclick="document.getBindingParent(this).onLinkClick();"/>
- </xul:description>
- </xul:hbox>
- <xul:toolbarbutton class="panel-promo-closebutton close-icon"
- oncommand="document.getBindingParent(this).onCloseButtonCommand();"
- tooltiptext="&closeNotification.tooltip;"/>
- </xul:hbox>
- </content>
-
- <implementation implements="nsIDOMEventListener">
- <constructor><![CDATA[
- this._panel.addEventListener("popupshowing", this, false);
- ]]></constructor>
-
- <destructor><![CDATA[
- this._panel.removeEventListener("popupshowing", this, false);
- ]]></destructor>
-
- <field name="_panel" readonly="true"><![CDATA[
- let node = this.parentNode;
- while(node && node.localName != "panel") {
- node = node.parentNode;
- }
- node;
- ]]></field>
- <field name="_promomessage" readonly="true">
- document.getAnonymousElementByAttribute(this, "anonid", "promo-message");
- </field>
- <field name="_promolink" readonly="true">
- document.getAnonymousElementByAttribute(this, "anonid", "promo-link");
- </field>
- <field name="_brandBundle" readonly="true">
- Services.strings.createBundle("chrome://branding/locale/brand.properties");
- </field>
- <property name="_viewsLeftMap">
- <getter><![CDATA[
- let viewsLeftMap = {};
- try {
- viewsLeftMap = JSON.parse(Services.prefs.getCharPref("browser.syncPromoViewsLeftMap"));
- } catch (ex) {
- // If the old preference exists, migrate it to the new one.
- try {
- let oldPref = Services.prefs.getIntPref("browser.syncPromoViewsLeft");
- Services.prefs.clearUserPref("browser.syncPromoViewsLeft");
- viewsLeftMap.bookmarks = oldPref;
- viewsLeftMap.passwords = oldPref;
- Services.prefs.setCharPref("browser.syncPromoViewsLeftMap",
- JSON.stringify(viewsLeftMap));
- } catch (ex2) {}
- }
- return viewsLeftMap;
- ]]></getter>
- </property>
- <property name="_viewsLeft">
- <getter><![CDATA[
- let views = 5;
- let map = this._viewsLeftMap;
- if (this._notificationType in map) {
- views = map[this._notificationType];
- }
- return views;
- ]]></getter>
- <setter><![CDATA[
- let map = this._viewsLeftMap;
- map[this._notificationType] = val;
- Services.prefs.setCharPref("browser.syncPromoViewsLeftMap",
- JSON.stringify(map));
- return val;
- ]]></setter>
- </property>
- <property name="_notificationType">
- <getter><![CDATA[
- // Use the popupid attribute to identify the notification type,
- // otherwise just rely on the panel id for common arrowpanels.
- let type = this._panel.firstChild.getAttribute("popupid") ||
- this._panel.id;
- if (type.startsWith("password-"))
- return "passwords";
- if (type == "editBookmarkPanel")
- return "bookmarks";
- if (type == "addon-install-complete") {
- if (!Services.prefs.prefHasUserValue("services.sync.username"))
- return "addons";
- if (!Services.prefs.getBoolPref("services.sync.engine.addons"))
- return "addons-sync-disabled";
- }
- return null;
- ]]></getter>
- </property>
- <property name="_notificationMessage">
- <getter><![CDATA[
- return gNavigatorBundle.getFormattedString(
- "syncPromoNotification." + this._notificationType + ".description",
- [this._brandBundle.GetStringFromName("syncBrandShortName")]
- );
- ]]></getter>
- </property>
- <property name="_notificationLink">
- <getter><![CDATA[
- if (this._notificationType == "addons-sync-disabled") {
- return "https://forum.palemoon.org/viewforum.php?f=52";
- }
- return "http://www.palemoon.org/sync/";
- ]]></getter>
- </property>
- <method name="onCloseButtonCommand">
- <body><![CDATA[
- this._viewsLeft = 0;
- this.hidden = true;
- ]]></body>
- </method>
- <method name="onLinkClick">
- <body><![CDATA[
- // Open a new selected tab and close the current panel.
- gBrowser.loadOneTab(this._promolink.getAttribute("href"),
- { inBackground: false });
- this._panel.hidePopup();
- ]]></body>
- </method>
- <method name="handleEvent">
- <parameter name="event"/>
- <body><![CDATA[
- if (event.type != "popupshowing" || event.target != this._panel)
- return;
-
- // A previous notification may have unhidden this.
- this.hidden = true;
-
- // Only handle supported notification panels.
- if (!this._notificationType) {
- return;
- }
-
- let viewsLeft = this._viewsLeft;
- if (viewsLeft) {
- // XXX: Short-circuit this for now.
- // TO-DO: Clean up this code for sync promotion
- this._viewsLeft = 0;
- viewsLeft = 0;
- return;
- // XXX
-
- if (Services.prefs.prefHasUserValue("services.sync.username") &&
- this._notificationType != "addons-sync-disabled") {
- // If the user has already setup Sync, don't show the notification.
- this._viewsLeft = 0;
- // Be sure to hide the panel, in case it was visible and the user
- // decided to setup Sync after noticing it.
- viewsLeft = 0;
- // The panel is still hidden, just bail out.
- return;
- }
- else {
- this._viewsLeft = viewsLeft - 1;
- }
-
- this._promolink.setAttribute("href", this._notificationLink);
- this._promolink.value = gNavigatorBundle.getString("syncPromoNotification.learnMoreLinkText");
-
- this.hidden = false;
-
- // HACK: The description element doesn't wrap correctly in panels,
- // thus set a width on it, based on the available space, before
- // setting its textContent. Then set its height as well, to
- // fix wrong height calculation on Linux (bug 659578).
- this._panel.addEventListener("popupshown", function panelShown() {
- this._panel.removeEventListener("popupshown", panelShown, true);
- // Previous popupShown events may close the panel or change
- // its contents, so ensure this is still valid.
- if (this._panel.state != "open" || !this._notificationType)
- return;
- this._promomessage.width = this._promomessage.getBoundingClientRect().width;
- this._promomessage.firstChild.textContent = this._notificationMessage;
- this._promomessage.height = this._promomessage.getBoundingClientRect().height;
- }.bind(this), true);
- }
- ]]></body>
- </method>
- </implementation>
- </binding>
-
<binding id="toolbarbutton-badged" display="xul:button"
extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
<content>
<children includes="observes|template|menupopup|panel|tooltip"/>
- <xul:hbox class="toolbarbutton-badge-container" align="start" pack="end" flex="1">
- <xul:hbox class="toolbarbutton-badge" xbl:inherits="badge"/>
+ <xul:stack class="toolbarbutton-badge-stack">
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
- </xul:hbox>
+ <xul:label class="toolbarbutton-badge" xbl:inherits="value=badge" top="0" end="0"/>
+ </xul:stack>
<xul:label class="toolbarbutton-text" crop="right" flex="1"
xbl:inherits="value=label,accesskey,crop"/>
</content>
diff --git a/application/palemoon/base/content/utilityOverlay.js b/application/palemoon/base/content/utilityOverlay.js
index b1e78d6a9..9763891ba 100644
--- a/application/palemoon/base/content/utilityOverlay.js
+++ b/application/palemoon/base/content/utilityOverlay.js
@@ -104,7 +104,8 @@ function openUILink(url, event, aIgnoreButton, aIgnoreAlt, aAllowThirdPartyFixup
allowThirdPartyFixup: aAllowThirdPartyFixup,
postData: aPostData,
referrerURI: aReferrerURI,
- initiatingDoc: event ? event.target.ownerDocument : null
+ referrerPolicy: Components.interfaces.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
+ initiatingDoc: event ? event.target.ownerDocument : null,
};
}
@@ -196,7 +197,8 @@ function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI
params = {
allowThirdPartyFixup: aAllowThirdPartyFixup,
postData: aPostData,
- referrerURI: aReferrerURI
+ referrerURI: aReferrerURI,
+ referrerPolicy: Components.interfaces.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
};
}
@@ -205,16 +207,22 @@ function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI
openLinkIn(url, where, params);
}
+/* eslint-disable complexity */
function openLinkIn(url, where, params) {
if (!where || !url)
return;
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
var aFromChrome = params.fromChrome;
var aAllowThirdPartyFixup = params.allowThirdPartyFixup;
var aPostData = params.postData;
var aCharset = params.charset;
var aReferrerURI = params.referrerURI;
+ var aReferrerPolicy = ('referrerPolicy' in params ?
+ params.referrerPolicy : Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT);
var aRelatedToCurrent = params.relatedToCurrent;
+ var aForceAllowDataURI = params.forceAllowDataURI;
var aInBackground = params.inBackground;
var aDisallowInheritPrincipal = params.disallowInheritPrincipal;
var aInitiatingDoc = params.initiatingDoc;
@@ -227,11 +235,10 @@ function openLinkIn(url, where, params) {
"where == 'save' but without initiatingDoc. See bug 814264.");
return;
}
+ // TODO(1073187): propagate referrerPolicy.
saveURL(url, null, null, true, null, aReferrerURI, aInitiatingDoc);
return;
}
- const Cc = Components.classes;
- const Ci = Components.interfaces;
var w = getTopWin();
if ((where == "tab" || where == "tabshifted") &&
@@ -241,6 +248,7 @@ function openLinkIn(url, where, params) {
}
if (!w || where == "window") {
+ // This propagates to window.arguments.
// Strip referrer data when opening a new private window, to prevent
// regular browsing data from leaking into it.
if (aIsPrivate) {
@@ -265,12 +273,23 @@ function openLinkIn(url, where, params) {
createInstance(Ci.nsISupportsPRBool);
allowThirdPartyFixupSupports.data = aAllowThirdPartyFixup;
+ var referrerURISupports = null;
+ if (aReferrerURI && sendReferrerURI) {
+ referrerURISupports = Cc["@mozilla.org/supports-string;1"].
+ createInstance(Ci.nsISupportsString);
+ referrerURISupports.data = aReferrerURI.spec;
+ }
+
+ var referrerPolicySupports = Cc["@mozilla.org/supports-PRUint32;1"].
+ createInstance(Ci.nsISupportsPRUint32);
+ referrerPolicySupports.data = aReferrerPolicy;
+
sa.AppendElement(wuri);
sa.AppendElement(charset);
- if (sendReferrerURI)
- sa.AppendElement(aReferrerURI);
+ sa.AppendElement(referrerURISupports);
sa.AppendElement(aPostData);
sa.AppendElement(allowThirdPartyFixupSupports);
+ sa.AppendElement(referrerPolicySupports);
let features = "chrome,dialog=no,all";
if (aIsPrivate) {
@@ -315,7 +334,15 @@ function openLinkIn(url, where, params) {
}
if (aDisallowInheritPrincipal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
- w.gBrowser.loadURIWithFlags(url, flags, aReferrerURI, null, aPostData);
+ if (aForceAllowDataURI) {
+ flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
+ }
+ w.gBrowser.loadURIWithFlags(url, {
+ flags: flags,
+ referrerURI: aReferrerURI,
+ referrerPolicy: aReferrerPolicy,
+ postData: aPostData,
+ });
break;
case "tabshifted":
loadInBackground = !loadInBackground;
@@ -324,6 +351,7 @@ function openLinkIn(url, where, params) {
let browser = w.gBrowser;
browser.loadOneTab(url, {
referrerURI: aReferrerURI,
+ referrerPolicy: aReferrerPolicy,
charset: aCharset,
postData: aPostData,
inBackground: loadInBackground,
@@ -572,9 +600,11 @@ function makeURLAbsolute(aBase, aUrl)
* @param [optional] aReferrer
* If aDocument is null, then this will be used as the referrer.
* There will be no security check.
+ * @param [optional] aReferrerPolicy
+ * Referrer policy - Ci.nsIHttpChannel.REFERRER_POLICY_*.
*/
function openNewTabWith(aURL, aDocument, aPostData, aEvent,
- aAllowThirdPartyFixup, aReferrer) {
+ aAllowThirdPartyFixup, aReferrer, aReferrerPolicy) {
if (aDocument)
urlSecurityCheck(aURL, aDocument.nodePrincipal);
@@ -589,10 +619,13 @@ function openNewTabWith(aURL, aDocument, aPostData, aEvent,
{ charset: originCharset,
postData: aPostData,
allowThirdPartyFixup: aAllowThirdPartyFixup,
- referrerURI: aDocument ? aDocument.documentURIObject : aReferrer });
+ referrerURI: aDocument ? aDocument.documentURIObject : aReferrer,
+ referrerPolicy: aReferrerPolicy,
+ });
}
-function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup, aReferrer) {
+function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup,
+ aReferrer, aReferrerPolicy) {
if (aDocument)
urlSecurityCheck(aURL, aDocument.nodePrincipal);
@@ -609,7 +642,9 @@ function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup, aR
{ charset: originCharset,
postData: aPostData,
allowThirdPartyFixup: aAllowThirdPartyFixup,
- referrerURI: aDocument ? aDocument.documentURIObject : aReferrer });
+ referrerURI: aDocument ? aDocument.documentURIObject : aReferrer,
+ referrerPolicy: aReferrerPolicy,
+ });
}
/**