diff options
author | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-04-25 15:48:44 +0200 |
---|---|---|
committer | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-04-25 15:48:44 +0200 |
commit | 3ab6c7feee8126bdfc5c9ab9371db41102e12e95 (patch) | |
tree | a309c45826300b888238b6a517051fe7e71d63eb | |
parent | b18a9cf86ea25bc52d9cfea584e3aa8bfbe81f0a (diff) | |
parent | b069dabc91b7e0f5f8d161cdbe598276a21d6d68 (diff) | |
download | UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.tar UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.tar.gz UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.tar.lz UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.tar.xz UXP-3ab6c7feee8126bdfc5c9ab9371db41102e12e95.zip |
Merge branch 'master' of https://github.com/MoonchildProductions/UXP into pm_url_1
654 files changed, 17176 insertions, 17653 deletions
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/browser-places.js b/application/palemoon/base/content/browser-places.js index 5c13a43f9..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: diff --git a/application/palemoon/base/content/browser.css b/application/palemoon/base/content/browser.css index 4865cfee7..658655970 100644 --- a/application/palemoon/base/content/browser.css +++ b/application/palemoon/base/content/browser.css @@ -328,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 { @@ -690,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.xul b/application/palemoon/base/content/browser.xul index ea9c3f969..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"?> @@ -128,9 +128,11 @@ <!-- 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. --> @@ -427,7 +429,7 @@ title="&locationItem.title;" class="chromeclass-location" removable="true"> <textbox id="urlbar" flex="1" placeholder="" - type="autocomplete" + type="private-autocomplete" autocompletesearch="urlinline history" autocompletesearchparam="enable-actions" autocompletepopup="PopupAutoCompleteRichResult" diff --git a/application/palemoon/base/content/content.js b/application/palemoon/base/content/content.js index 19c8b0682..653dac3e3 100644 --- a/application/palemoon/base/content/content.js +++ b/application/palemoon/base/content/content.js @@ -60,6 +60,114 @@ 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", {}); diff --git a/application/palemoon/base/content/nsContextMenu.js b/application/palemoon/base/content/nsContextMenu.js index 1fe592b52..830c20998 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(); @@ -906,7 +909,8 @@ nsContextMenu.prototype = { Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); let doc = this.target.ownerDocument; openUILink(viewURL, e, { disallowInheritPrincipal: true, - referrerURI: doc.documentURIObject }); + referrerURI: doc.documentURIObject, + forceAllowDataURI: true }); } }, diff --git a/application/palemoon/base/content/sanitize.js b/application/palemoon/base/content/sanitize.js index fccec6c98..f2eb24a55 100644 --- a/application/palemoon/base/content/sanitize.js +++ b/application/palemoon/base/content/sanitize.js @@ -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/tabbrowser.xml b/application/palemoon/base/content/tabbrowser.xml index 49db93377..530b42527 100644 --- a/application/palemoon/base/content/tabbrowser.xml +++ b/application/palemoon/base/content/tabbrowser.xml @@ -73,7 +73,7 @@ .getService(Components.interfaces.nsIFaviconService); </field> <field name="_placesAutocomplete" readonly="true"> - Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"] + Components.classes["@mozilla.org/autocomplete/search;1?name=history"] .getService(Components.interfaces.mozIPlacesAutoComplete); </field> <field name="mTabBox" readonly="true"> diff --git a/application/palemoon/base/content/urlbarBindings.xml b/application/palemoon/base/content/urlbarBindings.xml index 07cd5380d..3d22b2de4 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> @@ -837,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> @@ -1004,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"> @@ -1782,10 +1784,10 @@ 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..86cc5cea5 100644 --- a/application/palemoon/base/content/utilityOverlay.js +++ b/application/palemoon/base/content/utilityOverlay.js @@ -205,6 +205,7 @@ function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI openLinkIn(url, where, params); } +/* eslint-disable complexity */ function openLinkIn(url, where, params) { if (!where || !url) return; @@ -215,6 +216,7 @@ function openLinkIn(url, where, params) { var aCharset = params.charset; var aReferrerURI = params.referrerURI; var aRelatedToCurrent = params.relatedToCurrent; + var aForceAllowDataURI = params.forceAllowDataURI; var aInBackground = params.inBackground; var aDisallowInheritPrincipal = params.disallowInheritPrincipal; var aInitiatingDoc = params.initiatingDoc; @@ -315,6 +317,9 @@ function openLinkIn(url, where, params) { } if (aDisallowInheritPrincipal) flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; + if (aForceAllowDataURI) { + flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FORCE_ALLOW_DATA_URI; + } w.gBrowser.loadURIWithFlags(url, flags, aReferrerURI, null, aPostData); break; case "tabshifted": diff --git a/application/palemoon/base/jar.mn b/application/palemoon/base/jar.mn index 29896341e..fd2df79e1 100644 --- a/application/palemoon/base/jar.mn +++ b/application/palemoon/base/jar.mn @@ -108,6 +108,8 @@ browser.jar: * content/browser/sanitize.xul (content/sanitize.xul) * content/browser/sanitizeDialog.js (content/sanitizeDialog.js) content/browser/sanitizeDialog.css (content/sanitizeDialog.css) +* content/browser/autocomplete.css (content/autocomplete.css) +* content/browser/autocomplete.xml (content/autocomplete.xml) content/browser/tabbrowser.css (content/tabbrowser.css) * content/browser/tabbrowser.xml (content/tabbrowser.xml) * content/browser/urlbarBindings.xml (content/urlbarBindings.xml) diff --git a/application/palemoon/components/feeds/FeedConverter.js b/application/palemoon/components/feeds/FeedConverter.js index 75115cc94..d0f573774 100644 --- a/application/palemoon/components/feeds/FeedConverter.js +++ b/application/palemoon/components/feeds/FeedConverter.js @@ -260,7 +260,7 @@ FeedConverter.prototype = { } chromeChannel.loadGroup = this._request.loadGroup; - chromeChannel.asyncOpen(this._listener, null); + chromeChannel.asyncOpen2(this._listener); } finally { this._releaseHandles(); diff --git a/application/palemoon/components/feeds/FeedWriter.js b/application/palemoon/components/feeds/FeedWriter.js index 28cf582c2..cbb146564 100644 --- a/application/palemoon/components/feeds/FeedWriter.js +++ b/application/palemoon/components/feeds/FeedWriter.js @@ -9,6 +9,7 @@ const Cr = Components.results; const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); const FEEDWRITER_CID = Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}"); const FEEDWRITER_CONTRACTID = "@mozilla.org/browser/feeds/result-writer;1"; @@ -1137,16 +1138,14 @@ FeedWriter.prototype = { var nullPrincipal = Cc["@mozilla.org/nullprincipal;1"]. createInstance(Ci.nsIPrincipal); - var resolvedURI = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService). - newChannel2("about:feeds", - null, - null, - null, // aLoadingNode - nullPrincipal, - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER).URI; + // this channel is not going to be openend, use a nullPrincipal + // and the most restrctive securityFlag. + let resolvedURI = NetUtil.newChannel({ + uri: "about:feeds", + loadingPrincipal: nullPrincipal, + securityFlags: Ci.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED, + contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER + }).URI; if (resolvedURI.equals(chan.URI)) return chan.originalURI; diff --git a/application/palemoon/components/nsBrowserContentHandler.js b/application/palemoon/components/nsBrowserContentHandler.js index 13ea9da12..6a75b40f2 100644 --- a/application/palemoon/components/nsBrowserContentHandler.js +++ b/application/palemoon/components/nsBrowserContentHandler.js @@ -518,16 +518,16 @@ nsBrowserContentHandler.prototype = { #endif }, - helpInfo : " -browser Open a browser window.\n" + - " -new-window <url> Open <url> in a new window.\n" + - " -new-tab <url> Open <url> in a new tab.\n" + - " -private-window <url> Open <url> in a new private window.\n" + + helpInfo : " --browser Open a browser window.\n" + + " --new-window <url> Open <url> in a new window.\n" + + " --new-tab <url> Open <url> in a new tab.\n" + + " --private-window <url> Open <url> in a new private window.\n" + #ifdef XP_WIN - " -preferences Open Options dialog.\n" + + " --preferences Open Options dialog.\n" + #else - " -preferences Open Preferences dialog.\n" + + " --preferences Open Preferences dialog.\n" + #endif - " -search <term> Search <term> with your default search engine.\n", + " --search <term> Search <term> with your default search engine.\n", /* nsIBrowserHandler */ diff --git a/application/palemoon/components/nsBrowserGlue.js b/application/palemoon/components/nsBrowserGlue.js index c4205c2c5..225cddd52 100644 --- a/application/palemoon/components/nsBrowserGlue.js +++ b/application/palemoon/components/nsBrowserGlue.js @@ -35,6 +35,7 @@ Cu.import("resource://gre/modules/Services.jsm"); ["OS", "resource://gre/modules/osfile.jsm"], ["LoginManagerParent", "resource://gre/modules/LoginManagerParent.jsm"], ["FormValidationHandler", "resource:///modules/FormValidationHandler.jsm"], + ["AutoCompletePopup", "resource:///modules/AutoCompletePopup.jsm"], ["DateTimePickerHelper", "resource://gre/modules/DateTimePickerHelper.jsm"], ].forEach(([name, resource]) => XPCOMUtils.defineLazyModuleGetter(this, name, resource)); @@ -405,6 +406,8 @@ BrowserGlue.prototype = { #endif FormValidationHandler.init(); + AutoCompletePopup.init(); + LoginManagerParent.init(); Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); @@ -515,6 +518,7 @@ BrowserGlue.prototype = { webrtcUI.uninit(); #endif FormValidationHandler.uninit(); + AutoCompletePopup.uninit(); this._dispose(); }, diff --git a/application/palemoon/components/places/content/editBookmarkOverlay.js b/application/palemoon/components/places/content/editBookmarkOverlay.js index 98bfcccd7..43645cc73 100644 --- a/application/palemoon/components/places/content/editBookmarkOverlay.js +++ b/application/palemoon/components/places/content/editBookmarkOverlay.js @@ -16,6 +16,7 @@ var gEditItemOverlay = { _itemType: -1, _readOnly: false, _hiddenRows: [], + _onPanelReady: false, _observersAdded: false, _staticFoldersListBuilt: false, _initialized: false, @@ -50,6 +51,7 @@ var gEditItemOverlay = { this._readOnly = aInfo && aInfo.forceReadOnly; this._titleOverride = aInfo && aInfo.titleOverride ? aInfo.titleOverride : ""; + this._onPanelReady = aInfo && aInfo.onPanelReady; }, _showHideRows: function EIO__showHideRows() { @@ -219,7 +221,15 @@ var gEditItemOverlay = { this._observersAdded = true; } - this._initialized = true; + let focusElement = () => { + this._initialized = true; + }; + + if (this._onPanelReady) { + this._onPanelReady(focusElement); + } else { + focusElement(); + } }, /** @@ -243,11 +253,7 @@ var gEditItemOverlay = { if (field.value != aValue) { field.value = aValue; - - // clear the undo stack - var editor = field.editor; - if (editor) - editor.transactionManager.clear(); + this._editorTransactionManagerClear(field); } }, @@ -352,6 +358,26 @@ var gEditItemOverlay = { return document.getElementById("editBMPanel_" + aID); }, + _editorTransactionManagerClear: function EIO__editorTransactionManagerClear(aItem) { + // Clear the editor's undo stack + let transactionManager; + try { + transactionManager = aItem.editor.transactionManager; + } catch (e) { + // When retrieving the transaction manager, editor may be null resulting + // in a TypeError. Additionally, the transaction manager may not + // exist yet, which causes access to it to throw NS_ERROR_FAILURE. + // In either event, the transaction manager doesn't exist it, so we + // don't need to worry about clearing it. + if (!(e instanceof TypeError) && e.result != Cr.NS_ERROR_FAILURE) { + throw e; + } + } + if (transactionManager) { + transactionManager.clear(); + } + }, + _getItemStaticTitle: function EIO__getItemStaticTitle() { if (this._titleOverride) return this._titleOverride; @@ -370,11 +396,7 @@ var gEditItemOverlay = { var namePicker = this._element("namePicker"); namePicker.value = this._getItemStaticTitle(); namePicker.readOnly = this._readOnly; - - // clear the undo stack - var editor = namePicker.editor; - if (editor) - editor.transactionManager.clear(); + this._editorTransactionManagerClear(namePicker); }, uninitPanel: function EIO_uninitPanel(aHideCollapsibleElements) { @@ -963,8 +985,7 @@ var gEditItemOverlay = { var namePicker = this._element("namePicker"); if (namePicker.value != aValue) { namePicker.value = aValue; - // clear undo stack - namePicker.editor.transactionManager.clear(); + this._editorTransactionManagerClear(namePicker); } break; case "uri": diff --git a/application/palemoon/components/preferences/cookies.js b/application/palemoon/components/preferences/cookies.js index c0455d679..ea7e7d4e2 100644 --- a/application/palemoon/components/preferences/cookies.js +++ b/application/palemoon/components/preferences/cookies.js @@ -63,7 +63,9 @@ var gCookiesWindow = { _cookieEquals: function (aCookieA, aCookieB, aStrippedHost) { return aCookieA.rawHost == aStrippedHost && aCookieA.name == aCookieB.name && - aCookieA.path == aCookieB.path; + aCookieA.path == aCookieB.path && + ChromeUtils.isOriginAttributesEqual(aCookieA.originAttributes, + aCookieB.originAttributes); }, observe: function (aCookie, aTopic, aData) { @@ -268,15 +270,19 @@ var gCookiesWindow = { var item = this._getItemAtIndex(aIndex); if (!item) return; this._invalidateCache(aIndex - 1); - if (item.container) + if (item.container) { gCookiesWindow._hosts[item.rawHost] = null; - else { + } else { var parent = this._getItemAtIndex(item.parentIndex); for (var i = 0; i < parent.cookies.length; ++i) { var cookie = parent.cookies[i]; if (item.rawHost == cookie.rawHost && - item.name == cookie.name && item.path == cookie.path) + item.name == cookie.name && + item.path == cookie.path && + ChromeUtils.isOriginAttributesEqual(item.originAttributes, + cookie.originAttributes)) { parent.cookies.splice(i, removeCount); + } } } }, @@ -451,16 +457,17 @@ var gCookiesWindow = { _makeCookieObject: function (aStrippedHost, aCookie) { var host = aCookie.host; var formattedHost = host.charAt(0) == "." ? host.substring(1, host.length) : host; - var c = { name : aCookie.name, - value : aCookie.value, - isDomain : aCookie.isDomain, - host : aCookie.host, - rawHost : aStrippedHost, - path : aCookie.path, - isSecure : aCookie.isSecure, - expires : aCookie.expires, - level : 1, - container : false }; + var c = { name : aCookie.name, + value : aCookie.value, + isDomain : aCookie.isDomain, + host : aCookie.host, + rawHost : aStrippedHost, + path : aCookie.path, + isSecure : aCookie.isSecure, + expires : aCookie.expires, + level : 1, + container : false, + originAttributes: aCookie.originAttributes }; return c; }, @@ -567,7 +574,8 @@ var gCookiesWindow = { blockFutureCookies = psvc.getBoolPref("network.cookie.blockFutureCookies"); for (var i = 0; i < deleteItems.length; ++i) { var item = deleteItems[i]; - this._cm.remove(item.host, item.name, item.path, blockFutureCookies); + this._cm.remove(item.host, item.name, item.path, + blockFutureCookies, item.originAttributes); } }, diff --git a/application/palemoon/components/search/content/engineManager.js b/application/palemoon/components/search/content/engineManager.js index 92b6d59b7..993d48b06 100644 --- a/application/palemoon/components/search/content/engineManager.js +++ b/application/palemoon/components/search/content/engineManager.js @@ -2,7 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", + "resource://gre/modules/Task.jsm"); const Ci = Components.interfaces; const Cc = Components.classes; @@ -105,7 +110,7 @@ var gEngineManagerDialog = { document.getElementById("engineList").focus(); }, - editKeyword: function engineManager_editKeyword() { + editKeyword: Task.async(function* engineManager_editKeyword() { var selectedEngine = gEngineView.selectedEngine; if (!selectedEngine) return; @@ -121,12 +126,8 @@ var gEngineManagerDialog = { var dupName = ""; if (alias.value != "") { - try { - let bmserv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - if (bmserv.getURIForKeyword(alias.value)) - bduplicate = true; - } catch(ex) {} + // Check for duplicates in Places keywords. + bduplicate = !!(yield PlacesUtils.keywords.fetch(alias.value)); // Check for duplicates in changes we haven't committed yet let engines = gEngineView._engineStore.engines; @@ -154,7 +155,7 @@ var gEngineManagerDialog = { break; } } - }, + }), onSelect: function engineManager_onSelect() { // Buttons only work if an engine is selected and it's not the last engine, diff --git a/application/palemoon/components/search/content/engineManager.xul b/application/palemoon/components/search/content/engineManager.xul index 50181c066..1152ef8db 100644 --- a/application/palemoon/components/search/content/engineManager.xul +++ b/application/palemoon/components/search/content/engineManager.xul @@ -36,7 +36,7 @@ oncommand="gEngineManagerDialog.bump(-1);" disabled="true"/> <command id="cmd_editkeyword" - oncommand="gEngineManagerDialog.editKeyword();" + oncommand="gEngineManagerDialog.editKeyword().catch(Components.utils.reportError);" disabled="true"/> </commandset> diff --git a/application/palemoon/components/statusbar/Downloads.jsm b/application/palemoon/components/statusbar/Downloads.jsm index 74bc42144..091fdad2e 100644 --- a/application/palemoon/components/statusbar/Downloads.jsm +++ b/application/palemoon/components/statusbar/Downloads.jsm @@ -18,657 +18,657 @@ CU.import("resource://gre/modules/XPCOMUtils.jsm"); function S4EDownloadService(window, gBrowser, service, getters) { - this._window = window; - this._gBrowser = gBrowser; - this._service = service; - this._getters = getters; + this._window = window; + this._gBrowser = gBrowser; + this._service = service; + this._getters = getters; - this._handler = new JSTransferHandler(this._window, this); + this._handler = new JSTransferHandler(this._window, this); } S4EDownloadService.prototype = { - _window: null, - _gBrowser: null, - _service: null, - _getters: null, - - _handler: null, - _listening: false, - - _binding: false, - _customizing: false, - - _lastTime: Infinity, - - _dlActive: false, - _dlPaused: false, - _dlFinished: false, - - _dlCountStr: null, - _dlTimeStr: null, - - _dlProgressAvg: 0, - _dlProgressMax: 0, - _dlProgressMin: 0, - _dlProgressType: "active", - - _dlNotifyTimer: 0, - _dlNotifyGlowTimer: 0, - - init: function() - { - if(!this._getters.downloadButton) - { - this.uninit(); - return; - } - - if(this._listening) - { - return; - } - - this._handler.start(); - this._listening = true; - - this._lastTime = Infinity; - - this.updateBinding(); - this.updateStatus(); - }, - - uninit: function() - { - if(!this._listening) - { - return; - } - - this._listening = false; - this._handler.stop(); - - this.releaseBinding(); - }, - - destroy: function() - { - this.uninit(); - this._handler.destroy(); - - ["_window", "_gBrowser", "_service", "_getters", "_handler"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - updateBinding: function() - { - if(!this._listening) - { - this.releaseBinding(); - return; - } - - switch(this._service.downloadButtonAction) - { - case 1: // Default - this.attachBinding(); - break; - default: - this.releaseBinding(); - break; - } - }, - - attachBinding: function() - { - if(this._binding) - { - return; - } - - let db = this._window.DownloadsButton; - - db._getAnchorS4EBackup = db.getAnchor; - db.getAnchor = this.getAnchor.bind(this); - - db._releaseAnchorS4EBackup = db.releaseAnchor; - db.releaseAnchor = function() {}; - - this._binding = true; - }, - - releaseBinding: function() - { - if(!this._binding) - { - return; - } - - let db = this._window.DownloadsButton; - - db.getAnchor = db._getAnchorS4EBackup; - db.releaseAnchor = db._releaseAnchorS4EBackup; - - this._binding = false; - }, - - customizing: function(val) - { - this._customizing = val; - }, - - updateStatus: function(lastFinished) - { - if(!this._getters.downloadButton) - { - this.uninit(); - return; - } - - let numActive = 0; - let numPaused = 0; - let activeTotalSize = 0; - let activeTransferred = 0; - let activeMaxProgress = -Infinity; - let activeMinProgress = Infinity; - let pausedTotalSize = 0; - let pausedTransferred = 0; - let pausedMaxProgress = -Infinity; - let pausedMinProgress = Infinity; - let maxTime = -Infinity; - - let dls = ((this.isPrivateWindow) ? this._handler.activePrivateEntries() : this._handler.activeEntries()); - for(let dl of dls) - { - if(dl.state == CI.nsIDownloadManager.DOWNLOAD_DOWNLOADING) - { - numActive++; - if(dl.size > 0) - { - if(dl.speed > 0) - { - maxTime = Math.max(maxTime, (dl.size - dl.transferred) / dl.speed); - } - - activeTotalSize += dl.size; - activeTransferred += dl.transferred; - - let currentProgress = ((dl.transferred * 100) / dl.size); - activeMaxProgress = Math.max(activeMaxProgress, currentProgress); - activeMinProgress = Math.min(activeMinProgress, currentProgress); - } - } - else if(dl.state == CI.nsIDownloadManager.DOWNLOAD_PAUSED) - { - numPaused++; - if(dl.size > 0) - { - pausedTotalSize += dl.size; - pausedTransferred += dl.transferred; - - let currentProgress = ((dl.transferred * 100) / dl.size); - pausedMaxProgress = Math.max(pausedMaxProgress, currentProgress); - pausedMinProgress = Math.min(pausedMinProgress, currentProgress); - } - } - } - - if((numActive + numPaused) == 0) - { - this._dlActive = false; - this._dlFinished = lastFinished; - this.updateButton(); - this._lastTime = Infinity; - return; - } - - let dlPaused = (numActive == 0); - let dlStatus = ((dlPaused) ? this._getters.strings.getString("pausedDownloads") - : this._getters.strings.getString("activeDownloads")); - let dlCount = ((dlPaused) ? numPaused : numActive); - let dlTotalSize = ((dlPaused) ? pausedTotalSize : activeTotalSize); - let dlTransferred = ((dlPaused) ? pausedTransferred : activeTransferred); - let dlMaxProgress = ((dlPaused) ? pausedMaxProgress : activeMaxProgress); - let dlMinProgress = ((dlPaused) ? pausedMinProgress : activeMinProgress); - let dlProgressType = ((dlPaused) ? "paused" : "active"); - - [this._dlTimeStr, this._lastTime] = DownloadUtils.getTimeLeft(maxTime, this._lastTime); - this._dlCountStr = PluralForm.get(dlCount, dlStatus).replace("#1", dlCount); - this._dlProgressAvg = ((dlTotalSize == 0) ? 100 : ((dlTransferred * 100) / dlTotalSize)); - this._dlProgressMax = ((dlTotalSize == 0) ? 100 : dlMaxProgress); - this._dlProgressMin = ((dlTotalSize == 0) ? 100 : dlMinProgress); - this._dlProgressType = dlProgressType + ((dlTotalSize == 0) ? "-unknown" : ""); - this._dlPaused = dlPaused; - this._dlActive = true; - this._dlFinished = false; - - this.updateButton(); - }, - - updateButton: function() - { - let download_button = this._getters.downloadButton; - let download_tooltip = this._getters.downloadButtonTooltip; - let download_progress = this._getters.downloadButtonProgress; - let download_label = this._getters.downloadButtonLabel; - if(!download_button) - { - return; - } - - if(!this._dlActive) - { - download_button.collapsed = true; - download_label.value = download_tooltip.label = this._getters.strings.getString("noDownloads"); - - download_progress.collapsed = true; - download_progress.value = 0; - - if(this._dlFinished && this._handler.hasPBAPI && !this.isUIShowing) - { - this.callAttention(download_button); - } - return; - } - - switch(this._service.downloadProgress) - { - case 2: - download_progress.value = this._dlProgressMax; - break; - case 3: - download_progress.value = this._dlProgressMin; - break; - default: - download_progress.value = this._dlProgressAvg; - break; - } - download_progress.setAttribute("pmType", this._dlProgressType); - download_progress.collapsed = (this._service.downloadProgress == 0); - - download_label.value = this.buildString(this._service.downloadLabel); - download_tooltip.label = this.buildString(this._service.downloadTooltip); - - this.clearAttention(download_button); - download_button.collapsed = false; - }, - - callAttention: function(download_button) - { - if(this._dlNotifyGlowTimer != 0) - { - this._window.clearTimeout(this._dlNotifyGlowTimer); - this._dlNotifyGlowTimer = 0; - } - - download_button.setAttribute("attention", "true"); - - if(this._service.downloadNotifyTimeout) - { - this._dlNotifyGlowTimer = this._window.setTimeout(function(self, button) - { - self._dlNotifyGlowTimer = 0; - button.removeAttribute("attention"); - }, this._service.downloadNotifyTimeout, this, download_button); - } - }, - - clearAttention: function(download_button) - { - if(this._dlNotifyGlowTimer != 0) - { - this._window.clearTimeout(this._dlNotifyGlowTimer); - this._dlNotifyGlowTimer = 0; - } - - download_button.removeAttribute("attention"); - }, - - notify: function() - { - if(this._dlNotifyTimer == 0 && this._service.downloadNotifyAnimate) - { - let download_button_anchor = this._getters.downloadButtonAnchor; - let download_notify_anchor = this._getters.downloadNotifyAnchor; - if(download_button_anchor) - { - if(!download_notify_anchor.style.transform) - { - let bAnchorRect = download_button_anchor.getBoundingClientRect(); - let nAnchorRect = download_notify_anchor.getBoundingClientRect(); - - let translateX = bAnchorRect.left - nAnchorRect.left; - translateX += .5 * (bAnchorRect.width - nAnchorRect.width); - - let translateY = bAnchorRect.top - nAnchorRect.top; - translateY += .5 * (bAnchorRect.height - nAnchorRect.height); - - download_notify_anchor.style.transform = "translate(" + translateX + "px, " + translateY + "px)"; - } - - download_notify_anchor.setAttribute("notification", "finish"); - this._dlNotifyTimer = this._window.setTimeout(function(self, anchor) - { - self._dlNotifyTimer = 0; - anchor.removeAttribute("notification"); - anchor.style.transform = ""; - }, 1000, this, download_notify_anchor); - } - } - }, - - clearFinished: function() - { - this._dlFinished = false; - let download_button = this._getters.downloadButton; - if(download_button) - { - this.clearAttention(download_button); - } - }, - - getAnchor: function(aCallback) - { - if(this._customizing) - { - aCallback(null); - return; - } - - aCallback(this._getters.downloadButtonAnchor); - }, - - openUI: function(aEvent) - { - this.clearFinished(); - - switch(this._service.downloadButtonAction) - { - case 1: // Firefox Default - this._handler.openUINative(); - break; - case 2: // Show Library - this._window.PlacesCommandHook.showPlacesOrganizer("Downloads"); - break; - case 3: // Show Tab - let found = this._gBrowser.browsers.some(function(browser, index) - { - if("about:downloads" == browser.currentURI.spec) - { - this._gBrowser.selectedTab = this._gBrowser.tabContainer.childNodes[index]; - return true; - } - }, this); - - if(!found) - { - this._window.openUILinkIn("about:downloads", "tab"); - } - break; - case 4: // External Command - let command = this._service.downloadButtonActionCommand; - if(commend) - { - this._window.goDoCommand(command); - } - break; - default: // Nothing - break; - } - - aEvent.stopPropagation(); - }, - - get isPrivateWindow() - { - return this._handler.hasPBAPI && PrivateBrowsingUtils.isWindowPrivate(this._window); - }, - - get isUIShowing() - { - switch(this._service.downloadButtonAction) - { - case 1: // Firefox Default - return this._handler.isUIShowingNative; - case 2: // Show Library - var organizer = Services.wm.getMostRecentWindow("Places:Organizer"); - if(organizer) - { - let selectedNode = organizer.PlacesOrganizer._places.selectedNode; - let downloadsItemId = organizer.PlacesUIUtils.leftPaneQueries["Downloads"]; - return selectedNode && selectedNode.itemId === downloadsItemId; - } - return false; - case 3: // Show tab - let currentURI = this._gBrowser.currentURI; - return currentURI && currentURI.spec == "about:downloads"; - default: // Nothing - return false; - } - }, - - buildString: function(mode) - { - switch(mode) - { - case 0: - return this._dlCountStr; - case 1: - return ((this._dlPaused) ? this._dlCountStr : this._dlTimeStr); - default: - let compStr = this._dlCountStr; - if(!this._dlPaused) - { - compStr += " (" + this._dlTimeStr + ")"; - } - return compStr; - } - } + _window: null, + _gBrowser: null, + _service: null, + _getters: null, + + _handler: null, + _listening: false, + + _binding: false, + _customizing: false, + + _lastTime: Infinity, + + _dlActive: false, + _dlPaused: false, + _dlFinished: false, + + _dlCountStr: null, + _dlTimeStr: null, + + _dlProgressAvg: 0, + _dlProgressMax: 0, + _dlProgressMin: 0, + _dlProgressType: "active", + + _dlNotifyTimer: 0, + _dlNotifyGlowTimer: 0, + + init: function() + { + if(!this._getters.downloadButton) + { + this.uninit(); + return; + } + + if(this._listening) + { + return; + } + + this._handler.start(); + this._listening = true; + + this._lastTime = Infinity; + + this.updateBinding(); + this.updateStatus(); + }, + + uninit: function() + { + if(!this._listening) + { + return; + } + + this._listening = false; + this._handler.stop(); + + this.releaseBinding(); + }, + + destroy: function() + { + this.uninit(); + this._handler.destroy(); + + ["_window", "_gBrowser", "_service", "_getters", "_handler"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + updateBinding: function() + { + if(!this._listening) + { + this.releaseBinding(); + return; + } + + switch(this._service.downloadButtonAction) + { + case 1: // Default + this.attachBinding(); + break; + default: + this.releaseBinding(); + break; + } + }, + + attachBinding: function() + { + if(this._binding) + { + return; + } + + let db = this._window.DownloadsButton; + + db._getAnchorS4EBackup = db.getAnchor; + db.getAnchor = this.getAnchor.bind(this); + + db._releaseAnchorS4EBackup = db.releaseAnchor; + db.releaseAnchor = function() {}; + + this._binding = true; + }, + + releaseBinding: function() + { + if(!this._binding) + { + return; + } + + let db = this._window.DownloadsButton; + + db.getAnchor = db._getAnchorS4EBackup; + db.releaseAnchor = db._releaseAnchorS4EBackup; + + this._binding = false; + }, + + customizing: function(val) + { + this._customizing = val; + }, + + updateStatus: function(lastFinished) + { + if(!this._getters.downloadButton) + { + this.uninit(); + return; + } + + let numActive = 0; + let numPaused = 0; + let activeTotalSize = 0; + let activeTransferred = 0; + let activeMaxProgress = -Infinity; + let activeMinProgress = Infinity; + let pausedTotalSize = 0; + let pausedTransferred = 0; + let pausedMaxProgress = -Infinity; + let pausedMinProgress = Infinity; + let maxTime = -Infinity; + + let dls = ((this.isPrivateWindow) ? this._handler.activePrivateEntries() : this._handler.activeEntries()); + for(let dl of dls) + { + if(dl.state == CI.nsIDownloadManager.DOWNLOAD_DOWNLOADING) + { + numActive++; + if(dl.size > 0) + { + if(dl.speed > 0) + { + maxTime = Math.max(maxTime, (dl.size - dl.transferred) / dl.speed); + } + + activeTotalSize += dl.size; + activeTransferred += dl.transferred; + + let currentProgress = ((dl.transferred * 100) / dl.size); + activeMaxProgress = Math.max(activeMaxProgress, currentProgress); + activeMinProgress = Math.min(activeMinProgress, currentProgress); + } + } + else if(dl.state == CI.nsIDownloadManager.DOWNLOAD_PAUSED) + { + numPaused++; + if(dl.size > 0) + { + pausedTotalSize += dl.size; + pausedTransferred += dl.transferred; + + let currentProgress = ((dl.transferred * 100) / dl.size); + pausedMaxProgress = Math.max(pausedMaxProgress, currentProgress); + pausedMinProgress = Math.min(pausedMinProgress, currentProgress); + } + } + } + + if((numActive + numPaused) == 0) + { + this._dlActive = false; + this._dlFinished = lastFinished; + this.updateButton(); + this._lastTime = Infinity; + return; + } + + let dlPaused = (numActive == 0); + let dlStatus = ((dlPaused) ? this._getters.strings.getString("pausedDownloads") + : this._getters.strings.getString("activeDownloads")); + let dlCount = ((dlPaused) ? numPaused : numActive); + let dlTotalSize = ((dlPaused) ? pausedTotalSize : activeTotalSize); + let dlTransferred = ((dlPaused) ? pausedTransferred : activeTransferred); + let dlMaxProgress = ((dlPaused) ? pausedMaxProgress : activeMaxProgress); + let dlMinProgress = ((dlPaused) ? pausedMinProgress : activeMinProgress); + let dlProgressType = ((dlPaused) ? "paused" : "active"); + + [this._dlTimeStr, this._lastTime] = DownloadUtils.getTimeLeft(maxTime, this._lastTime); + this._dlCountStr = PluralForm.get(dlCount, dlStatus).replace("#1", dlCount); + this._dlProgressAvg = ((dlTotalSize == 0) ? 100 : ((dlTransferred * 100) / dlTotalSize)); + this._dlProgressMax = ((dlTotalSize == 0) ? 100 : dlMaxProgress); + this._dlProgressMin = ((dlTotalSize == 0) ? 100 : dlMinProgress); + this._dlProgressType = dlProgressType + ((dlTotalSize == 0) ? "-unknown" : ""); + this._dlPaused = dlPaused; + this._dlActive = true; + this._dlFinished = false; + + this.updateButton(); + }, + + updateButton: function() + { + let download_button = this._getters.downloadButton; + let download_tooltip = this._getters.downloadButtonTooltip; + let download_progress = this._getters.downloadButtonProgress; + let download_label = this._getters.downloadButtonLabel; + if(!download_button) + { + return; + } + + if(!this._dlActive) + { + download_button.collapsed = true; + download_label.value = download_tooltip.label = this._getters.strings.getString("noDownloads"); + + download_progress.collapsed = true; + download_progress.value = 0; + + if(this._dlFinished && this._handler.hasPBAPI && !this.isUIShowing) + { + this.callAttention(download_button); + } + return; + } + + switch(this._service.downloadProgress) + { + case 2: + download_progress.value = this._dlProgressMax; + break; + case 3: + download_progress.value = this._dlProgressMin; + break; + default: + download_progress.value = this._dlProgressAvg; + break; + } + download_progress.setAttribute("pmType", this._dlProgressType); + download_progress.collapsed = (this._service.downloadProgress == 0); + + download_label.value = this.buildString(this._service.downloadLabel); + download_tooltip.label = this.buildString(this._service.downloadTooltip); + + this.clearAttention(download_button); + download_button.collapsed = false; + }, + + callAttention: function(download_button) + { + if(this._dlNotifyGlowTimer != 0) + { + this._window.clearTimeout(this._dlNotifyGlowTimer); + this._dlNotifyGlowTimer = 0; + } + + download_button.setAttribute("attention", "true"); + + if(this._service.downloadNotifyTimeout) + { + this._dlNotifyGlowTimer = this._window.setTimeout(function(self, button) + { + self._dlNotifyGlowTimer = 0; + button.removeAttribute("attention"); + }, this._service.downloadNotifyTimeout, this, download_button); + } + }, + + clearAttention: function(download_button) + { + if(this._dlNotifyGlowTimer != 0) + { + this._window.clearTimeout(this._dlNotifyGlowTimer); + this._dlNotifyGlowTimer = 0; + } + + download_button.removeAttribute("attention"); + }, + + notify: function() + { + if(this._dlNotifyTimer == 0 && this._service.downloadNotifyAnimate) + { + let download_button_anchor = this._getters.downloadButtonAnchor; + let download_notify_anchor = this._getters.downloadNotifyAnchor; + if(download_button_anchor) + { + if(!download_notify_anchor.style.transform) + { + let bAnchorRect = download_button_anchor.getBoundingClientRect(); + let nAnchorRect = download_notify_anchor.getBoundingClientRect(); + + let translateX = bAnchorRect.left - nAnchorRect.left; + translateX += .5 * (bAnchorRect.width - nAnchorRect.width); + + let translateY = bAnchorRect.top - nAnchorRect.top; + translateY += .5 * (bAnchorRect.height - nAnchorRect.height); + + download_notify_anchor.style.transform = "translate(" + translateX + "px, " + translateY + "px)"; + } + + download_notify_anchor.setAttribute("notification", "finish"); + this._dlNotifyTimer = this._window.setTimeout(function(self, anchor) + { + self._dlNotifyTimer = 0; + anchor.removeAttribute("notification"); + anchor.style.transform = ""; + }, 1000, this, download_notify_anchor); + } + } + }, + + clearFinished: function() + { + this._dlFinished = false; + let download_button = this._getters.downloadButton; + if(download_button) + { + this.clearAttention(download_button); + } + }, + + getAnchor: function(aCallback) + { + if(this._customizing) + { + aCallback(null); + return; + } + + aCallback(this._getters.downloadButtonAnchor); + }, + + openUI: function(aEvent) + { + this.clearFinished(); + + switch(this._service.downloadButtonAction) + { + case 1: // Firefox Default + this._handler.openUINative(); + break; + case 2: // Show Library + this._window.PlacesCommandHook.showPlacesOrganizer("Downloads"); + break; + case 3: // Show Tab + let found = this._gBrowser.browsers.some(function(browser, index) + { + if("about:downloads" == browser.currentURI.spec) + { + this._gBrowser.selectedTab = this._gBrowser.tabContainer.childNodes[index]; + return true; + } + }, this); + + if(!found) + { + this._window.openUILinkIn("about:downloads", "tab"); + } + break; + case 4: // External Command + let command = this._service.downloadButtonActionCommand; + if(commend) + { + this._window.goDoCommand(command); + } + break; + default: // Nothing + break; + } + + aEvent.stopPropagation(); + }, + + get isPrivateWindow() + { + return this._handler.hasPBAPI && PrivateBrowsingUtils.isWindowPrivate(this._window); + }, + + get isUIShowing() + { + switch(this._service.downloadButtonAction) + { + case 1: // Firefox Default + return this._handler.isUIShowingNative; + case 2: // Show Library + var organizer = Services.wm.getMostRecentWindow("Places:Organizer"); + if(organizer) + { + let selectedNode = organizer.PlacesOrganizer._places.selectedNode; + let downloadsItemId = organizer.PlacesUIUtils.leftPaneQueries["Downloads"]; + return selectedNode && selectedNode.itemId === downloadsItemId; + } + return false; + case 3: // Show tab + let currentURI = this._gBrowser.currentURI; + return currentURI && currentURI.spec == "about:downloads"; + default: // Nothing + return false; + } + }, + + buildString: function(mode) + { + switch(mode) + { + case 0: + return this._dlCountStr; + case 1: + return ((this._dlPaused) ? this._dlCountStr : this._dlTimeStr); + default: + let compStr = this._dlCountStr; + if(!this._dlPaused) + { + compStr += " (" + this._dlTimeStr + ")"; + } + return compStr; + } + } }; function JSTransferHandler(window, downloadService) { - this._window = window; + this._window = window; - let api = CU.import("resource://gre/modules/Downloads.jsm", {}).Downloads; + let api = CU.import("resource://gre/modules/Downloads.jsm", {}).Downloads; - this._activePublic = new JSTransferListener(downloadService, api.getList(api.PUBLIC), false); - this._activePrivate = new JSTransferListener(downloadService, api.getList(api.PRIVATE), true); + this._activePublic = new JSTransferListener(downloadService, api.getList(api.PUBLIC), false); + this._activePrivate = new JSTransferListener(downloadService, api.getList(api.PRIVATE), true); } JSTransferHandler.prototype = { - _window: null, - _activePublic: null, - _activePrivate: null, - - destroy: function() - { - this._activePublic.destroy(); - this._activePrivate.destroy(); - - ["_window", "_activePublic", "_activePrivate"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - start: function() - { - this._activePublic.start(); - this._activePrivate.start(); - }, - - stop: function() - { - this._activePublic.stop(); - this._activePrivate.stop(); - }, - - get hasPBAPI() - { - return true; - }, - - openUINative: function() - { - this._window.DownloadsPanel.showPanel(); - }, - - get isUIShowingNative() - { - return this._window.DownloadsPanel.isPanelShowing; - }, - - activeEntries: function() - { - return this._activePublic.downloads(); - }, - - activePrivateEntries: function() - { - return this._activePrivate.downloads(); - } + _window: null, + _activePublic: null, + _activePrivate: null, + + destroy: function() + { + this._activePublic.destroy(); + this._activePrivate.destroy(); + + ["_window", "_activePublic", "_activePrivate"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + start: function() + { + this._activePublic.start(); + this._activePrivate.start(); + }, + + stop: function() + { + this._activePublic.stop(); + this._activePrivate.stop(); + }, + + get hasPBAPI() + { + return true; + }, + + openUINative: function() + { + this._window.DownloadsPanel.showPanel(); + }, + + get isUIShowingNative() + { + return this._window.DownloadsPanel.isPanelShowing; + }, + + activeEntries: function() + { + return this._activePublic.downloads(); + }, + + activePrivateEntries: function() + { + return this._activePrivate.downloads(); + } }; function JSTransferListener(downloadService, listPromise, isPrivate) { - this._downloadService = downloadService; - this._isPrivate = isPrivate; - this._downloads = new Map(); + this._downloadService = downloadService; + this._isPrivate = isPrivate; + this._downloads = new Map(); - listPromise.then(this.initList.bind(this)).then(null, CU.reportError); + listPromise.then(this.initList.bind(this)).then(null, CU.reportError); } JSTransferListener.prototype = { - _downloadService: null, - _list: null, - _downloads: null, - _isPrivate: false, - _wantsStart: false, - - initList: function(list) - { - this._list = list; - if(this._wantsStart) { - this.start(); - } - - this._list.getAll().then(this.initDownloads.bind(this)).then(null, CU.reportError); - }, - - initDownloads: function(downloads) - { - downloads.forEach(function(download) - { - this.onDownloadAdded(download); - }, this); - }, - - destroy: function() - { - this._downloads.clear(); - - ["_downloadService", "_list", "_downloads"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - start: function() - { - if(!this._list) - { - this._wantsStart = true; - return; - } - - this._list.addView(this); - }, - - stop: function() - { - if(!this._list) - { - this._wantsStart = false; - return; - } - - this._list.removeView(this); - }, - - downloads: function() - { - return this._downloads.values(); - }, - - convertToState: function(dl) - { - if(dl.succeeded) - { - return CI.nsIDownloadManager.DOWNLOAD_FINISHED; - } - if(dl.error && dl.error.becauseBlockedByParentalControls) - { - return CI.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL; - } - if(dl.error) - { - return CI.nsIDownloadManager.DOWNLOAD_FAILED; - } - if(dl.canceled && dl.hasPartialData) - { - return CI.nsIDownloadManager.DOWNLOAD_PAUSED; - } - if(dl.canceled) - { - return CI.nsIDownloadManager.DOWNLOAD_CANCELED; - } - if(dl.stopped) - { - return CI.nsIDownloadManager.DOWNLOAD_NOTSTARTED; - } - return CI.nsIDownloadManager.DOWNLOAD_DOWNLOADING; - }, - - onDownloadAdded: function(aDownload) - { - let dl = this._downloads.get(aDownload); - if(!dl) - { - dl = {}; - this._downloads.set(aDownload, dl); - } - - dl.state = this.convertToState(aDownload); - dl.size = aDownload.totalBytes; - dl.speed = aDownload.speed; - dl.transferred = aDownload.currentBytes; - }, - - onDownloadChanged: function(aDownload) - { - this.onDownloadAdded(aDownload); - - if(this._isPrivate != this._downloadService.isPrivateWindow) - { - return; - } - - this._downloadService.updateStatus(aDownload.succeeded); - - if(aDownload.succeeded) - { - this._downloadService.notify() - } - }, - - onDownloadRemoved: function(aDownload) - { - this._downloads.delete(aDownload); - } + _downloadService: null, + _list: null, + _downloads: null, + _isPrivate: false, + _wantsStart: false, + + initList: function(list) + { + this._list = list; + if(this._wantsStart) { + this.start(); + } + + this._list.getAll().then(this.initDownloads.bind(this)).then(null, CU.reportError); + }, + + initDownloads: function(downloads) + { + downloads.forEach(function(download) + { + this.onDownloadAdded(download); + }, this); + }, + + destroy: function() + { + this._downloads.clear(); + + ["_downloadService", "_list", "_downloads"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + start: function() + { + if(!this._list) + { + this._wantsStart = true; + return; + } + + this._list.addView(this); + }, + + stop: function() + { + if(!this._list) + { + this._wantsStart = false; + return; + } + + this._list.removeView(this); + }, + + downloads: function() + { + return this._downloads.values(); + }, + + convertToState: function(dl) + { + if(dl.succeeded) + { + return CI.nsIDownloadManager.DOWNLOAD_FINISHED; + } + if(dl.error && dl.error.becauseBlockedByParentalControls) + { + return CI.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL; + } + if(dl.error) + { + return CI.nsIDownloadManager.DOWNLOAD_FAILED; + } + if(dl.canceled && dl.hasPartialData) + { + return CI.nsIDownloadManager.DOWNLOAD_PAUSED; + } + if(dl.canceled) + { + return CI.nsIDownloadManager.DOWNLOAD_CANCELED; + } + if(dl.stopped) + { + return CI.nsIDownloadManager.DOWNLOAD_NOTSTARTED; + } + return CI.nsIDownloadManager.DOWNLOAD_DOWNLOADING; + }, + + onDownloadAdded: function(aDownload) + { + let dl = this._downloads.get(aDownload); + if(!dl) + { + dl = {}; + this._downloads.set(aDownload, dl); + } + + dl.state = this.convertToState(aDownload); + dl.size = aDownload.totalBytes; + dl.speed = aDownload.speed; + dl.transferred = aDownload.currentBytes; + }, + + onDownloadChanged: function(aDownload) + { + this.onDownloadAdded(aDownload); + + if(this._isPrivate != this._downloadService.isPrivateWindow) + { + return; + } + + this._downloadService.updateStatus(aDownload.succeeded); + + if(aDownload.succeeded) + { + this._downloadService.notify() + } + }, + + onDownloadRemoved: function(aDownload) + { + this._downloads.delete(aDownload); + } }; diff --git a/application/palemoon/components/statusbar/Progress.jsm b/application/palemoon/components/statusbar/Progress.jsm index c03a25450..69d55db49 100644 --- a/application/palemoon/components/statusbar/Progress.jsm +++ b/application/palemoon/components/statusbar/Progress.jsm @@ -12,172 +12,172 @@ const CU = Components.utils; CU.import("resource://gre/modules/XPCOMUtils.jsm"); function S4EProgressService(gBrowser, service, getters, statusService) { - this._gBrowser = gBrowser; - this._service = service; - this._getters = getters; - this._statusService = statusService; + this._gBrowser = gBrowser; + this._service = service; + this._getters = getters; + this._statusService = statusService; - this._gBrowser.addProgressListener(this); + this._gBrowser.addProgressListener(this); } S4EProgressService.prototype = { - _gBrowser: null, - _service: null, - _getters: null, - _statusService: null, - - _busyUI: false, - - set value(val) - { - let toolbar_progress = this._getters.toolbarProgress; - if(toolbar_progress) - { - toolbar_progress.value = val; - } - - let throbber_progress = this._getters.throbberProgress; - if(throbber_progress) - { - if(val) - { - throbber_progress.setAttribute("progress", val); - } - else - { - throbber_progress.removeAttribute("progress"); - } - } - }, - - set collapsed(val) - { - let toolbar_progress = this._getters.toolbarProgress; - if(toolbar_progress) - { - toolbar_progress.collapsed = val; - } - - let throbber_progress = this._getters.throbberProgress; - if(throbber_progress) - { - if(val) - { - throbber_progress.removeAttribute("busy"); - } - else - { - throbber_progress.setAttribute("busy", true); - } - } - }, - - destroy: function() - { - this._gBrowser.removeProgressListener(this); - - ["_gBrowser", "_service", "_getters", "_statusService"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) - { - this._statusService.setNetworkStatus(aMessage, this._busyUI); - }, - - onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) - { - let nsIWPL = CI.nsIWebProgressListener; - - if(!this._busyUI - && aStateFlags & nsIWPL.STATE_START - && aStateFlags & nsIWPL.STATE_IS_NETWORK - && !(aStateFlags & nsIWPL.STATE_RESTORING)) - { - this._busyUI = true; - this.value = 0; - this.collapsed = false; - } - else if(aStateFlags & nsIWPL.STATE_STOP) - { - if(aRequest) - { - let msg = ""; - let location; - if(aRequest instanceof CI.nsIChannel || "URI" in aRequest) - { - location = aRequest.URI; - if(location.spec != "about:blank") - { - switch (aStatus) - { - case Components.results.NS_BINDING_ABORTED: - msg = this._getters.strings.getString("nv_stopped"); - break; - case Components.results.NS_ERROR_NET_TIMEOUT: - msg = this._getters.strings.getString("nv_timeout"); - break; - } - } - } - - if(!msg && (!location || location.spec != "about:blank")) - { - msg = this._getters.strings.getString("nv_done"); - } - - this._statusService.setDefaultStatus(msg); - this._statusService.setNetworkStatus("", this._busyUI); - } - - if(this._busyUI) - { - this._busyUI = false; - this.collapsed = true; - this.value = 0; - } - } - }, - - onUpdateCurrentBrowser: function(aStateFlags, aStatus, aMessage, aTotalProgress) - { - let nsIWPL = CI.nsIWebProgressListener; - let loadingDone = aStateFlags & nsIWPL.STATE_STOP; - - this.onStateChange( - this._gBrowser.webProgress, - { URI: this._gBrowser.currentURI }, - ((loadingDone ? nsIWPL.STATE_STOP : nsIWPL.STATE_START) | (aStateFlags & nsIWPL.STATE_IS_NETWORK)), - aStatus - ); - - if(!loadingDone) - { - this.onProgressChange(this._gBrowser.webProgress, null, 0, 0, aTotalProgress, 1); - this.onStatusChange(this._gBrowser.webProgress, null, 0, aMessage); - } - }, - - onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) - { - if (aMaxTotalProgress > 0 && this._busyUI) - { - // This is highly optimized. Don't touch this code unless - // you are intimately familiar with the cost of setting - // attrs on XUL elements. -- hyatt - let percentage = (aCurTotalProgress * 100) / aMaxTotalProgress; - this.value = percentage; - } - }, - - onProgressChange64: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) - { - return this.onProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress); - }, - - QueryInterface: XPCOMUtils.generateQI([ CI.nsIWebProgressListener, CI.nsIWebProgressListener2 ]) + _gBrowser: null, + _service: null, + _getters: null, + _statusService: null, + + _busyUI: false, + + set value(val) + { + let toolbar_progress = this._getters.toolbarProgress; + if(toolbar_progress) + { + toolbar_progress.value = val; + } + + let throbber_progress = this._getters.throbberProgress; + if(throbber_progress) + { + if(val) + { + throbber_progress.setAttribute("progress", val); + } + else + { + throbber_progress.removeAttribute("progress"); + } + } + }, + + set collapsed(val) + { + let toolbar_progress = this._getters.toolbarProgress; + if(toolbar_progress) + { + toolbar_progress.collapsed = val; + } + + let throbber_progress = this._getters.throbberProgress; + if(throbber_progress) + { + if(val) + { + throbber_progress.removeAttribute("busy"); + } + else + { + throbber_progress.setAttribute("busy", true); + } + } + }, + + destroy: function() + { + this._gBrowser.removeProgressListener(this); + + ["_gBrowser", "_service", "_getters", "_statusService"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) + { + this._statusService.setNetworkStatus(aMessage, this._busyUI); + }, + + onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) + { + let nsIWPL = CI.nsIWebProgressListener; + + if(!this._busyUI + && aStateFlags & nsIWPL.STATE_START + && aStateFlags & nsIWPL.STATE_IS_NETWORK + && !(aStateFlags & nsIWPL.STATE_RESTORING)) + { + this._busyUI = true; + this.value = 0; + this.collapsed = false; + } + else if(aStateFlags & nsIWPL.STATE_STOP) + { + if(aRequest) + { + let msg = ""; + let location; + if(aRequest instanceof CI.nsIChannel || "URI" in aRequest) + { + location = aRequest.URI; + if(location.spec != "about:blank") + { + switch (aStatus) + { + case Components.results.NS_BINDING_ABORTED: + msg = this._getters.strings.getString("nv_stopped"); + break; + case Components.results.NS_ERROR_NET_TIMEOUT: + msg = this._getters.strings.getString("nv_timeout"); + break; + } + } + } + + if(!msg && (!location || location.spec != "about:blank")) + { + msg = this._getters.strings.getString("nv_done"); + } + + this._statusService.setDefaultStatus(msg); + this._statusService.setNetworkStatus("", this._busyUI); + } + + if(this._busyUI) + { + this._busyUI = false; + this.collapsed = true; + this.value = 0; + } + } + }, + + onUpdateCurrentBrowser: function(aStateFlags, aStatus, aMessage, aTotalProgress) + { + let nsIWPL = CI.nsIWebProgressListener; + let loadingDone = aStateFlags & nsIWPL.STATE_STOP; + + this.onStateChange( + this._gBrowser.webProgress, + { URI: this._gBrowser.currentURI }, + ((loadingDone ? nsIWPL.STATE_STOP : nsIWPL.STATE_START) | (aStateFlags & nsIWPL.STATE_IS_NETWORK)), + aStatus + ); + + if(!loadingDone) + { + this.onProgressChange(this._gBrowser.webProgress, null, 0, 0, aTotalProgress, 1); + this.onStatusChange(this._gBrowser.webProgress, null, 0, aMessage); + } + }, + + onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) + { + if (aMaxTotalProgress > 0 && this._busyUI) + { + // This is highly optimized. Don't touch this code unless + // you are intimately familiar with the cost of setting + // attrs on XUL elements. -- hyatt + let percentage = (aCurTotalProgress * 100) / aMaxTotalProgress; + this.value = percentage; + } + }, + + onProgressChange64: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) + { + return this.onProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress); + }, + + QueryInterface: XPCOMUtils.generateQI([ CI.nsIWebProgressListener, CI.nsIWebProgressListener2 ]) }; diff --git a/application/palemoon/components/statusbar/Status.jsm b/application/palemoon/components/statusbar/Status.jsm index 3795545a3..d888c7d94 100644 --- a/application/palemoon/components/statusbar/Status.jsm +++ b/application/palemoon/components/statusbar/Status.jsm @@ -13,452 +13,452 @@ CU.import("resource://gre/modules/XPCOMUtils.jsm"); function S4EStatusService(window, service, getters) { - this._window = window; - this._service = service; - this._getters = getters; + this._window = window; + this._service = service; + this._getters = getters; - this._overLinkService = new S4EOverlinkService(this._window, this._service, this); + this._overLinkService = new S4EOverlinkService(this._window, this._service, this); } S4EStatusService.prototype = { - _window: null, - _service: null, - _getters: null, - _overLinkService: null, - - _overLink: { val: "", type: "" }, - _network: { val: "", type: "" }, - _networkXHR: { val: "", type: "" }, - _status: { val: "", type: "" }, - _jsStatus: { val: "", type: "" }, - _defaultStatus: { val: "", type: "" }, - - _isFullScreen: false, - _isFullScreenVideo: false, - - _statusText: { val: "", type: "" }, - _noUpdate: false, - _statusChromeTimeoutID: 0, - _statusContentTimeoutID: 0, - - getCompositeStatusText: function() - { - return this._statusText.val; - }, - - getStatusText: function() - { - return this._status.val; - }, - - setNetworkStatus: function(status, busy) - { - if(busy) - { - this._network = { val: status, type: "network" }; - this._networkXHR = { val: "", type: "network xhr" }; - } - else - { - this._networkXHR = { val: status, type: "network xhr" }; - } - this.updateStatusField(); - }, - - setStatusText: function(status) - { - this._status = { val: status, type: "status chrome" }; - this.updateStatusField(); - }, - - setJSStatus: function(status) - { - this._jsStatus = { val: status, type: "status content" }; - this.updateStatusField(); - }, - - setJSDefaultStatus: function(status) - { - // This was removed from Firefox in Bug 862917 - }, - - setDefaultStatus: function(status) - { - this._defaultStatus = { val: status, type: "status chrome default" }; - this.updateStatusField(); - }, - - setOverLink: function(link, aAnchor) - { - this._overLinkService.update(link, aAnchor); - }, - - setOverLinkInternal: function(link, aAnchor) - { - let status = this._service.status; - let statusLinkOver = this._service.statusLinkOver; - - if(statusLinkOver) - { - link = link.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g, encodeURIComponent); - if(status == statusLinkOver) - { - this._overLink = { val: link, type: "overLink", anchor: aAnchor }; - this.updateStatusField(); - } - else - { - this.setStatusField(statusLinkOver, { val: link, type: "overLink", anchor: aAnchor }, true); - } - } - }, - - setNoUpdate: function(nu) - { - this._noUpdate = nu; - }, - - buildBinding: function() { - let XULBWPropHandler = function(prop, oldval, newval) { - CU.reportError("Attempt to modify XULBrowserWindow." + prop); - return oldval; - }; - - ["updateStatusField", "onStatusChange"].forEach(function(prop) - { - this._window.XULBrowserWindow.unwatch(prop); - this._window.XULBrowserWindow[prop] = function() {}; - this._window.XULBrowserWindow.watch(prop, XULBWPropHandler); - }, this); - - ["getCompositeStatusText", "getStatusText", "setStatusText", "setJSStatus", - "setJSDefaultStatus", "setDefaultStatus", "setOverLink"].forEach(function(prop) - { - this._window.XULBrowserWindow.unwatch(prop); - this._window.XULBrowserWindow[prop] = this[prop].bind(this); - this._window.XULBrowserWindow.watch(prop, XULBWPropHandler); - }, this); - - let XULBWHandler = function(prop, oldval, newval) { - if(!newval) - { - return newval; - } - CU.reportError("XULBrowserWindow changed. Updating S4E bindings."); - this._window.setTimeout(function(self) - { - self.buildBinding(); - }, 0, this); - return newval; - }; - - this._window.watch("XULBrowserWindow", XULBWHandler); - }, - - destroy: function() - { - // No need to unbind from the XULBrowserWindow, it's already null at this point - - this.clearTimer("_statusChromeTimeoutID"); - this.clearTimer("_statusContentTimeoutID"); - - this._overLinkService.destroy(); - - ["_overLink", "_network", "_networkXHR", "_status", "_jsStatus", "_defaultStatus", - "_statusText", "_window", "_service", "_getters", "_overLinkService"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - buildTextOrder: function() - { - this.__defineGetter__("_textOrder", function() - { - let textOrder = ["_overLink"]; - if(this._service.statusNetwork) - { - textOrder.push("_network"); - if(this._service.statusNetworkXHR) - { - textOrder.push("_networkXHR"); - } - } - textOrder.push("_status", "_jsStatus"); - if(this._service.statusDefault) - { - textOrder.push("_defaultStatus"); - } - - delete this._textOrder; - return this._textOrder = textOrder; - }); - }, - - updateStatusField: function(force) - { - let text = { val: "", type: "" }; - for(let i = 0; !text.val && i < this._textOrder.length; i++) - { - text = this[this._textOrder[i]]; - } - - if(this._statusText.val != text.val || force) - { - if(this._noUpdate) - { - return; - } - - this._statusText = text; - - this.setStatusField(this._service.status, text, false); - - if(text.val && this._service.statusTimeout) - { - this.setTimer(text.type); - } - } - }, - - updateFullScreen: function() - { - this._isFullScreen = this._window.fullScreen; - this._isFullScreenVideo = false; - if(this._isFullScreen) - { - let fsEl = this._window.content.document.mozFullScreenElement; - if(fsEl && (fsEl.nodeName == "VIDEO" || fsEl.getElementsByTagName("VIDEO").length > 0)) - { - this._isFullScreenVideo = true; - } - } - - this.clearStatusField(); - this.updateStatusField(true); - }, - - setTimer: function(type) - { - let typeArgs = type.split(" ", 3); - - if(typeArgs.length < 2 || typeArgs[0] != "status") - { - return; - } - - if(typeArgs[1] == "chrome") - { - this.clearTimer("_statusChromeTimeoutID"); - this._statusChromeTimeoutID = this._window.setTimeout(function(self, isDefault) - { - self._statusChromeTimeoutID = 0; - if(isDefault) - { - self.setDefaultStatus(""); - } - else - { - self.setStatusText(""); - } - }, this._service.statusTimeout, this, (typeArgs.length == 3 && typeArgs[2] == "default")); - } - else - { - this.clearTimer("_statusContentTimeoutID"); - this._statusContentTimeoutID = this._window.setTimeout(function(self) - { - self._statusContentTimeoutID = 0; - self.setJSStatus(""); - }, this._service.statusTimeout, this); - } - }, - - clearTimer: function(timerName) - { - if(this[timerName] != 0) - { - this._window.clearTimeout(this[timerName]); - this[timerName] = 0; - } - }, - - clearStatusField: function() - { - this._getters.statusOverlay.value = ""; - - let status_label = this._getters.statusWidgetLabel; - if(status_label) - { - status_label.value = ""; - } - - }, - - setStatusField: function(location, text, allowTooltip) - { - if(!location) - { - return; - } - - let label = null; - - if(this._isFullScreen && this._service.advancedStatusDetectFullScreen) - { - switch(location) - { - case 1: // Toolbar - location = 3 - break; - case 2: // URL bar - if(Services.prefs.getBoolPref("browser.fullscreen.autohide")) - { - location = 3 - } - break; - } - } - - switch(location) - { - case 1: // Toolbar - label = this._getters.statusWidgetLabel; - break; - case 2: // URL Bar - break; - case 3: // Popup - default: - if(this._isFullScreenVideo && this._service.advancedStatusDetectVideo) - { - return; - } - label = this._getters.statusOverlay; - break; - } - - if(label) - { - label.setAttribute("previoustype", label.getAttribute("type")); - label.setAttribute("type", text.type); - label.value = text.val; - label.setAttribute("crop", text.type == "overLink" ? "center" : "end"); - } - } + _window: null, + _service: null, + _getters: null, + _overLinkService: null, + + _overLink: { val: "", type: "" }, + _network: { val: "", type: "" }, + _networkXHR: { val: "", type: "" }, + _status: { val: "", type: "" }, + _jsStatus: { val: "", type: "" }, + _defaultStatus: { val: "", type: "" }, + + _isFullScreen: false, + _isFullScreenVideo: false, + + _statusText: { val: "", type: "" }, + _noUpdate: false, + _statusChromeTimeoutID: 0, + _statusContentTimeoutID: 0, + + getCompositeStatusText: function() + { + return this._statusText.val; + }, + + getStatusText: function() + { + return this._status.val; + }, + + setNetworkStatus: function(status, busy) + { + if(busy) + { + this._network = { val: status, type: "network" }; + this._networkXHR = { val: "", type: "network xhr" }; + } + else + { + this._networkXHR = { val: status, type: "network xhr" }; + } + this.updateStatusField(); + }, + + setStatusText: function(status) + { + this._status = { val: status, type: "status chrome" }; + this.updateStatusField(); + }, + + setJSStatus: function(status) + { + this._jsStatus = { val: status, type: "status content" }; + this.updateStatusField(); + }, + + setJSDefaultStatus: function(status) + { + // This was removed from Firefox in Bug 862917 + }, + + setDefaultStatus: function(status) + { + this._defaultStatus = { val: status, type: "status chrome default" }; + this.updateStatusField(); + }, + + setOverLink: function(link, aAnchor) + { + this._overLinkService.update(link, aAnchor); + }, + + setOverLinkInternal: function(link, aAnchor) + { + let status = this._service.status; + let statusLinkOver = this._service.statusLinkOver; + + if(statusLinkOver) + { + link = link.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g, encodeURIComponent); + if(status == statusLinkOver) + { + this._overLink = { val: link, type: "overLink", anchor: aAnchor }; + this.updateStatusField(); + } + else + { + this.setStatusField(statusLinkOver, { val: link, type: "overLink", anchor: aAnchor }, true); + } + } + }, + + setNoUpdate: function(nu) + { + this._noUpdate = nu; + }, + + buildBinding: function() { + let XULBWPropHandler = function(prop, oldval, newval) { + CU.reportError("Attempt to modify XULBrowserWindow." + prop); + return oldval; + }; + + ["updateStatusField", "onStatusChange"].forEach(function(prop) + { + this._window.XULBrowserWindow.unwatch(prop); + this._window.XULBrowserWindow[prop] = function() {}; + this._window.XULBrowserWindow.watch(prop, XULBWPropHandler); + }, this); + + ["getCompositeStatusText", "getStatusText", "setStatusText", "setJSStatus", + "setJSDefaultStatus", "setDefaultStatus", "setOverLink"].forEach(function(prop) + { + this._window.XULBrowserWindow.unwatch(prop); + this._window.XULBrowserWindow[prop] = this[prop].bind(this); + this._window.XULBrowserWindow.watch(prop, XULBWPropHandler); + }, this); + + let XULBWHandler = function(prop, oldval, newval) { + if(!newval) + { + return newval; + } + CU.reportError("XULBrowserWindow changed. Updating S4E bindings."); + this._window.setTimeout(function(self) + { + self.buildBinding(); + }, 0, this); + return newval; + }; + + this._window.watch("XULBrowserWindow", XULBWHandler); + }, + + destroy: function() + { + // No need to unbind from the XULBrowserWindow, it's already null at this point + + this.clearTimer("_statusChromeTimeoutID"); + this.clearTimer("_statusContentTimeoutID"); + + this._overLinkService.destroy(); + + ["_overLink", "_network", "_networkXHR", "_status", "_jsStatus", "_defaultStatus", + "_statusText", "_window", "_service", "_getters", "_overLinkService"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + buildTextOrder: function() + { + this.__defineGetter__("_textOrder", function() + { + let textOrder = ["_overLink"]; + if(this._service.statusNetwork) + { + textOrder.push("_network"); + if(this._service.statusNetworkXHR) + { + textOrder.push("_networkXHR"); + } + } + textOrder.push("_status", "_jsStatus"); + if(this._service.statusDefault) + { + textOrder.push("_defaultStatus"); + } + + delete this._textOrder; + return this._textOrder = textOrder; + }); + }, + + updateStatusField: function(force) + { + let text = { val: "", type: "" }; + for(let i = 0; !text.val && i < this._textOrder.length; i++) + { + text = this[this._textOrder[i]]; + } + + if(this._statusText.val != text.val || force) + { + if(this._noUpdate) + { + return; + } + + this._statusText = text; + + this.setStatusField(this._service.status, text, false); + + if(text.val && this._service.statusTimeout) + { + this.setTimer(text.type); + } + } + }, + + updateFullScreen: function() + { + this._isFullScreen = this._window.fullScreen; + this._isFullScreenVideo = false; + if(this._isFullScreen) + { + let fsEl = this._window.content.document.mozFullScreenElement; + if(fsEl && (fsEl.nodeName == "VIDEO" || fsEl.getElementsByTagName("VIDEO").length > 0)) + { + this._isFullScreenVideo = true; + } + } + + this.clearStatusField(); + this.updateStatusField(true); + }, + + setTimer: function(type) + { + let typeArgs = type.split(" ", 3); + + if(typeArgs.length < 2 || typeArgs[0] != "status") + { + return; + } + + if(typeArgs[1] == "chrome") + { + this.clearTimer("_statusChromeTimeoutID"); + this._statusChromeTimeoutID = this._window.setTimeout(function(self, isDefault) + { + self._statusChromeTimeoutID = 0; + if(isDefault) + { + self.setDefaultStatus(""); + } + else + { + self.setStatusText(""); + } + }, this._service.statusTimeout, this, (typeArgs.length == 3 && typeArgs[2] == "default")); + } + else + { + this.clearTimer("_statusContentTimeoutID"); + this._statusContentTimeoutID = this._window.setTimeout(function(self) + { + self._statusContentTimeoutID = 0; + self.setJSStatus(""); + }, this._service.statusTimeout, this); + } + }, + + clearTimer: function(timerName) + { + if(this[timerName] != 0) + { + this._window.clearTimeout(this[timerName]); + this[timerName] = 0; + } + }, + + clearStatusField: function() + { + this._getters.statusOverlay.value = ""; + + let status_label = this._getters.statusWidgetLabel; + if(status_label) + { + status_label.value = ""; + } + + }, + + setStatusField: function(location, text, allowTooltip) + { + if(!location) + { + return; + } + + let label = null; + + if(this._isFullScreen && this._service.advancedStatusDetectFullScreen) + { + switch(location) + { + case 1: // Toolbar + location = 3 + break; + case 2: // URL bar + if(Services.prefs.getBoolPref("browser.fullscreen.autohide")) + { + location = 3 + } + break; + } + } + + switch(location) + { + case 1: // Toolbar + label = this._getters.statusWidgetLabel; + break; + case 2: // URL Bar + break; + case 3: // Popup + default: + if(this._isFullScreenVideo && this._service.advancedStatusDetectVideo) + { + return; + } + label = this._getters.statusOverlay; + break; + } + + if(label) + { + label.setAttribute("previoustype", label.getAttribute("type")); + label.setAttribute("type", text.type); + label.value = text.val; + label.setAttribute("crop", text.type == "overLink" ? "center" : "end"); + } + } }; function S4EOverlinkService(window, service, statusService) { - this._window = window; - this._service = service; - this._statusService = statusService; + this._window = window; + this._service = service; + this._statusService = statusService; } S4EOverlinkService.prototype = { - _window: null, - _service: null, - _statusService: null, - - _timer: 0, - _currentLink: { link: "", anchor: null }, - _pendingLink: { link: "", anchor: null }, - _listening: false, - - update: function(aLink, aAnchor) - { - this.clearTimer(); - this.stopListen(); - this._pendingLink = { link: aLink, anchor: aAnchor }; - - if(!aLink) - { - if(this._window.XULBrowserWindow.hideOverLinkImmediately || !this._service.statusLinkOverDelayHide) - { - this._show(); - } - else - { - this._showDelayed(); - } - } - else if(this._currentLink.link || !this._service.statusLinkOverDelayShow) - { - this._show(); - } - else - { - this._showDelayed(); - this.startListen(); - } - }, - - destroy: function() - { - this.clearTimer(); - this.stopListen(); - - ["_currentLink", "_pendingLink", "_statusService", "_window"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - startListen: function() - { - if(!this._listening) - { - this._window.addEventListener("mousemove", this, true); - this._listening = true; - } - }, - - stopListen: function() - { - if(this._listening) - { - this._window.removeEventListener("mousemove", this, true); - this._listening = false; - } - }, - - clearTimer: function() - { - if(this._timer != 0) - { - this._window.clearTimeout(this._timer); - this._timer = 0; - } - }, - - handleEvent: function(event) - { - switch(event.type) - { - case "mousemove": - this.clearTimer(); - this._showDelayed(); - } - }, - - _showDelayed: function() - { - let delay = ((this._pendingLink.link) - ? this._service.statusLinkOverDelayShow - : this._service.statusLinkOverDelayHide); - - this._timer = this._window.setTimeout(function(self) - { - self._timer = 0; - self._show(); - self.stopListen(); - }, delay, this); - }, - - _show: function() - { - this._currentLink = this._pendingLink; - this._statusService.setOverLinkInternal(this._currentLink.link, this._currentLink.anchor); - } + _window: null, + _service: null, + _statusService: null, + + _timer: 0, + _currentLink: { link: "", anchor: null }, + _pendingLink: { link: "", anchor: null }, + _listening: false, + + update: function(aLink, aAnchor) + { + this.clearTimer(); + this.stopListen(); + this._pendingLink = { link: aLink, anchor: aAnchor }; + + if(!aLink) + { + if(this._window.XULBrowserWindow.hideOverLinkImmediately || !this._service.statusLinkOverDelayHide) + { + this._show(); + } + else + { + this._showDelayed(); + } + } + else if(this._currentLink.link || !this._service.statusLinkOverDelayShow) + { + this._show(); + } + else + { + this._showDelayed(); + this.startListen(); + } + }, + + destroy: function() + { + this.clearTimer(); + this.stopListen(); + + ["_currentLink", "_pendingLink", "_statusService", "_window"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + startListen: function() + { + if(!this._listening) + { + this._window.addEventListener("mousemove", this, true); + this._listening = true; + } + }, + + stopListen: function() + { + if(this._listening) + { + this._window.removeEventListener("mousemove", this, true); + this._listening = false; + } + }, + + clearTimer: function() + { + if(this._timer != 0) + { + this._window.clearTimeout(this._timer); + this._timer = 0; + } + }, + + handleEvent: function(event) + { + switch(event.type) + { + case "mousemove": + this.clearTimer(); + this._showDelayed(); + } + }, + + _showDelayed: function() + { + let delay = ((this._pendingLink.link) + ? this._service.statusLinkOverDelayShow + : this._service.statusLinkOverDelayHide); + + this._timer = this._window.setTimeout(function(self) + { + self._timer = 0; + self._show(); + self.stopListen(); + }, delay, this); + }, + + _show: function() + { + this._currentLink = this._pendingLink; + this._statusService.setOverLinkInternal(this._currentLink.link, this._currentLink.anchor); + } }; diff --git a/application/palemoon/components/statusbar/Status4Evar.jsm b/application/palemoon/components/statusbar/Status4Evar.jsm index 03e899afc..055306a88 100644 --- a/application/palemoon/components/statusbar/Status4Evar.jsm +++ b/application/palemoon/components/statusbar/Status4Evar.jsm @@ -23,257 +23,257 @@ CU.import("resource:///modules/statusbar/Toolbars.jsm"); function Status4Evar(window, gBrowser, toolbox) { - this._window = window; - this._toolbox = toolbox; + this._window = window; + this._toolbox = toolbox; - this.getters = new S4EWindowGetters(this._window); - this.toolbars = new S4EToolbars(this._window, gBrowser, this._toolbox, s4e_service, this.getters); - this.statusService = new S4EStatusService(this._window, s4e_service, this.getters); - this.progressMeter = new S4EProgressService(gBrowser, s4e_service, this.getters, this.statusService); - this.downloadStatus = new S4EDownloadService(this._window, gBrowser, s4e_service, this.getters); - this.sizeModeService = new SizeModeService(this._window, this); + this.getters = new S4EWindowGetters(this._window); + this.toolbars = new S4EToolbars(this._window, gBrowser, this._toolbox, s4e_service, this.getters); + this.statusService = new S4EStatusService(this._window, s4e_service, this.getters); + this.progressMeter = new S4EProgressService(gBrowser, s4e_service, this.getters, this.statusService); + this.downloadStatus = new S4EDownloadService(this._window, gBrowser, s4e_service, this.getters); + this.sizeModeService = new SizeModeService(this._window, this); - this._window.addEventListener("unload", this, false); + this._window.addEventListener("unload", this, false); } Status4Evar.prototype = { - _window: null, - _toolbox: null, - - getters: null, - toolbars: null, - statusService: null, - progressMeter: null, - downloadStatus: null, - sizeModeService: null, - - setup: function() - { - this._toolbox.addEventListener("beforecustomization", this, false); - this._toolbox.addEventListener("aftercustomization", this, false); - - this.toolbars.setup(); - this.updateWindow(); - - // OMFG HAX! If a page is already loading, fake a network start event - if(this._window.XULBrowserWindow._busyUI) - { - let nsIWPL = CI.nsIWebProgressListener; - this.progressMeter.onStateChange(0, null, nsIWPL.STATE_START | nsIWPL.STATE_IS_NETWORK, 0); - } - }, - - destroy: function() - { - this._window.removeEventListener("unload", this, false); - this._toolbox.removeEventListener("aftercustomization", this, false); - this._toolbox.removeEventListener("beforecustomization", this, false); - - this.getters.destroy(); - this.statusService.destroy(); - this.downloadStatus.destroy(); - this.progressMeter.destroy(); - this.toolbars.destroy(); - this.sizeModeService.destroy(); - - ["_window", "_toolbox", "getters", "statusService", "downloadStatus", - "progressMeter", "toolbars", "sizeModeService"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - handleEvent: function(aEvent) - { - switch(aEvent.type) - { - case "unload": - this.destroy(); - break; - case "beforecustomization": - this.beforeCustomization(); - break; - case "aftercustomization": - this.updateWindow(); - break; - } - }, - - beforeCustomization: function() - { - this.toolbars.updateSplitters(false); - this.toolbars.updateWindowGripper(false); - - this.statusService.setNoUpdate(true); - let status_label = this.getters.statusWidgetLabel; - if(status_label) - { - status_label.value = this.getters.strings.getString("statusText"); - } - - this.downloadStatus.customizing(true); - }, - - updateWindow: function() - { - this.statusService.setNoUpdate(false); - this.getters.resetGetters(); - this.statusService.buildTextOrder(); - this.statusService.buildBinding(); - this.downloadStatus.init(); - this.downloadStatus.customizing(false); - this.toolbars.updateSplitters(true); - - s4e_service.updateWindow(this._window); - // This also handles the following: - // * buildTextOrder() - // * updateStatusField(true) - // * updateWindowGripper(true) - }, - - launchOptions: function(currentWindow) - { - let optionsURL = "chrome://browser/content/statusbar/prefs.xul"; - let windows = Services.wm.getEnumerator(null); - while (windows.hasMoreElements()) - { - let win = windows.getNext(); - if (win.document.documentURI == optionsURL) - { - win.focus(); - return; - } - } - - let features = "chrome,titlebar,toolbar,centerscreen"; - try - { - let instantApply = Services.prefs.getBoolPref("browser.preferences.instantApply"); - features += instantApply ? ",dialog=no" : ",modal"; - } - catch(e) - { - features += ",modal"; - } - currentWindow.openDialog(optionsURL, "", features); - } + _window: null, + _toolbox: null, + + getters: null, + toolbars: null, + statusService: null, + progressMeter: null, + downloadStatus: null, + sizeModeService: null, + + setup: function() + { + this._toolbox.addEventListener("beforecustomization", this, false); + this._toolbox.addEventListener("aftercustomization", this, false); + + this.toolbars.setup(); + this.updateWindow(); + + // OMFG HAX! If a page is already loading, fake a network start event + if(this._window.XULBrowserWindow._busyUI) + { + let nsIWPL = CI.nsIWebProgressListener; + this.progressMeter.onStateChange(0, null, nsIWPL.STATE_START | nsIWPL.STATE_IS_NETWORK, 0); + } + }, + + destroy: function() + { + this._window.removeEventListener("unload", this, false); + this._toolbox.removeEventListener("aftercustomization", this, false); + this._toolbox.removeEventListener("beforecustomization", this, false); + + this.getters.destroy(); + this.statusService.destroy(); + this.downloadStatus.destroy(); + this.progressMeter.destroy(); + this.toolbars.destroy(); + this.sizeModeService.destroy(); + + ["_window", "_toolbox", "getters", "statusService", "downloadStatus", + "progressMeter", "toolbars", "sizeModeService"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + handleEvent: function(aEvent) + { + switch(aEvent.type) + { + case "unload": + this.destroy(); + break; + case "beforecustomization": + this.beforeCustomization(); + break; + case "aftercustomization": + this.updateWindow(); + break; + } + }, + + beforeCustomization: function() + { + this.toolbars.updateSplitters(false); + this.toolbars.updateWindowGripper(false); + + this.statusService.setNoUpdate(true); + let status_label = this.getters.statusWidgetLabel; + if(status_label) + { + status_label.value = this.getters.strings.getString("statusText"); + } + + this.downloadStatus.customizing(true); + }, + + updateWindow: function() + { + this.statusService.setNoUpdate(false); + this.getters.resetGetters(); + this.statusService.buildTextOrder(); + this.statusService.buildBinding(); + this.downloadStatus.init(); + this.downloadStatus.customizing(false); + this.toolbars.updateSplitters(true); + + s4e_service.updateWindow(this._window); + // This also handles the following: + // * buildTextOrder() + // * updateStatusField(true) + // * updateWindowGripper(true) + }, + + launchOptions: function(currentWindow) + { + let optionsURL = "chrome://browser/content/statusbar/prefs.xul"; + let windows = Services.wm.getEnumerator(null); + while (windows.hasMoreElements()) + { + let win = windows.getNext(); + if (win.document.documentURI == optionsURL) + { + win.focus(); + return; + } + } + + let features = "chrome,titlebar,toolbar,centerscreen"; + try + { + let instantApply = Services.prefs.getBoolPref("browser.preferences.instantApply"); + features += instantApply ? ",dialog=no" : ",modal"; + } + catch(e) + { + features += ",modal"; + } + currentWindow.openDialog(optionsURL, "", features); + } }; function S4EWindowGetters(window) { - this._window = window; + this._window = window; } S4EWindowGetters.prototype = { - _window: null, - _getterMap: - [ - ["addonbar", "addon-bar"], - ["addonbarCloseButton", "addonbar-closebutton"], - ["browserBottomBox", "browser-bottombox"], - ["downloadButton", "status4evar-download-button"], - ["downloadButtonTooltip", "status4evar-download-tooltip"], - ["downloadButtonProgress", "status4evar-download-progress-bar"], - ["downloadButtonLabel", "status4evar-download-label"], - ["downloadButtonAnchor", "status4evar-download-anchor"], - ["downloadNotifyAnchor", "status4evar-download-notification-anchor"], - ["statusBar", "status4evar-status-bar"], - ["statusWidget", "status4evar-status-widget"], - ["statusWidgetLabel", "status4evar-status-text"], - ["strings", "bundle_status4evar"], - ["throbberProgress", "status4evar-throbber-widget"], - ["toolbarProgress", "status4evar-progress-bar"] - ], - - resetGetters: function() - { - let document = this._window.document; - - this._getterMap.forEach(function(getter) - { - let [prop, id] = getter; - delete this[prop]; - this.__defineGetter__(prop, function() - { - delete this[prop]; - return this[prop] = document.getElementById(id); - }); - }, this); - - delete this.statusOverlay; - this.__defineGetter__("statusOverlay", function() - { - let so = this._window.XULBrowserWindow.statusTextField; - if(!so) - { - return null; - } - - delete this.statusOverlay; - return this.statusOverlay = so; - }); - }, - - destroy: function() - { - this._getterMap.forEach(function(getter) - { - let [prop, id] = getter; - delete this[prop]; - }, this); - - ["statusOverlay", "statusOverlay", "_window"].forEach(function(prop) - { - delete this[prop]; - }, this); - } + _window: null, + _getterMap: + [ + ["addonbar", "addon-bar"], + ["addonbarCloseButton", "addonbar-closebutton"], + ["browserBottomBox", "browser-bottombox"], + ["downloadButton", "status4evar-download-button"], + ["downloadButtonTooltip", "status4evar-download-tooltip"], + ["downloadButtonProgress", "status4evar-download-progress-bar"], + ["downloadButtonLabel", "status4evar-download-label"], + ["downloadButtonAnchor", "status4evar-download-anchor"], + ["downloadNotifyAnchor", "status4evar-download-notification-anchor"], + ["statusBar", "status4evar-status-bar"], + ["statusWidget", "status4evar-status-widget"], + ["statusWidgetLabel", "status4evar-status-text"], + ["strings", "bundle_status4evar"], + ["throbberProgress", "status4evar-throbber-widget"], + ["toolbarProgress", "status4evar-progress-bar"] + ], + + resetGetters: function() + { + let document = this._window.document; + + this._getterMap.forEach(function(getter) + { + let [prop, id] = getter; + delete this[prop]; + this.__defineGetter__(prop, function() + { + delete this[prop]; + return this[prop] = document.getElementById(id); + }); + }, this); + + delete this.statusOverlay; + this.__defineGetter__("statusOverlay", function() + { + let so = this._window.XULBrowserWindow.statusTextField; + if(!so) + { + return null; + } + + delete this.statusOverlay; + return this.statusOverlay = so; + }); + }, + + destroy: function() + { + this._getterMap.forEach(function(getter) + { + let [prop, id] = getter; + delete this[prop]; + }, this); + + ["statusOverlay", "statusOverlay", "_window"].forEach(function(prop) + { + delete this[prop]; + }, this); + } }; function SizeModeService(window, s4e) { - this._window = window; - this._s4e = s4e; + this._window = window; + this._s4e = s4e; - this.lastFullScreen = this._window.fullScreen; - this.lastwindowState = this._window.windowState; - this._window.addEventListener("sizemodechange", this, false); + this.lastFullScreen = this._window.fullScreen; + this.lastwindowState = this._window.windowState; + this._window.addEventListener("sizemodechange", this, false); } SizeModeService.prototype = { - _window: null, - _s4e: null, - - lastFullScreen: null, - lastwindowState: null, - - destroy: function() - { - this._window.removeEventListener("sizemodechange", this, false); - - ["_window", "_s4e"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - handleEvent: function(e) - { - if(this._window.fullScreen != this.lastFullScreen) - { - this.lastFullScreen = this._window.fullScreen; - this._s4e.statusService.updateFullScreen(); - } - - if(this._window.windowState != this.lastwindowState) - { - this.lastwindowState = this._window.windowState; - this._s4e.toolbars.updateWindowGripper(true); - } - }, - - QueryInterface: XPCOMUtils.generateQI([ CI.nsIDOMEventListener ]) + _window: null, + _s4e: null, + + lastFullScreen: null, + lastwindowState: null, + + destroy: function() + { + this._window.removeEventListener("sizemodechange", this, false); + + ["_window", "_s4e"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + handleEvent: function(e) + { + if(this._window.fullScreen != this.lastFullScreen) + { + this.lastFullScreen = this._window.fullScreen; + this._s4e.statusService.updateFullScreen(); + } + + if(this._window.windowState != this.lastwindowState) + { + this.lastwindowState = this._window.windowState; + this._s4e.toolbars.updateWindowGripper(true); + } + }, + + QueryInterface: XPCOMUtils.generateQI([ CI.nsIDOMEventListener ]) }; diff --git a/application/palemoon/components/statusbar/Toolbars.jsm b/application/palemoon/components/statusbar/Toolbars.jsm index dda8565fd..321efd092 100644 --- a/application/palemoon/components/statusbar/Toolbars.jsm +++ b/application/palemoon/components/statusbar/Toolbars.jsm @@ -13,209 +13,209 @@ CU.import("resource://gre/modules/Services.jsm"); function S4EToolbars(window, gBrowser, toolbox, service, getters) { - this._window = window; - this._toolbox = toolbox; - this._service = service; - this._getters = getters; - this._handler = new ClassicS4EToolbars(this._window, this._toolbox); + this._window = window; + this._toolbox = toolbox; + this._service = service; + this._getters = getters; + this._handler = new ClassicS4EToolbars(this._window, this._toolbox); } S4EToolbars.prototype = { - _window: null, - _toolbox: null, - _service: null, - _getters: null, - - _handler: null, - - setup: function() - { - this.updateSplitters(false); - this.updateWindowGripper(false); - this._handler.setup(this._service.firstRun); - }, - - destroy: function() - { - this._handler.destroy(); - - ["_window", "_toolbox", "_service", "_getters", "_handler"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - updateSplitters: function(action) - { - let document = this._window.document; - - let splitter_before = document.getElementById("status4evar-status-splitter-before"); - if(splitter_before) - { - splitter_before.parentNode.removeChild(splitter_before); - } - - let splitter_after = document.getElementById("status4evar-status-splitter-after"); - if(splitter_after) - { - splitter_after.parentNode.removeChild(splitter_after); - } - - let status = this._getters.statusWidget; - if(!action || !status) - { - return; - } - - let urlbar = document.getElementById("urlbar-container"); - let stop = document.getElementById("stop-button"); - let fullscreenflex = document.getElementById("fullscreenflex"); - - let nextSibling = status.nextSibling; - let previousSibling = status.previousSibling; - - function getSplitter(splitter, suffix) - { - if(!splitter) - { - splitter = document.createElement("splitter"); - splitter.id = "status4evar-status-splitter-" + suffix; - splitter.setAttribute("resizebefore", "flex"); - splitter.setAttribute("resizeafter", "flex"); - splitter.className = "chromeclass-toolbar-additional status4evar-status-splitter"; - } - return splitter; - } - - if((previousSibling && previousSibling.flex > 0) - || (urlbar && stop && urlbar.getAttribute("combined") && stop == previousSibling)) - { - status.parentNode.insertBefore(getSplitter(splitter_before, "before"), status); - } - - if(nextSibling && nextSibling.flex > 0 && nextSibling != fullscreenflex) - { - status.parentNode.insertBefore(getSplitter(splitter_after, "after"), nextSibling); - } - }, - - updateWindowGripper: function(action) - { - let document = this._window.document; - - let gripper = document.getElementById("status4evar-window-gripper"); - let toolbar = this._getters.statusBar || this._getters.addonbar; - - if(!action || !toolbar || !this._service.addonbarWindowGripper - || this._window.windowState != CI.nsIDOMChromeWindow.STATE_NORMAL || toolbar.toolbox.customizing) - { - if(gripper) - { - gripper.parentNode.removeChild(gripper); - } - return; - } - - gripper = this._handler.buildGripper(toolbar, gripper, "status4evar-window-gripper"); - - toolbar.appendChild(gripper); - } + _window: null, + _toolbox: null, + _service: null, + _getters: null, + + _handler: null, + + setup: function() + { + this.updateSplitters(false); + this.updateWindowGripper(false); + this._handler.setup(this._service.firstRun); + }, + + destroy: function() + { + this._handler.destroy(); + + ["_window", "_toolbox", "_service", "_getters", "_handler"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + updateSplitters: function(action) + { + let document = this._window.document; + + let splitter_before = document.getElementById("status4evar-status-splitter-before"); + if(splitter_before) + { + splitter_before.parentNode.removeChild(splitter_before); + } + + let splitter_after = document.getElementById("status4evar-status-splitter-after"); + if(splitter_after) + { + splitter_after.parentNode.removeChild(splitter_after); + } + + let status = this._getters.statusWidget; + if(!action || !status) + { + return; + } + + let urlbar = document.getElementById("urlbar-container"); + let stop = document.getElementById("stop-button"); + let fullscreenflex = document.getElementById("fullscreenflex"); + + let nextSibling = status.nextSibling; + let previousSibling = status.previousSibling; + + function getSplitter(splitter, suffix) + { + if(!splitter) + { + splitter = document.createElement("splitter"); + splitter.id = "status4evar-status-splitter-" + suffix; + splitter.setAttribute("resizebefore", "flex"); + splitter.setAttribute("resizeafter", "flex"); + splitter.className = "chromeclass-toolbar-additional status4evar-status-splitter"; + } + return splitter; + } + + if((previousSibling && previousSibling.flex > 0) + || (urlbar && stop && urlbar.getAttribute("combined") && stop == previousSibling)) + { + status.parentNode.insertBefore(getSplitter(splitter_before, "before"), status); + } + + if(nextSibling && nextSibling.flex > 0 && nextSibling != fullscreenflex) + { + status.parentNode.insertBefore(getSplitter(splitter_after, "after"), nextSibling); + } + }, + + updateWindowGripper: function(action) + { + let document = this._window.document; + + let gripper = document.getElementById("status4evar-window-gripper"); + let toolbar = this._getters.statusBar || this._getters.addonbar; + + if(!action || !toolbar || !this._service.addonbarWindowGripper + || this._window.windowState != CI.nsIDOMChromeWindow.STATE_NORMAL || toolbar.toolbox.customizing) + { + if(gripper) + { + gripper.parentNode.removeChild(gripper); + } + return; + } + + gripper = this._handler.buildGripper(toolbar, gripper, "status4evar-window-gripper"); + + toolbar.appendChild(gripper); + } }; function ClassicS4EToolbars(window, toolbox) { - this._window = window; - this._toolbox = toolbox; + this._window = window; + this._toolbox = toolbox; } ClassicS4EToolbars.prototype = { - _window: null, - _toolbox: null, - - setup: function(firstRun) - { - let document = this._window.document; - - let addon_bar = document.getElementById("addon-bar"); - if(addon_bar) - { - let baseSet = "addonbar-closebutton" - + ",status4evar-status-widget" - + ",status4evar-progress-widget"; - - // Update the defaultSet - let defaultSet = baseSet; - let defaultSetIgnore = ["addonbar-closebutton", "spring", "status-bar"]; - addon_bar.getAttribute("defaultset").split(",").forEach(function(item) - { - if(defaultSetIgnore.indexOf(item) == -1) - { - defaultSet += "," + item; - } - }); - defaultSet += ",status-bar" - addon_bar.setAttribute("defaultset", defaultSet); - - // Update the currentSet - if(firstRun) - { - let isCustomizableToolbar = function(aElt) - { - return aElt.localName == "toolbar" && aElt.getAttribute("customizable") == "true"; - } - - let isCustomizedAlready = false; - let toolbars = Array.filter(this._toolbox.childNodes, isCustomizableToolbar).concat( - Array.filter(this._toolbox.externalToolbars, isCustomizableToolbar)); - toolbars.forEach(function(toolbar) - { - if(toolbar.currentSet.indexOf("status4evar") > -1) - { - isCustomizedAlready = true; - } - }); - - if(!isCustomizedAlready) - { - let currentSet = baseSet; - let currentSetIgnore = ["addonbar-closebutton", "spring"]; - addon_bar.currentSet.split(",").forEach(function(item) - { - if(currentSetIgnore.indexOf(item) == -1) - { - currentSet += "," + item; - } - }); - addon_bar.currentSet = currentSet; - addon_bar.setAttribute("currentset", currentSet); - document.persist(addon_bar.id, "currentset"); - this._window.setToolbarVisibility(addon_bar, true); - } - } - } - }, - - destroy: function() - { - ["_window", "_toolbox"].forEach(function(prop) - { - delete this[prop]; - }, this); - }, - - buildGripper: function(toolbar, gripper, id) - { - if(!gripper) - { - let document = this._window.document; - - gripper = document.createElement("resizer"); - gripper.id = id; - gripper.dir = "bottomend"; - } - - return gripper; - } + _window: null, + _toolbox: null, + + setup: function(firstRun) + { + let document = this._window.document; + + let addon_bar = document.getElementById("addon-bar"); + if(addon_bar) + { + let baseSet = "addonbar-closebutton" + + ",status4evar-status-widget" + + ",status4evar-progress-widget"; + + // Update the defaultSet + let defaultSet = baseSet; + let defaultSetIgnore = ["addonbar-closebutton", "spring", "status-bar"]; + addon_bar.getAttribute("defaultset").split(",").forEach(function(item) + { + if(defaultSetIgnore.indexOf(item) == -1) + { + defaultSet += "," + item; + } + }); + defaultSet += ",status-bar" + addon_bar.setAttribute("defaultset", defaultSet); + + // Update the currentSet + if(firstRun) + { + let isCustomizableToolbar = function(aElt) + { + return aElt.localName == "toolbar" && aElt.getAttribute("customizable") == "true"; + } + + let isCustomizedAlready = false; + let toolbars = Array.filter(this._toolbox.childNodes, isCustomizableToolbar).concat( + Array.filter(this._toolbox.externalToolbars, isCustomizableToolbar)); + toolbars.forEach(function(toolbar) + { + if(toolbar.currentSet.indexOf("status4evar") > -1) + { + isCustomizedAlready = true; + } + }); + + if(!isCustomizedAlready) + { + let currentSet = baseSet; + let currentSetIgnore = ["addonbar-closebutton", "spring"]; + addon_bar.currentSet.split(",").forEach(function(item) + { + if(currentSetIgnore.indexOf(item) == -1) + { + currentSet += "," + item; + } + }); + addon_bar.currentSet = currentSet; + addon_bar.setAttribute("currentset", currentSet); + document.persist(addon_bar.id, "currentset"); + this._window.setToolbarVisibility(addon_bar, true); + } + } + } + }, + + destroy: function() + { + ["_window", "_toolbox"].forEach(function(prop) + { + delete this[prop]; + }, this); + }, + + buildGripper: function(toolbar, gripper, id) + { + if(!gripper) + { + let document = this._window.document; + + gripper = document.createElement("resizer"); + gripper.id = id; + gripper.dir = "bottomend"; + } + + return gripper; + } }; diff --git a/application/palemoon/components/statusbar/content/overlay.css b/application/palemoon/components/statusbar/content/overlay.css index 6375b8ef8..fd3452119 100644 --- a/application/palemoon/components/statusbar/content/overlay.css +++ b/application/palemoon/components/statusbar/content/overlay.css @@ -8,8 +8,7 @@ * Status Popup */ -statuspanel -{ - -moz-binding: url("chrome://browser/content/statusbar/tabbrowser.xml#statuspanel"); +statuspanel { + -moz-binding: url("chrome://browser/content/statusbar/tabbrowser.xml#statuspanel"); } diff --git a/application/palemoon/components/statusbar/content/overlay.js b/application/palemoon/components/statusbar/content/overlay.js index cf6cfe296..b868aaf0e 100644 --- a/application/palemoon/components/statusbar/content/overlay.js +++ b/application/palemoon/components/statusbar/content/overlay.js @@ -6,11 +6,11 @@ if(!caligon) var caligon = {}; window.addEventListener("load", function buildS4E() { - window.removeEventListener("load", buildS4E, false); + window.removeEventListener("load", buildS4E, false); - Components.utils.import("resource:///modules/statusbar/Status4Evar.jsm"); + Components.utils.import("resource:///modules/statusbar/Status4Evar.jsm"); - caligon.status4evar = new Status4Evar(window, gBrowser, gNavToolbox); - caligon.status4evar.setup(); + caligon.status4evar = new Status4Evar(window, gBrowser, gNavToolbox); + caligon.status4evar.setup(); }, false); diff --git a/application/palemoon/components/statusbar/content/overlay.xul b/application/palemoon/components/statusbar/content/overlay.xul index f9a61a92e..b9934ee65 100644 --- a/application/palemoon/components/statusbar/content/overlay.xul +++ b/application/palemoon/components/statusbar/content/overlay.xul @@ -13,23 +13,23 @@ <overlay id="status4evar-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - <stringbundleset id="stringbundleset"> - <stringbundle id="bundle_status4evar" src="chrome://browser/locale/statusbar/overlay.properties" /> - </stringbundleset> + <stringbundleset id="stringbundleset"> + <stringbundle id="bundle_status4evar" src="chrome://browser/locale/statusbar/overlay.properties" /> + </stringbundleset> - <script type="application/javascript" src="chrome://browser/content/statusbar/overlay.js" /> + <script type="application/javascript" src="chrome://browser/content/statusbar/overlay.js" /> - <commandset> - <command id="S4E:Options" oncommand="caligon.status4evar.launchOptions(window);"/> - </commandset> + <commandset> + <command id="S4E:Options" oncommand="caligon.status4evar.launchOptions(window);"/> + </commandset> - <popupset id="mainPopupSet"> - <hbox id="status4evar-download-notification-container" mousethrough="always"> - <vbox id="status4evar-download-notification-anchor"> - <vbox id="status4evar-download-notification-icon" /> - </vbox> - </hbox> - </popupset> + <popupset id="mainPopupSet"> + <hbox id="status4evar-download-notification-container" mousethrough="always"> + <vbox id="status4evar-download-notification-anchor"> + <vbox id="status4evar-download-notification-icon" /> + </vbox> + </hbox> + </popupset> <menupopup id="menu_ToolsPopup"> <menuitem id="statusbar-options-fx" command="S4E:Options" @@ -41,41 +41,41 @@ label="&status4evar.menu.options.label;"/> </menupopup> - <toolbarpalette id="BrowserToolbarPalette"> - <toolbaritem id="status4evar-status-widget" - title="&status4evar.status.widget.title;" - removable="true" flex="1" persist="width" width="100"> - <label id="status4evar-status-text" flex="1" crop="end" value="&status4evar.status.widget.title;" /> - </toolbaritem> + <toolbarpalette id="BrowserToolbarPalette"> + <toolbaritem id="status4evar-status-widget" + title="&status4evar.status.widget.title;" + removable="true" flex="1" persist="width" width="100"> + <label id="status4evar-status-text" flex="1" crop="end" value="&status4evar.status.widget.title;" /> + </toolbaritem> - <toolbarbutton id="status4evar-download-button" - title="&status4evar.download.widget.title;" - class="toolbarbutton-1 chromeclass-toolbar-additional" - removable="true" collapsed="true" tooltip="_child" - oncommand="caligon.status4evar.downloadStatus.openUI(event)"> - <stack id="status4evar-download-anchor" class="toolbarbutton-icon"> - <vbox id="status4evar-download-icon" /> - <vbox pack="end"> - <progressmeter id="status4evar-download-progress-bar" mode="normal" value="0" collapsed="true" min="0" max="100" /> - </vbox> - </stack> - <tooltip id="status4evar-download-tooltip" /> - <label id="status4evar-download-label" value="&status4evar.download.widget.title;" class="toolbarbutton-text" crop="right" flex="1" /> - </toolbarbutton> + <toolbarbutton id="status4evar-download-button" + title="&status4evar.download.widget.title;" + class="toolbarbutton-1 chromeclass-toolbar-additional" + removable="true" collapsed="true" tooltip="_child" + oncommand="caligon.status4evar.downloadStatus.openUI(event)"> + <stack id="status4evar-download-anchor" class="toolbarbutton-icon"> + <vbox id="status4evar-download-icon" /> + <vbox pack="end"> + <progressmeter id="status4evar-download-progress-bar" mode="normal" value="0" collapsed="true" min="0" max="100" /> + </vbox> + </stack> + <tooltip id="status4evar-download-tooltip" /> + <label id="status4evar-download-label" value="&status4evar.download.widget.title;" class="toolbarbutton-text" crop="right" flex="1" /> + </toolbarbutton> - <toolbaritem id="status4evar-progress-widget" - title="&status4evar.progress.widget.title;" - removable="true"> - <progressmeter id="status4evar-progress-bar" class="progressmeter-statusbar" - mode="normal" value="0" collapsed="true" min="0" max="100" /> - </toolbaritem> + <toolbaritem id="status4evar-progress-widget" + title="&status4evar.progress.widget.title;" + removable="true"> + <progressmeter id="status4evar-progress-bar" class="progressmeter-statusbar" + mode="normal" value="0" collapsed="true" min="0" max="100" /> + </toolbaritem> - <toolbarbutton id="status4evar-options-button" - title="&status4evar.options.widget.title;" - class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&status4evar.options.widget.label;" - removable="true" command="S4E:Options" tooltiptext="&status4evar.options.widget.title;" /> - </toolbarpalette> + <toolbarbutton id="status4evar-options-button" + title="&status4evar.options.widget.title;" + class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&status4evar.options.widget.label;" + removable="true" command="S4E:Options" tooltiptext="&status4evar.options.widget.title;" /> + </toolbarpalette> <statusbar id="status-bar" ordinal="1" /> </overlay> diff --git a/application/palemoon/components/statusbar/content/prefs.css b/application/palemoon/components/statusbar/content/prefs.css index c627f78fb..bafaa6129 100644 --- a/application/palemoon/components/statusbar/content/prefs.css +++ b/application/palemoon/components/statusbar/content/prefs.css @@ -4,8 +4,7 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); -.css-bg-editor -{ - -moz-binding: url("chrome://browser/content/statusbar/prefs.xml#css-bg-editor"); +.css-bg-editor { + -moz-binding: url("chrome://browser/content/statusbar/prefs.xml#css-bg-editor"); } diff --git a/application/palemoon/components/statusbar/content/prefs.js b/application/palemoon/components/statusbar/content/prefs.js index ed81fb271..47fd4b63d 100644 --- a/application/palemoon/components/statusbar/content/prefs.js +++ b/application/palemoon/components/statusbar/content/prefs.js @@ -6,267 +6,267 @@ Components.utils.import("resource://gre/modules/Services.jsm"); var status4evarPrefs = { - get dynamicProgressStyle() - { - let styleSheets = window.document.styleSheets; - for(let i = 0; i < styleSheets.length; i++) - { - let styleSheet = styleSheets[i]; - if(styleSheet.href == "chrome://browser/skin/statusbar/dynamic.css") - { - delete this.dynamicProgressStyle; - return this.dynamicProgressStyle = styleSheet; - } - } - - return null; - }, + get dynamicProgressStyle() + { + let styleSheets = window.document.styleSheets; + for(let i = 0; i < styleSheets.length; i++) + { + let styleSheet = styleSheets[i]; + if(styleSheet.href == "chrome://browser/skin/statusbar/dynamic.css") + { + delete this.dynamicProgressStyle; + return this.dynamicProgressStyle = styleSheet; + } + } + + return null; + }, // // Status timeout management // - get statusTimeoutPref() - { - delete this.statusTimeoutPref; - return this.statusTimeoutPref = document.getElementById("status4evar-pref-status-timeout"); - }, - - get statusTimeoutCheckbox() - { - delete this.statusTimeoutCheckbox; - return this.statusTimeoutCheckbox = document.getElementById("status4evar-status-timeout-check"); - }, - - statusTimeoutChanged: function() - { - if(this.statusTimeoutPref.value > 0) - { - this.statusTimeoutPref.disabled = false; - this.statusTimeoutCheckbox.checked = true; - } - else - { - this.statusTimeoutPref.disabled = true; - this.statusTimeoutCheckbox.checked = false; - } - }, - - statusTimeoutSync: function() - { - this.statusTimeoutChanged(); - return undefined; - }, - - statusTimeoutToggle: function() - { - if(this.statusTimeoutPref.disabled == this.statusTimeoutCheckbox.checked) - { - if(this.statusTimeoutCheckbox.checked) - { - this.statusTimeoutPref.value = 10; - } - else - { - this.statusTimeoutPref.value = 0; - } - } - }, + get statusTimeoutPref() + { + delete this.statusTimeoutPref; + return this.statusTimeoutPref = document.getElementById("status4evar-pref-status-timeout"); + }, + + get statusTimeoutCheckbox() + { + delete this.statusTimeoutCheckbox; + return this.statusTimeoutCheckbox = document.getElementById("status4evar-status-timeout-check"); + }, + + statusTimeoutChanged: function() + { + if(this.statusTimeoutPref.value > 0) + { + this.statusTimeoutPref.disabled = false; + this.statusTimeoutCheckbox.checked = true; + } + else + { + this.statusTimeoutPref.disabled = true; + this.statusTimeoutCheckbox.checked = false; + } + }, + + statusTimeoutSync: function() + { + this.statusTimeoutChanged(); + return undefined; + }, + + statusTimeoutToggle: function() + { + if(this.statusTimeoutPref.disabled == this.statusTimeoutCheckbox.checked) + { + if(this.statusTimeoutCheckbox.checked) + { + this.statusTimeoutPref.value = 10; + } + else + { + this.statusTimeoutPref.value = 0; + } + } + }, // // Status network management // - get statusNetworkPref() - { - delete this.statusNetworkPref; - return this.statusNetworkPref = document.getElementById("status4evar-pref-status-network"); - }, - - get statusNetworkXHRPref() - { - delete this.statusNetworkXHRPref; - return this.statusNetworkXHRPref = document.getElementById("status4evar-pref-status-network-xhr"); - }, - - statusNetworkChanged: function() - { - this.statusNetworkXHRPref.disabled = ! this.statusNetworkPref.value; - }, - - statusNetworkSync: function() - { - this.statusNetworkChanged(); - return undefined; - }, + get statusNetworkPref() + { + delete this.statusNetworkPref; + return this.statusNetworkPref = document.getElementById("status4evar-pref-status-network"); + }, + + get statusNetworkXHRPref() + { + delete this.statusNetworkXHRPref; + return this.statusNetworkXHRPref = document.getElementById("status4evar-pref-status-network-xhr"); + }, + + statusNetworkChanged: function() + { + this.statusNetworkXHRPref.disabled = ! this.statusNetworkPref.value; + }, + + statusNetworkSync: function() + { + this.statusNetworkChanged(); + return undefined; + }, // // Status Text langth managment // - get textMaxLengthPref() - { - delete this.textMaxLengthPref; - return this.textMaxLengthPref = document.getElementById("status4evar-pref-status-toolbar-maxLength"); - }, - - get textMaxLengthCheckbox() - { - delete this.textMaxLengthCheckbox; - return this.textMaxLengthCheckbox = document.getElementById("status4evar-status-toolbar-maxLength-check"); - }, - - textLengthChanged: function() - { - if(this.textMaxLengthPref.value > 0) - { - this.textMaxLengthPref.disabled = false; - this.textMaxLengthCheckbox.checked = true; - } - else - { - this.textMaxLengthPref.disabled = true; - this.textMaxLengthCheckbox.checked = false; - } - }, - - textLengthSync: function() - { - this.textLengthChanged(); - return undefined; - }, - - textLengthToggle: function() - { - if(this.textMaxLengthPref.disabled == this.textMaxLengthCheckbox.checked) - { - if(this.textMaxLengthCheckbox.checked) - { - this.textMaxLengthPref.value = 800; - } - else - { - this.textMaxLengthPref.value = 0; - } - } - }, + get textMaxLengthPref() + { + delete this.textMaxLengthPref; + return this.textMaxLengthPref = document.getElementById("status4evar-pref-status-toolbar-maxLength"); + }, + + get textMaxLengthCheckbox() + { + delete this.textMaxLengthCheckbox; + return this.textMaxLengthCheckbox = document.getElementById("status4evar-status-toolbar-maxLength-check"); + }, + + textLengthChanged: function() + { + if(this.textMaxLengthPref.value > 0) + { + this.textMaxLengthPref.disabled = false; + this.textMaxLengthCheckbox.checked = true; + } + else + { + this.textMaxLengthPref.disabled = true; + this.textMaxLengthCheckbox.checked = false; + } + }, + + textLengthSync: function() + { + this.textLengthChanged(); + return undefined; + }, + + textLengthToggle: function() + { + if(this.textMaxLengthPref.disabled == this.textMaxLengthCheckbox.checked) + { + if(this.textMaxLengthCheckbox.checked) + { + this.textMaxLengthPref.value = 800; + } + else + { + this.textMaxLengthPref.value = 0; + } + } + }, // // Toolbar progress style management // - get progressToolbarStylePref() - { - delete this.progressToolbarStylePref; - return this.progressToolbarStylePref = document.getElementById("status4evar-pref-progress-toolbar-style"); - }, - - get progressToolbarCSSPref() - { - delete this.progressToolbarCSSPref; - return this.progressToolbarCSSPref = document.getElementById("status4evar-pref-progress-toolbar-css"); - }, - - get progressToolbarProgress() - { - delete this.progressToolbarProgress; - return this.progressToolbarProgress = document.getElementById("status4evar-progress-bar"); - }, - - progressToolbarCSSChanged: function() - { - if(!this.progressToolbarCSSPref.value) - { - this.progressToolbarCSSPref.value = "#33FF33"; - } - this.dynamicProgressStyle.cssRules[1].style.background = this.progressToolbarCSSPref.value; - }, - - progressToolbarStyleChanged: function() - { - this.progressToolbarCSSChanged(); - this.progressToolbarCSSPref.disabled = !this.progressToolbarStylePref.value; - if(this.progressToolbarStylePref.value) - { - this.progressToolbarProgress.setAttribute("s4estyle", true); - } - else - { - this.progressToolbarProgress.removeAttribute("s4estyle"); - } - }, - - progressToolbarStyleSync: function() - { - this.progressToolbarStyleChanged(); - return undefined; - }, + get progressToolbarStylePref() + { + delete this.progressToolbarStylePref; + return this.progressToolbarStylePref = document.getElementById("status4evar-pref-progress-toolbar-style"); + }, + + get progressToolbarCSSPref() + { + delete this.progressToolbarCSSPref; + return this.progressToolbarCSSPref = document.getElementById("status4evar-pref-progress-toolbar-css"); + }, + + get progressToolbarProgress() + { + delete this.progressToolbarProgress; + return this.progressToolbarProgress = document.getElementById("status4evar-progress-bar"); + }, + + progressToolbarCSSChanged: function() + { + if(!this.progressToolbarCSSPref.value) + { + this.progressToolbarCSSPref.value = "#33FF33"; + } + this.dynamicProgressStyle.cssRules[1].style.background = this.progressToolbarCSSPref.value; + }, + + progressToolbarStyleChanged: function() + { + this.progressToolbarCSSChanged(); + this.progressToolbarCSSPref.disabled = !this.progressToolbarStylePref.value; + if(this.progressToolbarStylePref.value) + { + this.progressToolbarProgress.setAttribute("s4estyle", true); + } + else + { + this.progressToolbarProgress.removeAttribute("s4estyle"); + } + }, + + progressToolbarStyleSync: function() + { + this.progressToolbarStyleChanged(); + return undefined; + }, // // Download progress management // - get downloadProgressCheck() - { - delete this.downloadProgressCheck; - return this.downloadProgressCheck = document.getElementById("status4evar-download-progress-check"); - }, - - get downloadProgressPref() - { - delete this.downloadProgressPref; - return this.downloadProgressPref = document.getElementById("status4evar-pref-download-progress"); - }, - - get downloadProgressColorActivePref() - { - delete this.downloadProgressActiveColorPref; - return this.downloadProgressActiveColorPref = document.getElementById("status4evar-pref-download-color-active"); - }, - - get downloadProgressColorPausedPref() - { - delete this.downloadProgressPausedColorPref; - return this.downloadProgressPausedColorPref = document.getElementById("status4evar-pref-download-color-paused"); - }, - - downloadProgressSync: function() - { - let val = this.downloadProgressPref.value; - this.downloadProgressColorActivePref.disabled = (val == 0); - this.downloadProgressColorPausedPref.disabled = (val == 0); - this.downloadProgressPref.disabled = (val == 0); - this.downloadProgressCheck.checked = (val != 0); - return ((val == 0) ? 1 : val); - }, - - downloadProgressToggle: function() - { - let enabled = this.downloadProgressCheck.checked; - this.downloadProgressPref.value = ((enabled) ? 1 : 0); - }, + get downloadProgressCheck() + { + delete this.downloadProgressCheck; + return this.downloadProgressCheck = document.getElementById("status4evar-download-progress-check"); + }, + + get downloadProgressPref() + { + delete this.downloadProgressPref; + return this.downloadProgressPref = document.getElementById("status4evar-pref-download-progress"); + }, + + get downloadProgressColorActivePref() + { + delete this.downloadProgressActiveColorPref; + return this.downloadProgressActiveColorPref = document.getElementById("status4evar-pref-download-color-active"); + }, + + get downloadProgressColorPausedPref() + { + delete this.downloadProgressPausedColorPref; + return this.downloadProgressPausedColorPref = document.getElementById("status4evar-pref-download-color-paused"); + }, + + downloadProgressSync: function() + { + let val = this.downloadProgressPref.value; + this.downloadProgressColorActivePref.disabled = (val == 0); + this.downloadProgressColorPausedPref.disabled = (val == 0); + this.downloadProgressPref.disabled = (val == 0); + this.downloadProgressCheck.checked = (val != 0); + return ((val == 0) ? 1 : val); + }, + + downloadProgressToggle: function() + { + let enabled = this.downloadProgressCheck.checked; + this.downloadProgressPref.value = ((enabled) ? 1 : 0); + }, // // Pref Window load // - get downloadButtonActionCommandPref() - { - delete this.downloadButtonActionCommandPref; - return this.downloadButtonActionCommandPref = document.getElementById("status4evar-pref-download-button-action-command"); - }, - - get downloadButtonActionThirdPartyItem() - { - delete this.downloadButtonActionThirdPartyItem; - return this.downloadButtonActionThirdPartyItem = document.getElementById("status4evar-download-button-action-menu-thirdparty"); - }, - - onPrefWindowLoad: function() - { - if(!this.downloadButtonActionCommandPref.value) - { - this.downloadButtonActionThirdPartyItem.disabled = true; - } - }, - - onPrefWindowUnLoad: function() - { - } + get downloadButtonActionCommandPref() + { + delete this.downloadButtonActionCommandPref; + return this.downloadButtonActionCommandPref = document.getElementById("status4evar-pref-download-button-action-command"); + }, + + get downloadButtonActionThirdPartyItem() + { + delete this.downloadButtonActionThirdPartyItem; + return this.downloadButtonActionThirdPartyItem = document.getElementById("status4evar-download-button-action-menu-thirdparty"); + }, + + onPrefWindowLoad: function() + { + if(!this.downloadButtonActionCommandPref.value) + { + this.downloadButtonActionThirdPartyItem.disabled = true; + } + }, + + onPrefWindowUnLoad: function() + { + } } var XULBrowserWindow = { diff --git a/application/palemoon/components/statusbar/content/prefs.xml b/application/palemoon/components/statusbar/content/prefs.xml index cf4a00bb8..44baab18d 100644 --- a/application/palemoon/components/statusbar/content/prefs.xml +++ b/application/palemoon/components/statusbar/content/prefs.xml @@ -11,694 +11,694 @@ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl"> - <binding id="css-bg-editor"> - <content sizetopopup="pref"> - <xul:vbox flex="1"> - <xul:deck anonid="css-bg-editor-deck" flex="1"> - <xul:vbox> - <xul:hbox align="center"> - <xul:label xbl:inherits="disabled">&status4evar.editor.css.color.label;</xul:label> - <xul:colorpicker anonid="css-bg-editor-color" type="button" onchange="this._editor._buildCSS();" xbl:inherits="disabled" /> - </xul:hbox> - - <xul:hbox align="center"> - <xul:label xbl:inherits="disabled">&status4evar.editor.css.image.label;</xul:label> - <xul:textbox anonid="css-bg-editor-image" readonly="true" flex="1" xbl:inherits="disabled" /> - <xul:button anonid="css-bg-editor-image-browse" label="&status4evar.option.browse;" oncommand="this._editor._imageBrowse();" xbl:inherits="disabled" /> - </xul:hbox> - <xul:hbox align="center" pack="end"> - <xul:button anonid="css-bg-editor-image-clear" label="&status4evar.option.clear;" oncommand="this._editor._imageClear();" xbl:inherits="disabled=no-image" /> - </xul:hbox> - - <xul:hbox> - <xul:groupbox pack="center"> - <xul:caption label="" /> - <xul:hbox flex="1" align="center"> - <xul:label>X</xul:label> - </xul:hbox> - <xul:separator class="groove" orient="horizontal" /> - <xul:hbox flex="1" align="center"> - <xul:label>Y</xul:label> - </xul:hbox> - </xul:groupbox> - - <xul:groupbox> - <xul:caption label="&status4evar.editor.css.image.repeat;" xbl:inherits="disabled=no-image" /> - <xul:menulist anonid="css-bg-editor-image-repeat-x" sizetopopup="always" onselect="this._editor._buildCSS();" xbl:inherits="disabled=no-image"> - <xul:menupopup> - <xul:menuitem label="&status4evar.option.no-repeat;" value="no-repeat" /> - <xul:menuitem label="&status4evar.option.repeat;" value="repeat" /> + <binding id="css-bg-editor"> + <content sizetopopup="pref"> + <xul:vbox flex="1"> + <xul:deck anonid="css-bg-editor-deck" flex="1"> + <xul:vbox> + <xul:hbox align="center"> + <xul:label xbl:inherits="disabled">&status4evar.editor.css.color.label;</xul:label> + <xul:colorpicker anonid="css-bg-editor-color" type="button" onchange="this._editor._buildCSS();" xbl:inherits="disabled" /> + </xul:hbox> + + <xul:hbox align="center"> + <xul:label xbl:inherits="disabled">&status4evar.editor.css.image.label;</xul:label> + <xul:textbox anonid="css-bg-editor-image" readonly="true" flex="1" xbl:inherits="disabled" /> + <xul:button anonid="css-bg-editor-image-browse" label="&status4evar.option.browse;" oncommand="this._editor._imageBrowse();" xbl:inherits="disabled" /> + </xul:hbox> + <xul:hbox align="center" pack="end"> + <xul:button anonid="css-bg-editor-image-clear" label="&status4evar.option.clear;" oncommand="this._editor._imageClear();" xbl:inherits="disabled=no-image" /> + </xul:hbox> + + <xul:hbox> + <xul:groupbox pack="center"> + <xul:caption label="" /> + <xul:hbox flex="1" align="center"> + <xul:label>X</xul:label> + </xul:hbox> + <xul:separator class="groove" orient="horizontal" /> + <xul:hbox flex="1" align="center"> + <xul:label>Y</xul:label> + </xul:hbox> + </xul:groupbox> + + <xul:groupbox> + <xul:caption label="&status4evar.editor.css.image.repeat;" xbl:inherits="disabled=no-image" /> + <xul:menulist anonid="css-bg-editor-image-repeat-x" sizetopopup="always" onselect="this._editor._buildCSS();" xbl:inherits="disabled=no-image"> + <xul:menupopup> + <xul:menuitem label="&status4evar.option.no-repeat;" value="no-repeat" /> + <xul:menuitem label="&status4evar.option.repeat;" value="repeat" /> <!-- - <xul:menuitem label="&status4evar.option.space;" value="space" /> - <xul:menuitem label="&status4evar.option.round;" value="round" /> + <xul:menuitem label="&status4evar.option.space;" value="space" /> + <xul:menuitem label="&status4evar.option.round;" value="round" /> --> - </xul:menupopup> - </xul:menulist> - <xul:separator class="groove" orient="horizontal" /> - <xul:menulist anonid="css-bg-editor-image-repeat-y" sizetopopup="always" onselect="this._editor._buildCSS();" xbl:inherits="disabled=no-image"> - <xul:menupopup> - <xul:menuitem label="&status4evar.option.no-repeat;" value="no-repeat" /> - <xul:menuitem label="&status4evar.option.repeat;" value="repeat" /> + </xul:menupopup> + </xul:menulist> + <xul:separator class="groove" orient="horizontal" /> + <xul:menulist anonid="css-bg-editor-image-repeat-y" sizetopopup="always" onselect="this._editor._buildCSS();" xbl:inherits="disabled=no-image"> + <xul:menupopup> + <xul:menuitem label="&status4evar.option.no-repeat;" value="no-repeat" /> + <xul:menuitem label="&status4evar.option.repeat;" value="repeat" /> <!-- - <xul:menuitem label="&status4evar.option.space;" value="space" /> - <xul:menuitem label="&status4evar.option.round;" value="round" /> + <xul:menuitem label="&status4evar.option.space;" value="space" /> + <xul:menuitem label="&status4evar.option.round;" value="round" /> --> - </xul:menupopup> - </xul:menulist> - </xul:groupbox> - - <xul:groupbox> - <xul:caption label="&status4evar.editor.css.image.position;" xbl:inherits="disabled=no-image" /> - <xul:menulist anonid="css-bg-editor-image-position-x" sizetopopup="always" onselect="this._editor._updatePositionX();" xbl:inherits="disabled=no-image"> - <xul:menupopup> - <xul:menuitem label="&status4evar.option.left;" value="left" /> - <xul:menuitem label="&status4evar.option.center;" value="center" /> - <xul:menuitem label="&status4evar.option.right;" value="right" /> - <xul:menuitem label="&status4evar.option.offset;" value="offset" /> - </xul:menupopup> - </xul:menulist> - <xul:separator class="groove" orient="horizontal" /> - <xul:menulist anonid="css-bg-editor-image-position-y" sizetopopup="always" onselect="this._editor._updatePositionY();" xbl:inherits="disabled=no-image"> - <xul:menupopup> - <xul:menuitem label="&status4evar.option.top;" value="top" /> - <xul:menuitem label="&status4evar.option.center;" value="center" /> - <xul:menuitem label="&status4evar.option.bottom;" value="bottom" /> - <xul:menuitem label="&status4evar.option.offset;" value="offset" /> - </xul:menupopup> - </xul:menulist> - </xul:groupbox> - - <xul:groupbox> - <xul:caption label="&status4evar.editor.css.image.offset;" xbl:inherits="disabled=no-image" /> - <xul:hbox> - <xul:textbox anonid="css-bg-editor-image-offset-x" type="number" size="4" min="-65535" onchange="this._editor._buildCSS();" /> - <xul:menulist anonid="css-bg-editor-image-offset-unit-x" sizetopopup="always" onselect="this._editor._buildCSS();"> - <xul:menupopup> - <xul:menuitem label="%" value="%" /> - <xul:menuitem label="px" value="px" /> - <xul:menuitem label="em" value="em" /> - <xul:menuitem label="in" value="in" /> - <xul:menuitem label="cm" value="cm" /> - <xul:menuitem label="mm" value="mm" /> - <xul:menuitem label="pt" value="pt" /> - <xul:menuitem label="pc" value="pc" /> - </xul:menupopup> - </xul:menulist> - </xul:hbox> - <xul:separator class="groove" orient="horizontal" /> - <xul:hbox> - <xul:textbox anonid="css-bg-editor-image-offset-y" type="number" size="4" min="-65535" onchange="this._editor._buildCSS();" /> - <xul:menulist anonid="css-bg-editor-image-offset-unit-y" sizetopopup="always" onselect="this._editor._buildCSS();"> - <xul:menupopup> - <xul:menuitem label="%" value="%" /> - <xul:menuitem label="px" value="px" /> - <xul:menuitem label="em" value="em" /> - <xul:menuitem label="in" value="in" /> - <xul:menuitem label="cm" value="cm" /> - <xul:menuitem label="mm" value="mm" /> - <xul:menuitem label="pt" value="pt" /> - <xul:menuitem label="pc" value="pc" /> - </xul:menupopup> - </xul:menulist> - </xul:hbox> - </xul:groupbox> - </xul:hbox> - </xul:vbox> - - <xul:textbox anonid="css-bg-editor-css-text" multiline="true" rows="6" xbl:inherits="disabled" /> - </xul:deck> - </xul:vbox> - - <xul:hbox align="center" pack="end"> - <children includes="progressmeter|toolbox" /> - <xul:label xbl:inherits="disabled">&status4evar.editor.label;</xul:label> - <xul:menulist anonid="css-bg-editor-mode-menu" sizetopopup="always" onselect="this._editor._updateMode();" xbl:inherits="disabled"> - <xul:menupopup> - <xul:menuitem label="&status4evar.option.simple;" /> - <xul:menuitem label="&status4evar.option.advanced;" /> - </xul:menupopup> - </xul:menulist> - </xul:hbox> - </content> - - <implementation> - <constructor><![CDATA[ - [ - "_editorColor", - "_editorImageBrowse", - "_editorImageClear", - "_editorImageRepeatX", - "_editorImageRepeatY", - "_editorImagePositionX", - "_editorImagePositionY", - "_editorImageOffsetX", - "_editorImageOffsetY", - "_editorImageOffsetUnitX", - "_editorImageOffsetUnitY", - "_editorMode" - ].forEach(function(prop) - { - this[prop]._editor = this; - }, this); - - this.setAdvanced(true, false); - ]]></constructor> - - <destructor><![CDATA[ - ]]></destructor> - - <field name="_disableBuildCSS"><![CDATA[ - true - ]]></field> - - <field name="_editorColor" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-color"); - ]]></field> - - <field name="_editorCSS" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-css-text"); - ]]></field> - - <field name="_editorDeck" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-deck"); - ]]></field> - - <field name="_editorImage" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image"); - ]]></field> - - <field name="_editorImageBrowse" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-browse"); - ]]></field> - - <field name="_editorImageClear" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-clear"); - ]]></field> - - <field name="_editorImageRepeatX" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-repeat-x"); - ]]></field> - - <field name="_editorImageRepeatY" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-repeat-y"); - ]]></field> - - <field name="_editorImagePositionX" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-position-x"); - ]]></field> - - <field name="_editorImagePositionY" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-position-y"); - ]]></field> - - <field name="_editorImageOffsetX" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-x"); - ]]></field> - - <field name="_editorImageOffsetY" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-y"); - ]]></field> - - <field name="_editorImageOffsetUnitX" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-unit-x"); - ]]></field> - - <field name="_editorImageOffsetUnitY" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-unit-y"); - ]]></field> - - <field name="_editorMode" readonly="true"><![CDATA[ - document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-mode-menu"); - ]]></field> - - <field name="_initialized"><![CDATA[ - false - ]]></field> - - <field name="_reRGB" readonly="true"><![CDATA[ - /^rgb\((\d+), (\d+), (\d+)\)$/ - ]]></field> - - <field name="_reURL" readonly="true"><![CDATA[ - /^url\(\s*['"]?(.+?)['"]?\s*\)$/ - ]]></field> - - <field name="_reBgPosition" readonly="true"><![CDATA[ - /^(left|center|right)? ?(-?\d+[^\s\d]+)? ?(top|center|bottom)? ?(-?\d+[^\s\d]+)?$/ - ]]></field> - - <field name="_reCSSUnit" readonly="true"><![CDATA[ - /^(-?\d+)([^\s\d]+)$/ - ]]></field> - - <field name="_strings" readonly="true"><![CDATA[ - document.getElementById("bundle_status4evar"); - ]]></field> - - <property name="value"> - <getter><![CDATA[ - return this._editorCSS.value; - ]]></getter> - <setter><![CDATA[ - this._editorCSS.value = val; - - if(!this._initialized) - { - this.setAdvanced(false, false); - this._initialized = true; - } - - return val; - ]]></setter> - </property> - - <property name="disabled"> - <getter><![CDATA[ - return this.getAttribute("disabled") == "true"; - ]]></getter> - <setter><![CDATA[ - if(val) - { - this.setAttribute("disabled", "true"); - } - else - { - this.removeAttribute("disabled"); - } - - this._updateImageControllDisable(); - - return val; - ]]></setter> - </property> - - <method name="setAdvanced"> - <parameter name="aVal"/> - <parameter name="aPrompt"/> - <body><![CDATA[ - if(!aVal) - { - let success = this._parseCSS(); - if(!success) - { - let result = aPrompt && Services.prompt.confirm(window, - this._strings.getString("simpleEditorTitle"), - this._strings.getString("simpleEditorMessage")); - if(result) - { // Continue to simple mode - this._buildCSS(); - } - else - { // Stay on advanced mode - aVal = true; - } - } - } - - this._disableBuildCSS = aVal; - this._editorDeck.selectedIndex = ((aVal) ? 1 : 0); - this._editorMode.selectedIndex = ((aVal) ? 1 : 0); - ]]></body> - </method> - - <method name="_buildCSS"> - <body><![CDATA[ - if(this._disableBuildCSS) - { - return; - } - - let cssVal = this._editorColor.color; - let imgVal = this._editorImage.value; - if(imgVal) - { - cssVal += " url(\"" + imgVal + "\")"; - - // - // Print the background repeat - // - let bgRX = this._editorImageRepeatX.value; - let bgRY = this._editorImageRepeatY.value; - if(bgRX == "repeat" && bgRY == "no-repeat") - { - cssVal += " repeat-x"; - } - else if(bgRX == "no-repeat" && bgRY == "repeat") - { - cssVal += " repeat-y"; - } - else - { - cssVal += " " + bgRX; - if(bgRX != bgRY) - { - cssVal += " " + bgRY; - } - } - - // - // Print the background position - // - let bgPX = this._editorImagePositionX.value; - let bgPOX = this._editorImageOffsetX.value; - if(bgPX != "offset") - { - cssVal += " " + bgPX; - } - else - { - cssVal += " " + bgPOX + this._editorImageOffsetUnitX.value; - } - - let bgPY = this._editorImagePositionY.value; - let bgPOY = this._editorImageOffsetY.value; - if(bgPY != "offset") - { - cssVal += " " + bgPY; - } - else - { - cssVal += " " + bgPOY + this._editorImageOffsetUnitY.value; - } - } - - this._editorCSS.value = cssVal; - - let event = document.createEvent("Event"); - event.initEvent("change", true, true); - this._editorCSS.dispatchEvent(event); - ]]></body> - </method> - - <method name="_parseCSS"> - <body><![CDATA[ - let retVal = true; - - let cssParser = document.createElement("div"); - cssParser.style.background = this._editorCSS.value; - if(!cssParser.style.background) - { - Components.utils.reportError("Error parsing background CSS rule: " + this._editorCSS.value); - cssParser.style.background = "#33FF33"; - retVal = false; - } - - // - // Parse the background color - // - let bgC = cssParser.style.backgroundColor; - if(this._reRGB.test(bgC)) - { - let digits = this._reRGB.exec(bgC); - - let red = parseInt(digits[1]); - let green = parseInt(digits[2]); - let blue = parseInt(digits[3]); - - let rgb = blue | (green << 8) | (red << 16); - bgC = "#" + rgb.toString(16); - } - else - { - Components.utils.reportError("Error parsing background-color value: " + bgC); - bgC = "#33FF33"; - retVal = false; - } - - // - // Parse the background image - // - let bgI = cssParser.style.backgroundImage; - if(bgI != "none" && !this._reURL.test(bgI)) - { - Components.utils.reportError("Error parsing background-image value: " + bgI); - bgI = "none"; - retVal = false; - } - bgI = ((bgI != "none") ? this._reURL.exec(bgI)[1].trim() : ""); - - // - // Parse the background repeat - // - let bgR = cssParser.style.backgroundRepeat.split(" "); - let bgRX = bgR[0]; - if(bgRX == "repeat-x") - { - bgRX = "repeat"; - } - else if(bgRX == "repeat-y") - { - bgRX = "no-repeat"; - } - - let bgRY = bgR[bgR.length - 1]; - if(bgRY == "repeat-x") - { - bgRY = "no-repeat"; - } - else if(bgRY == "repeat-y") - { - bgRY = "repeat"; - } - - // - // Parse the background position - // - let bgP = cssParser.style.backgroundPosition; - let bgPParts = this._reBgPosition.exec(bgP); - let bgPValues = new Array(); - for(let i = 1; i <= 4; i++) - { - if(bgPParts[i]) - { - bgPValues.push({ - "value": bgPParts[i], - "group": i - }); - } - } - - if(bgPValues.length == 1) - { - bgPValues.splice(((bgPValues[0].group == 2) ? 0 : 1), 0, { - "value": "center", - "group": ((bgPValues[0].group == 2) ? 0 : 2) - }); - } - - if(bgPValues.length == 2 && bgPValues[1].group == 2) - { - bgPValues[1].group = 4; - } - - for(let i = 0; i < 4; i++) - { - let group = (i + 1); - if(bgPValues[i] != undefined && bgPValues[i].group == group) - { - continue; - } - - let tmp = "0px"; - switch(i) - { - case 0: - tmp = "offset"; - break; - case 2: - tmp = "offset"; - break; - } - - bgPValues.splice(i, 0, { - "value": tmp, - "group": group - }); - } - - let bgPOXParts = this._reCSSUnit.exec(bgPValues[1].value); - let bgPOYParts = this._reCSSUnit.exec(bgPValues[3].value); - - // - // Parse the background size - // - - // - // Initialize the UI - // - let disableBuildCSS = this._disableBuildCSS; - this._disableBuildCSS = true; - - this._editorColor.color = bgC; - this._editorImage.value = bgI; - this._editorImageOffsetX.value = bgPOXParts[1]; - this._editorImageOffsetY.value = bgPOYParts[1]; - - [ - [this._editorImageRepeatX, bgRX, "repeat", "repeat X"], - [this._editorImageRepeatY, bgRY, "repeat", "repeat Y"], - [this._editorImagePositionX, bgPValues[0].value, "left", "position X"], - [this._editorImagePositionY, bgPValues[2].value, "top", "position Y"], - [this._editorImageOffsetUnitX, bgPOXParts[2], "px", "offset X unit"], - [this._editorImageOffsetUnitY, bgPOYParts[2], "px", "offset Y unit"] - ].forEach(function(info) - { - if(!this._setSelectedItemSafe(info[0], info[1], info[2])) - { - Components.utils.reportError("Error setting " + info[3] + " to " + info[1]); - retVal = false; - } - }, this); - - this._updateImageControllDisable(); - - this._disableBuildCSS = disableBuildCSS; - - return retVal; - ]]></body> - </method> - - <method name="_imageBrowse"> - <body><![CDATA[ - let nsIFilePicker = Components.interfaces.nsIFilePicker; - let filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); - filePicker.init(window, this._strings.getString("imageSelectTitle"), nsIFilePicker.modeOpen); - filePicker.appendFilters(nsIFilePicker.filterImages); - - let res = filePicker.show(); - if(res == nsIFilePicker.returnOK) - { - this._editorImage.value = Services.io.newFileURI(filePicker.file).spec; - this._updateImageControllDisable(); - this._buildCSS(); - } - ]]></body> - </method> - - <method name="_imageClear"> - <body><![CDATA[ - this._editorImage.value = ""; - this._editorImageRepeatX.value = "repeat"; - this._editorImageRepeatY.value = "repeat"; - this._editorImagePositionX.value = "left"; - this._editorImagePositionY.value = "top"; - this._editorImageOffsetX.value = 0; - this._editorImageOffsetY.value = 0; - this._editorImageOffsetUnitX.value = "px"; - this._editorImageOffsetUnitY.value = "px"; - this._updateImageControllDisable(); - this._buildCSS(); - ]]></body> - </method> - - <method name="_processEvent"> - <parameter name="event"/> - <body><![CDATA[ - if(!("css-bg-editor-css-text" == event.originalTarget.getAttribute("anonid") - || "css-bg-editor-css-text" == document.getBindingParent(event.originalTarget).getAttribute("anonid"))) - { - event.stopPropagation(); - } - - //Components.utils.reportError("Editor event " + event.type + " on " + event.originalTarget.tagName + "::" + event.originalTarget.getAttribute("anonid")); - ]]></body> - </method> - - <method name="_setSelectedItemSafe"> - <parameter name="aElement"/> - <parameter name="aValue"/> - <parameter name="aDefault"/> - <body><![CDATA[ - aElement.value = aValue; - if(!aElement.selectedItem || aElement.selectedItem.value != aValue) - { - aElement.value = aDefault; - return false; - } - return true; - ]]></body> - </method> - - <method name="_updateImageControllDisable"> - <body><![CDATA[ - if(this.disabled || !this._editorImage.value) - { - this.setAttribute("no-image", "true"); - this._updatePositionOffsetXDisabled(true); - this._updatePositionOffsetYDisabled(true); - } - else - { - this.removeAttribute("no-image"); - this._updatePositionOffsetXDisabled(false); - this._updatePositionOffsetYDisabled(false); - } - ]]></body> - </method> - - <method name="_updateMode"> - <body><![CDATA[ - if(this._editorMode.selectedIndex == this._editorDeck.selectedIndex) - { - return; - } - - this.setAdvanced(((this._editorMode.selectedIndex == 1) ? true : false), true); - ]]></body> - </method> - - <method name="_updatePositionOffsetXDisabled"> - <parameter name="aVal"/> - <body><![CDATA[ - let bgPX = this._editorImagePositionX.value; - let disableOffsetX = aVal || (bgPX != "offset");// || bgPX == "center"); - this._editorImageOffsetX.disabled = disableOffsetX; - this._editorImageOffsetUnitX.disabled = disableOffsetX; - ]]></body> - </method> - - <method name="_updatePositionOffsetYDisabled"> - <parameter name="aVal"/> - <body><![CDATA[ - let bgPY = this._editorImagePositionY.value; - var disableOffsetY = aVal || (bgPY != "offset");// || bgPY == "center"); - this._editorImageOffsetY.disabled = disableOffsetY; - this._editorImageOffsetUnitY.disabled = disableOffsetY; - ]]></body> - </method> - - <method name="_updatePositionX"> - <body><![CDATA[ - this._updatePositionOffsetXDisabled(false); - this._buildCSS(); - ]]></body> - </method> - - <method name="_updatePositionY"> - <body><![CDATA[ - this._updatePositionOffsetYDisabled(false); - this._buildCSS(); - ]]></body> - </method> - </implementation> - - <handlers> - <handler event="command"><![CDATA[ - this._processEvent(event); - ]]></handler> - - <handler event="change"><![CDATA[ - this._processEvent(event); - ]]></handler> - - <handler event="input"><![CDATA[ - this._processEvent(event); - ]]></handler> - - <handler event="select"><![CDATA[ - this._processEvent(event); - ]]></handler> - </handlers> - </binding> + </xul:menupopup> + </xul:menulist> + </xul:groupbox> + + <xul:groupbox> + <xul:caption label="&status4evar.editor.css.image.position;" xbl:inherits="disabled=no-image" /> + <xul:menulist anonid="css-bg-editor-image-position-x" sizetopopup="always" onselect="this._editor._updatePositionX();" xbl:inherits="disabled=no-image"> + <xul:menupopup> + <xul:menuitem label="&status4evar.option.left;" value="left" /> + <xul:menuitem label="&status4evar.option.center;" value="center" /> + <xul:menuitem label="&status4evar.option.right;" value="right" /> + <xul:menuitem label="&status4evar.option.offset;" value="offset" /> + </xul:menupopup> + </xul:menulist> + <xul:separator class="groove" orient="horizontal" /> + <xul:menulist anonid="css-bg-editor-image-position-y" sizetopopup="always" onselect="this._editor._updatePositionY();" xbl:inherits="disabled=no-image"> + <xul:menupopup> + <xul:menuitem label="&status4evar.option.top;" value="top" /> + <xul:menuitem label="&status4evar.option.center;" value="center" /> + <xul:menuitem label="&status4evar.option.bottom;" value="bottom" /> + <xul:menuitem label="&status4evar.option.offset;" value="offset" /> + </xul:menupopup> + </xul:menulist> + </xul:groupbox> + + <xul:groupbox> + <xul:caption label="&status4evar.editor.css.image.offset;" xbl:inherits="disabled=no-image" /> + <xul:hbox> + <xul:textbox anonid="css-bg-editor-image-offset-x" type="number" size="4" min="-65535" onchange="this._editor._buildCSS();" /> + <xul:menulist anonid="css-bg-editor-image-offset-unit-x" sizetopopup="always" onselect="this._editor._buildCSS();"> + <xul:menupopup> + <xul:menuitem label="%" value="%" /> + <xul:menuitem label="px" value="px" /> + <xul:menuitem label="em" value="em" /> + <xul:menuitem label="in" value="in" /> + <xul:menuitem label="cm" value="cm" /> + <xul:menuitem label="mm" value="mm" /> + <xul:menuitem label="pt" value="pt" /> + <xul:menuitem label="pc" value="pc" /> + </xul:menupopup> + </xul:menulist> + </xul:hbox> + <xul:separator class="groove" orient="horizontal" /> + <xul:hbox> + <xul:textbox anonid="css-bg-editor-image-offset-y" type="number" size="4" min="-65535" onchange="this._editor._buildCSS();" /> + <xul:menulist anonid="css-bg-editor-image-offset-unit-y" sizetopopup="always" onselect="this._editor._buildCSS();"> + <xul:menupopup> + <xul:menuitem label="%" value="%" /> + <xul:menuitem label="px" value="px" /> + <xul:menuitem label="em" value="em" /> + <xul:menuitem label="in" value="in" /> + <xul:menuitem label="cm" value="cm" /> + <xul:menuitem label="mm" value="mm" /> + <xul:menuitem label="pt" value="pt" /> + <xul:menuitem label="pc" value="pc" /> + </xul:menupopup> + </xul:menulist> + </xul:hbox> + </xul:groupbox> + </xul:hbox> + </xul:vbox> + + <xul:textbox anonid="css-bg-editor-css-text" multiline="true" rows="6" xbl:inherits="disabled" /> + </xul:deck> + </xul:vbox> + + <xul:hbox align="center" pack="end"> + <children includes="progressmeter|toolbox" /> + <xul:label xbl:inherits="disabled">&status4evar.editor.label;</xul:label> + <xul:menulist anonid="css-bg-editor-mode-menu" sizetopopup="always" onselect="this._editor._updateMode();" xbl:inherits="disabled"> + <xul:menupopup> + <xul:menuitem label="&status4evar.option.simple;" /> + <xul:menuitem label="&status4evar.option.advanced;" /> + </xul:menupopup> + </xul:menulist> + </xul:hbox> + </content> + + <implementation> + <constructor><![CDATA[ + [ + "_editorColor", + "_editorImageBrowse", + "_editorImageClear", + "_editorImageRepeatX", + "_editorImageRepeatY", + "_editorImagePositionX", + "_editorImagePositionY", + "_editorImageOffsetX", + "_editorImageOffsetY", + "_editorImageOffsetUnitX", + "_editorImageOffsetUnitY", + "_editorMode" + ].forEach(function(prop) + { + this[prop]._editor = this; + }, this); + + this.setAdvanced(true, false); + ]]></constructor> + + <destructor><![CDATA[ + ]]></destructor> + + <field name="_disableBuildCSS"><![CDATA[ + true + ]]></field> + + <field name="_editorColor" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-color"); + ]]></field> + + <field name="_editorCSS" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-css-text"); + ]]></field> + + <field name="_editorDeck" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-deck"); + ]]></field> + + <field name="_editorImage" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image"); + ]]></field> + + <field name="_editorImageBrowse" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-browse"); + ]]></field> + + <field name="_editorImageClear" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-clear"); + ]]></field> + + <field name="_editorImageRepeatX" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-repeat-x"); + ]]></field> + + <field name="_editorImageRepeatY" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-repeat-y"); + ]]></field> + + <field name="_editorImagePositionX" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-position-x"); + ]]></field> + + <field name="_editorImagePositionY" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-position-y"); + ]]></field> + + <field name="_editorImageOffsetX" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-x"); + ]]></field> + + <field name="_editorImageOffsetY" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-y"); + ]]></field> + + <field name="_editorImageOffsetUnitX" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-unit-x"); + ]]></field> + + <field name="_editorImageOffsetUnitY" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-unit-y"); + ]]></field> + + <field name="_editorMode" readonly="true"><![CDATA[ + document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-mode-menu"); + ]]></field> + + <field name="_initialized"><![CDATA[ + false + ]]></field> + + <field name="_reRGB" readonly="true"><![CDATA[ + /^rgb\((\d+), (\d+), (\d+)\)$/ + ]]></field> + + <field name="_reURL" readonly="true"><![CDATA[ + /^url\(\s*['"]?(.+?)['"]?\s*\)$/ + ]]></field> + + <field name="_reBgPosition" readonly="true"><![CDATA[ + /^(left|center|right)? ?(-?\d+[^\s\d]+)? ?(top|center|bottom)? ?(-?\d+[^\s\d]+)?$/ + ]]></field> + + <field name="_reCSSUnit" readonly="true"><![CDATA[ + /^(-?\d+)([^\s\d]+)$/ + ]]></field> + + <field name="_strings" readonly="true"><![CDATA[ + document.getElementById("bundle_status4evar"); + ]]></field> + + <property name="value"> + <getter><![CDATA[ + return this._editorCSS.value; + ]]></getter> + <setter><![CDATA[ + this._editorCSS.value = val; + + if(!this._initialized) + { + this.setAdvanced(false, false); + this._initialized = true; + } + + return val; + ]]></setter> + </property> + + <property name="disabled"> + <getter><![CDATA[ + return this.getAttribute("disabled") == "true"; + ]]></getter> + <setter><![CDATA[ + if(val) + { + this.setAttribute("disabled", "true"); + } + else + { + this.removeAttribute("disabled"); + } + + this._updateImageControllDisable(); + + return val; + ]]></setter> + </property> + + <method name="setAdvanced"> + <parameter name="aVal"/> + <parameter name="aPrompt"/> + <body><![CDATA[ + if(!aVal) + { + let success = this._parseCSS(); + if(!success) + { + let result = aPrompt && Services.prompt.confirm(window, + this._strings.getString("simpleEditorTitle"), + this._strings.getString("simpleEditorMessage")); + if(result) + { // Continue to simple mode + this._buildCSS(); + } + else + { // Stay on advanced mode + aVal = true; + } + } + } + + this._disableBuildCSS = aVal; + this._editorDeck.selectedIndex = ((aVal) ? 1 : 0); + this._editorMode.selectedIndex = ((aVal) ? 1 : 0); + ]]></body> + </method> + + <method name="_buildCSS"> + <body><![CDATA[ + if(this._disableBuildCSS) + { + return; + } + + let cssVal = this._editorColor.color; + let imgVal = this._editorImage.value; + if(imgVal) + { + cssVal += " url(\"" + imgVal + "\")"; + + // + // Print the background repeat + // + let bgRX = this._editorImageRepeatX.value; + let bgRY = this._editorImageRepeatY.value; + if(bgRX == "repeat" && bgRY == "no-repeat") + { + cssVal += " repeat-x"; + } + else if(bgRX == "no-repeat" && bgRY == "repeat") + { + cssVal += " repeat-y"; + } + else + { + cssVal += " " + bgRX; + if(bgRX != bgRY) + { + cssVal += " " + bgRY; + } + } + + // + // Print the background position + // + let bgPX = this._editorImagePositionX.value; + let bgPOX = this._editorImageOffsetX.value; + if(bgPX != "offset") + { + cssVal += " " + bgPX; + } + else + { + cssVal += " " + bgPOX + this._editorImageOffsetUnitX.value; + } + + let bgPY = this._editorImagePositionY.value; + let bgPOY = this._editorImageOffsetY.value; + if(bgPY != "offset") + { + cssVal += " " + bgPY; + } + else + { + cssVal += " " + bgPOY + this._editorImageOffsetUnitY.value; + } + } + + this._editorCSS.value = cssVal; + + let event = document.createEvent("Event"); + event.initEvent("change", true, true); + this._editorCSS.dispatchEvent(event); + ]]></body> + </method> + + <method name="_parseCSS"> + <body><![CDATA[ + let retVal = true; + + let cssParser = document.createElement("div"); + cssParser.style.background = this._editorCSS.value; + if(!cssParser.style.background) + { + Components.utils.reportError("Error parsing background CSS rule: " + this._editorCSS.value); + cssParser.style.background = "#33FF33"; + retVal = false; + } + + // + // Parse the background color + // + let bgC = cssParser.style.backgroundColor; + if(this._reRGB.test(bgC)) + { + let digits = this._reRGB.exec(bgC); + + let red = parseInt(digits[1]); + let green = parseInt(digits[2]); + let blue = parseInt(digits[3]); + + let rgb = blue | (green << 8) | (red << 16); + bgC = "#" + rgb.toString(16); + } + else + { + Components.utils.reportError("Error parsing background-color value: " + bgC); + bgC = "#33FF33"; + retVal = false; + } + + // + // Parse the background image + // + let bgI = cssParser.style.backgroundImage; + if(bgI != "none" && !this._reURL.test(bgI)) + { + Components.utils.reportError("Error parsing background-image value: " + bgI); + bgI = "none"; + retVal = false; + } + bgI = ((bgI != "none") ? this._reURL.exec(bgI)[1].trim() : ""); + + // + // Parse the background repeat + // + let bgR = cssParser.style.backgroundRepeat.split(" "); + let bgRX = bgR[0]; + if(bgRX == "repeat-x") + { + bgRX = "repeat"; + } + else if(bgRX == "repeat-y") + { + bgRX = "no-repeat"; + } + + let bgRY = bgR[bgR.length - 1]; + if(bgRY == "repeat-x") + { + bgRY = "no-repeat"; + } + else if(bgRY == "repeat-y") + { + bgRY = "repeat"; + } + + // + // Parse the background position + // + let bgP = cssParser.style.backgroundPosition; + let bgPParts = this._reBgPosition.exec(bgP); + let bgPValues = new Array(); + for(let i = 1; i <= 4; i++) + { + if(bgPParts[i]) + { + bgPValues.push({ + "value": bgPParts[i], + "group": i + }); + } + } + + if(bgPValues.length == 1) + { + bgPValues.splice(((bgPValues[0].group == 2) ? 0 : 1), 0, { + "value": "center", + "group": ((bgPValues[0].group == 2) ? 0 : 2) + }); + } + + if(bgPValues.length == 2 && bgPValues[1].group == 2) + { + bgPValues[1].group = 4; + } + + for(let i = 0; i < 4; i++) + { + let group = (i + 1); + if(bgPValues[i] != undefined && bgPValues[i].group == group) + { + continue; + } + + let tmp = "0px"; + switch(i) + { + case 0: + tmp = "offset"; + break; + case 2: + tmp = "offset"; + break; + } + + bgPValues.splice(i, 0, { + "value": tmp, + "group": group + }); + } + + let bgPOXParts = this._reCSSUnit.exec(bgPValues[1].value); + let bgPOYParts = this._reCSSUnit.exec(bgPValues[3].value); + + // + // Parse the background size + // + + // + // Initialize the UI + // + let disableBuildCSS = this._disableBuildCSS; + this._disableBuildCSS = true; + + this._editorColor.color = bgC; + this._editorImage.value = bgI; + this._editorImageOffsetX.value = bgPOXParts[1]; + this._editorImageOffsetY.value = bgPOYParts[1]; + + [ + [this._editorImageRepeatX, bgRX, "repeat", "repeat X"], + [this._editorImageRepeatY, bgRY, "repeat", "repeat Y"], + [this._editorImagePositionX, bgPValues[0].value, "left", "position X"], + [this._editorImagePositionY, bgPValues[2].value, "top", "position Y"], + [this._editorImageOffsetUnitX, bgPOXParts[2], "px", "offset X unit"], + [this._editorImageOffsetUnitY, bgPOYParts[2], "px", "offset Y unit"] + ].forEach(function(info) + { + if(!this._setSelectedItemSafe(info[0], info[1], info[2])) + { + Components.utils.reportError("Error setting " + info[3] + " to " + info[1]); + retVal = false; + } + }, this); + + this._updateImageControllDisable(); + + this._disableBuildCSS = disableBuildCSS; + + return retVal; + ]]></body> + </method> + + <method name="_imageBrowse"> + <body><![CDATA[ + let nsIFilePicker = Components.interfaces.nsIFilePicker; + let filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); + filePicker.init(window, this._strings.getString("imageSelectTitle"), nsIFilePicker.modeOpen); + filePicker.appendFilters(nsIFilePicker.filterImages); + + let res = filePicker.show(); + if(res == nsIFilePicker.returnOK) + { + this._editorImage.value = Services.io.newFileURI(filePicker.file).spec; + this._updateImageControllDisable(); + this._buildCSS(); + } + ]]></body> + </method> + + <method name="_imageClear"> + <body><![CDATA[ + this._editorImage.value = ""; + this._editorImageRepeatX.value = "repeat"; + this._editorImageRepeatY.value = "repeat"; + this._editorImagePositionX.value = "left"; + this._editorImagePositionY.value = "top"; + this._editorImageOffsetX.value = 0; + this._editorImageOffsetY.value = 0; + this._editorImageOffsetUnitX.value = "px"; + this._editorImageOffsetUnitY.value = "px"; + this._updateImageControllDisable(); + this._buildCSS(); + ]]></body> + </method> + + <method name="_processEvent"> + <parameter name="event"/> + <body><![CDATA[ + if(!("css-bg-editor-css-text" == event.originalTarget.getAttribute("anonid") + || "css-bg-editor-css-text" == document.getBindingParent(event.originalTarget).getAttribute("anonid"))) + { + event.stopPropagation(); + } + + //Components.utils.reportError("Editor event " + event.type + " on " + event.originalTarget.tagName + "::" + event.originalTarget.getAttribute("anonid")); + ]]></body> + </method> + + <method name="_setSelectedItemSafe"> + <parameter name="aElement"/> + <parameter name="aValue"/> + <parameter name="aDefault"/> + <body><![CDATA[ + aElement.value = aValue; + if(!aElement.selectedItem || aElement.selectedItem.value != aValue) + { + aElement.value = aDefault; + return false; + } + return true; + ]]></body> + </method> + + <method name="_updateImageControllDisable"> + <body><![CDATA[ + if(this.disabled || !this._editorImage.value) + { + this.setAttribute("no-image", "true"); + this._updatePositionOffsetXDisabled(true); + this._updatePositionOffsetYDisabled(true); + } + else + { + this.removeAttribute("no-image"); + this._updatePositionOffsetXDisabled(false); + this._updatePositionOffsetYDisabled(false); + } + ]]></body> + </method> + + <method name="_updateMode"> + <body><![CDATA[ + if(this._editorMode.selectedIndex == this._editorDeck.selectedIndex) + { + return; + } + + this.setAdvanced(((this._editorMode.selectedIndex == 1) ? true : false), true); + ]]></body> + </method> + + <method name="_updatePositionOffsetXDisabled"> + <parameter name="aVal"/> + <body><![CDATA[ + let bgPX = this._editorImagePositionX.value; + let disableOffsetX = aVal || (bgPX != "offset");// || bgPX == "center"); + this._editorImageOffsetX.disabled = disableOffsetX; + this._editorImageOffsetUnitX.disabled = disableOffsetX; + ]]></body> + </method> + + <method name="_updatePositionOffsetYDisabled"> + <parameter name="aVal"/> + <body><![CDATA[ + let bgPY = this._editorImagePositionY.value; + var disableOffsetY = aVal || (bgPY != "offset");// || bgPY == "center"); + this._editorImageOffsetY.disabled = disableOffsetY; + this._editorImageOffsetUnitY.disabled = disableOffsetY; + ]]></body> + </method> + + <method name="_updatePositionX"> + <body><![CDATA[ + this._updatePositionOffsetXDisabled(false); + this._buildCSS(); + ]]></body> + </method> + + <method name="_updatePositionY"> + <body><![CDATA[ + this._updatePositionOffsetYDisabled(false); + this._buildCSS(); + ]]></body> + </method> + </implementation> + + <handlers> + <handler event="command"><![CDATA[ + this._processEvent(event); + ]]></handler> + + <handler event="change"><![CDATA[ + this._processEvent(event); + ]]></handler> + + <handler event="input"><![CDATA[ + this._processEvent(event); + ]]></handler> + + <handler event="select"><![CDATA[ + this._processEvent(event); + ]]></handler> + </handlers> + </binding> </bindings> diff --git a/application/palemoon/components/statusbar/content/prefs.xul b/application/palemoon/components/statusbar/content/prefs.xul index d10dc006a..dd4158246 100644 --- a/application/palemoon/components/statusbar/content/prefs.xul +++ b/application/palemoon/components/statusbar/content/prefs.xul @@ -5,8 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. --> <!DOCTYPE prefwindow [ - <!ENTITY % prefsDTD SYSTEM "chrome://browser/locale/statusbar/statusbar-prefs.dtd"> - %prefsDTD; + <!ENTITY % prefsDTD SYSTEM "chrome://browser/locale/statusbar/statusbar-prefs.dtd"> + %prefsDTD; ]> <?xml-stylesheet href="chrome://global/skin/config.css" type="text/css" ?> @@ -23,275 +23,275 @@ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="status4evarPrefs.onPrefWindowLoad();" onunload="status4evarPrefs.onPrefWindowUnLoad();"> - <stringbundleset id="stringbundleset"> - <stringbundle id="bundle_status4evar" src="chrome://browser/locale/statusbar/prefs.properties" /> - </stringbundleset> - <script type="application/javascript" src="chrome://browser/content/statusbar/prefs.js" /> + <stringbundleset id="stringbundleset"> + <stringbundle id="bundle_status4evar" src="chrome://browser/locale/statusbar/prefs.properties" /> + </stringbundleset> + <script type="application/javascript" src="chrome://browser/content/statusbar/prefs.js" /> - <prefpane id="status4evar-pane-status" label="&status4evar.pane.status;"> - <preferences> - <preference id="status4evar-pref-status" name="status4evar.status" type="int" /> - <preference id="status4evar-pref-status-default" name="status4evar.status.default" type="bool" /> - <preference id="status4evar-pref-status-network" name="status4evar.status.network" type="bool" - onchange="status4evarPrefs.statusNetworkChanged();" /> - <preference id="status4evar-pref-status-network-xhr" name="status4evar.status.network.xhr" type="bool" /> - <preference id="status4evar-pref-status-timeout" name="status4evar.status.timeout" type="int" - onchange="status4evarPrefs.statusTimeoutChanged();" /> - <preference id="status4evar-pref-status-linkOver" name="status4evar.status.linkOver" type="int" /> - <preference id="status4evar-pref-status-linkOver-delay-show" name="status4evar.status.linkOver.delay.show" type="int" /> - <preference id="status4evar-pref-status-linkOver-delay-hide" name="status4evar.status.linkOver.delay.hide" type="int" /> - <preference id="status4evar-pref-status-toolbar-maxLength" name="status4evar.status.toolbar.maxLength" type="int" - onchange="status4evarPrefs.textLengthChanged();" /> - <preference id="status4evar-pref-status-popup-invertMirror" name="status4evar.status.popup.invertMirror" type="bool" /> - <preference id="status4evar-pref-status-popup-mouseMirror" name="status4evar.status.popup.mouseMirror" type="bool" /> - <preference id="toolkit-pref-dom-status-change" name="dom.disable_window_status_change" type="bool" inverted="true" /> - </preferences> - - <commandset id="status4evar-commandset-status"> - <command id="status4evar-command-status-timeout" oncommand="status4evarPrefs.statusTimeoutToggle();" /> - <command id="status4evar-command-status-toolbar-maxLength" oncommand="status4evarPrefs.textLengthToggle();" /> - </commandset> - - <tabbox id="status4evar-tabbox-status" flex="1"> - <tabs id="status4evar-tabs-status"> - <tab id="status4evar-tab-status-general" label="&status4evar.tab.general;" /> - <tab id="status4evar-tab-status-toolbar" label="&status4evar.tab.toolbar;" /> - <tab id="status4evar-tab-status-popup" label="&status4evar.tab.popup;" /> - </tabs> - - <tabpanels id="status4evar-tabpanels-status" flex="1"> - <tabpanel id="status4evar-tabpanel-status-general" orient="vertical"> - <groupbox id="status4evar-status-general-status"> - <caption label="&status4evar.status.general.status.caption;" /> - - <hbox align="center"> - <label id="status4evar-status-label" control="status4evar-status-menu">&status4evar.status.label;</label> - <menulist id="status4evar-status-menu" preference="status4evar-pref-status" sizetopopup="always"> - <menupopup> - <menuitem label="&status4evar.option.none;" value="0" /> - <menuitem label="&status4evar.option.toolbar;" value="1" /> - <menuitem label="&status4evar.option.popup;" value="3" /> - </menupopup> - </menulist> - </hbox> - - <hbox align="center"> - <checkbox id="status4evar-status-timeout-check" label="&status4evar.status.timeout.label;" - command="status4evar-command-status-timeout" /> - <textbox id="status4evar-status-timeout-value" preference="status4evar-pref-status-timeout" type="number" size="4" - onsyncfrompreference="return status4evarPrefs.statusTimeoutSync();" /> - <label id="status4evar-status-timeout-unit">&status4evar.unit.seconds;</label> - </hbox> - - <checkbox id="status4evar-status-default-check" preference="status4evar-pref-status-default" label="&status4evar.status.default.label;" /> - - <checkbox id="status4evar-status-network-check" preference="status4evar-pref-status-network" label="&status4evar.status.network.label;" - onsyncfrompreference="return status4evarPrefs.statusNetworkSync();" /> - - <hbox align="center" class="indent"> - <checkbox id="status4evar-status-network-xhr-check" preference="status4evar-pref-status-network-xhr" label="&status4evar.status.network.xhr.label;" /> - </hbox> - - <checkbox id="toolkit-dom-status-change-check" preference="toolkit-pref-dom-status-change" label="&toolkit.dom.status.change.label;" /> - </groupbox> - - <groupbox id="status4evar-status-general-linkOver"> - <caption label="&status4evar.status.general.linkOver.caption;" /> - - <hbox align="center"> - <label id="status4evar-status-linkOver-label" control="status4evar-status-linkOver-menu">&status4evar.status.linkOver.label;</label> - <menulist id="status4evar-status-linkOver-menu" preference="status4evar-pref-status-linkOver" sizetopopup="always"> - <menupopup> - <menuitem label="&status4evar.option.none;" value="0" /> - <menuitem label="&status4evar.option.toolbar;" value="1" /> - <menuitem label="&status4evar.option.popup;" value="3" /> - </menupopup> - </menulist> - </hbox> - - <hbox align="center"> - <label id="status4evar-status-linkOver-delay-show-label" control="status4evar-status-linkOver-delay-show-value">&status4evar.status.linkOver.delay.show.label;</label> - <textbox id="status4evar-status-linkOver-delay-show-value" preference="status4evar-pref-status-linkOver-delay-show" type="number" size="5" /> - <label id="status4evar-status-linkOver-delay-show-unit">&status4evar.unit.milliseconds;</label> - </hbox> - - <hbox align="center"> - <label id="status4evar-status-linkOver-delay-hide-label" control="status4evar-status-linkOver-delay-hide-value">&status4evar.status.linkOver.delay.hide.label;</label> - <textbox id="status4evar-status-linkOver-delay-hide-value" preference="status4evar-pref-status-linkOver-delay-hide" type="number" size="5" /> - <label id="status4evar-status-linkOver-delay-hide-unit">&status4evar.unit.milliseconds;</label> - </hbox> - </groupbox> - - </tabpanel> - - <tabpanel id="status4evar-tabpanel-status-toolbar" orient="vertical"> - <hbox align="center"> - <checkbox id="status4evar-status-toolbar-maxLength-check" label="&status4evar.status.toolbar.maxLength.label;" - command="status4evar-command-status-toolbar-maxLength" /> - <textbox id="status4evar-status-toolbar-maxLength-value" preference="status4evar-pref-status-toolbar-maxLength" type="number" size="4" - onsyncfrompreference="return status4evarPrefs.textLengthSync();" /> - <label id="status4evar-status-toolbar-maxLength-unit">&status4evar.unit.px;</label> - </hbox> - </tabpanel> - - <tabpanel id="status4evar-tabpanel-status-popup" orient="vertical"> - <checkbox id="status4evar-status-popup-invertMirror-check" preference="status4evar-pref-status-popup-invertMirror" label="&status4evar.status.popup.invertMirror.label;" /> - - <checkbox id="status4evar-status-popup-mouseMirror-check" preference="status4evar-pref-status-popup-mouseMirror" label="&status4evar.status.popup.mouseMirror.label;" /> - </tabpanel> - - </tabpanels> - </tabbox> - </prefpane> - - <prefpane id="status4evar-pane-progress" label="&status4evar.pane.progress;"> - <preferences> - <preference id="status4evar-pref-progress-toolbar-force" name="status4evar.progress.toolbar.force" type="bool" /> - <preference id="status4evar-pref-progress-toolbar-style" name="status4evar.progress.toolbar.style" type="bool" - onchange="status4evarPrefs.progressToolbarStyleChanged();" /> - <preference id="status4evar-pref-progress-toolbar-css" name="status4evar.progress.toolbar.css" type="string" - onchange="status4evarPrefs.progressToolbarCSSChanged();" /> - </preferences> - - <commandset id="status4evar-commandset-status"> - </commandset> - - <checkbox id="status4evar-progress-toolbar-force-check" preference="status4evar-pref-progress-toolbar-force" label="&status4evar.progress.toolbar.force.label;" /> - - <checkbox id="status4evar-progress-toolbar-style-check" preference="status4evar-pref-progress-toolbar-style" label="&status4evar.progress.style.label;" - onsyncfrompreference="return status4evarPrefs.progressToolbarStyleSync();" /> - - <vbox class="css-bg-editor" preference="status4evar-pref-progress-toolbar-css" preference-editable="true" flex="1"> - <progressmeter id="status4evar-progress-bar" value="75" flex="1" /> - </vbox> - </prefpane> - - <prefpane id="status4evar-pane-download" label="&status4evar.pane.download;"> - <preferences> - <preference id="status4evar-pref-download-button-action" name="status4evar.download.button.action" type="int" /> - <preference id="status4evar-pref-download-color-active" name="status4evar.download.color.active" type="string" /> - <preference id="status4evar-pref-download-color-paused" name="status4evar.download.color.paused" type="string" /> - <preference id="status4evar-pref-download-force" name="status4evar.download.force" type="bool" /> - <preference id="status4evar-pref-download-label" name="status4evar.download.label" type="int" /> - <preference id="status4evar-pref-download-label-force" name="status4evar.download.label.force" type="bool" /> - <preference id="status4evar-pref-download-notify-animate" name="status4evar.download.notify.animate" type="bool" /> - <preference id="status4evar-pref-download-notify-timeout" name="status4evar.download.notify.timeout" type="int" /> - <preference id="status4evar-pref-download-progress" name="status4evar.download.progress" type="int" /> - <preference id="status4evar-pref-download-tooltip" name="status4evar.download.tooltip" type="int" /> - - <preference id="status4evar-pref-download-button-action-command" name="status4evar.download.button.action.command" type="string"/> - </preferences> - - <commandset id="status4evar-commandset-download"> - <command id="status4evar-command-download-progress" oncommand="status4evarPrefs.downloadProgressToggle();" /> - </commandset> - - <checkbox id="status4evar-download-force-check" preference="status4evar-pref-download-force" label="&status4evar.download.force.label;" /> - - <checkbox id="status4evar-download-label-force-check" preference="status4evar-pref-download-label-force" label="&status4evar.download.label.force.label;" /> - - <hbox align="center"> - <label id="status4evar-download-label-label" control="status4evar-download-label-menu">&status4evar.download.label.label;</label> - <menulist id="status4evar-download-label-menu" preference="status4evar-pref-download-label" sizetopopup="always"> - <menupopup> - <menuitem value="0" label="&status4evar.option.dlcount;" /> - <menuitem value="1" label="&status4evar.option.dltime;" /> - <menuitem value="2" label="&status4evar.option.both;" /> - </menupopup> - </menulist> - </hbox> - - <hbox align="center"> - <label id="status4evar-download-tooltip-label" control="status4evar-download-tooltip-menu">&status4evar.download.tooltip.label;</label> - <menulist id="status4evar-download-tooltip-menu" preference="status4evar-pref-download-tooltip" sizetopopup="always"> - <menupopup> - <menuitem value="0" label="&status4evar.option.dlcount;" /> - <menuitem value="1" label="&status4evar.option.dltime;" /> - <menuitem value="2" label="&status4evar.option.both;" /> - </menupopup> - </menulist> - </hbox> - - <hbox align="center"> - <label id="status4evar-download-button-action-label" control="status4evar-download-button-action-menu">&status4evar.download.button.action.label;</label> - <menulist id="status4evar-download-button-action-menu" preference="status4evar-pref-download-button-action" sizetopopup="always"> - <menupopup> - <menuitem value="0" label="&status4evar.option.nothing;" /> - <menuitem value="1" label="&status4evar.option.firefoxdefault;" /> - <menuitem value="2" label="&status4evar.option.download.library;" /> - <menuitem value="3" label="&status4evar.option.download.tab;" /> - <menuitem value="4" label="&status4evar.option.download.thirdparty;" id="status4evar-download-button-action-menu-thirdparty" /> - </menupopup> - </menulist> - </hbox> - - <hbox align="center"> - <label id="status4evar-download-notify-timeout-label" control="status4evar-download-notify-timeout-value">&status4evar.download.notify.timeout.label;</label> - <textbox id="status4evar-download-notify-timeout-value" preference="status4evar-pref-download-notify-timeout" type="number" size="3" /> - <label id="status4evar-download-notify-timeout-unit">&status4evar.unit.seconds;</label> - </hbox> - - <checkbox id="status4evar-download-notify-animate-check" preference="status4evar-pref-download-notify-animate" label="&status4evar.download.notify.animate.label;" /> - - <checkbox id="status4evar-download-progress-check" command="status4evar-command-download-progress" label="&status4evar.download.progress.label;" /> - - <vbox class="indent"> - <hbox align="center"> - <radiogroup id="status4evar-download-progress-radiogroup" preference="status4evar-pref-download-progress" - onsyncfrompreference="return status4evarPrefs.downloadProgressSync();"> - <radio value="1" label="&status4evar.download.progress.average.label;" /> - <radio value="2" label="&status4evar.download.progress.max.label;" /> - <radio value="3" label="&status4evar.download.progress.min.label;" /> - </radiogroup> - </hbox> - - <hbox align="center"> - <label id="status4evar-download-color-active-label" control="status4evar-download-color-active-picker">&status4evar.download.color.active.label;</label> - <colorpicker id="status4evar-download-color-active-picker" preference="status4evar-pref-download-color-active" type="button" /> - </hbox> - - <hbox align="center"> - <label id="status4evar-download-color-paused-label" control="status4evar-download-color-paused-picker">&status4evar.download.color.paused.label;</label> - <colorpicker id="status4evar-download-color-paused-picker" preference="status4evar-pref-download-color-paused" type="button" /> - </hbox> - </vbox> - </prefpane> - - <prefpane id="status4evar-pane-addonbar" label="&status4evar.pane.statusbar;"> - <preferences> - <preference id="status4evar-pref-addonbar-borderStyle" name="status4evar.addonbar.borderStyle" type="bool" /> - <preference id="status4evar-pref-addonbar-closeButton" name="status4evar.addonbar.closeButton" type="bool" /> - <preference id="status4evar-pref-addonbar-windowGripper" name="status4evar.addonbar.windowGripper" type="bool" /> - </preferences> - - <checkbox id="status4evar-addonbar-borderStyle-check" preference="status4evar-pref-addonbar-borderStyle" label="&status4evar.addonbar.borderStyle;" /> - - <checkbox id="status4evar-addonbar-closeButton-check" preference="status4evar-pref-addonbar-closeButton" label="&status4evar.addonbar.closeButton;" /> - - <checkbox id="status4evar-addonbar-windowGripper-check" preference="status4evar-pref-addonbar-windowGripper" label="&status4evar.addonbar.windowGripper;" /> - </prefpane> - - <prefpane id="status4evar-pane-advanced" label="&status4evar.pane.advanced;"> - <preferences> - <preference id="status4evar-pref-advanced-status-detectFullScreen" name="status4evar.advanced.status.detectFullScreen" type="bool" /> - <preference id="status4evar-pref-advanced-status-detectVideo" name="status4evar.advanced.status.detectVideo" type="bool" /> - <preference id="browser-pref-urlbar-trimming-enabled" name="browser.urlbar.trimURLs" type="bool" /> - </preferences> - - <vbox flex="1"> - <groupbox id="status4evar-status-urlbar-builtin"> - <caption label="&status4evar.status.urlbar.firefox.builtin.caption;" /> - - <checkbox id="browser-urlbar-trimming-enabled-ckeck" preference="browser-pref-urlbar-trimming-enabled" label="&browser.urlbar.trimming.enabled.label;" /> - </groupbox> - - <groupbox id="status4evar-advanced-status"> - <caption label="&status4evar.pane.status;" /> - - <checkbox id="status4evar-advanced-status-detectFullScreen-check" preference="status4evar-pref-advanced-status-detectFullScreen" label="&status4evar.advanced.status.detectFullScreen;" /> - <checkbox id="status4evar-advanced-status-detectVideo-check" preference="status4evar-pref-advanced-status-detectVideo" label="&status4evar.advanced.status.detectVideo;" /> - </groupbox> - </vbox> - </prefpane> + <prefpane id="status4evar-pane-status" label="&status4evar.pane.status;"> + <preferences> + <preference id="status4evar-pref-status" name="status4evar.status" type="int" /> + <preference id="status4evar-pref-status-default" name="status4evar.status.default" type="bool" /> + <preference id="status4evar-pref-status-network" name="status4evar.status.network" type="bool" + onchange="status4evarPrefs.statusNetworkChanged();" /> + <preference id="status4evar-pref-status-network-xhr" name="status4evar.status.network.xhr" type="bool" /> + <preference id="status4evar-pref-status-timeout" name="status4evar.status.timeout" type="int" + onchange="status4evarPrefs.statusTimeoutChanged();" /> + <preference id="status4evar-pref-status-linkOver" name="status4evar.status.linkOver" type="int" /> + <preference id="status4evar-pref-status-linkOver-delay-show" name="status4evar.status.linkOver.delay.show" type="int" /> + <preference id="status4evar-pref-status-linkOver-delay-hide" name="status4evar.status.linkOver.delay.hide" type="int" /> + <preference id="status4evar-pref-status-toolbar-maxLength" name="status4evar.status.toolbar.maxLength" type="int" + onchange="status4evarPrefs.textLengthChanged();" /> + <preference id="status4evar-pref-status-popup-invertMirror" name="status4evar.status.popup.invertMirror" type="bool" /> + <preference id="status4evar-pref-status-popup-mouseMirror" name="status4evar.status.popup.mouseMirror" type="bool" /> + <preference id="toolkit-pref-dom-status-change" name="dom.disable_window_status_change" type="bool" inverted="true" /> + </preferences> + + <commandset id="status4evar-commandset-status"> + <command id="status4evar-command-status-timeout" oncommand="status4evarPrefs.statusTimeoutToggle();" /> + <command id="status4evar-command-status-toolbar-maxLength" oncommand="status4evarPrefs.textLengthToggle();" /> + </commandset> + + <tabbox id="status4evar-tabbox-status" flex="1"> + <tabs id="status4evar-tabs-status"> + <tab id="status4evar-tab-status-general" label="&status4evar.tab.general;" /> + <tab id="status4evar-tab-status-toolbar" label="&status4evar.tab.toolbar;" /> + <tab id="status4evar-tab-status-popup" label="&status4evar.tab.popup;" /> + </tabs> + + <tabpanels id="status4evar-tabpanels-status" flex="1"> + <tabpanel id="status4evar-tabpanel-status-general" orient="vertical"> + <groupbox id="status4evar-status-general-status"> + <caption label="&status4evar.status.general.status.caption;" /> + + <hbox align="center"> + <label id="status4evar-status-label" control="status4evar-status-menu">&status4evar.status.label;</label> + <menulist id="status4evar-status-menu" preference="status4evar-pref-status" sizetopopup="always"> + <menupopup> + <menuitem label="&status4evar.option.none;" value="0" /> + <menuitem label="&status4evar.option.toolbar;" value="1" /> + <menuitem label="&status4evar.option.popup;" value="3" /> + </menupopup> + </menulist> + </hbox> + + <hbox align="center"> + <checkbox id="status4evar-status-timeout-check" label="&status4evar.status.timeout.label;" + command="status4evar-command-status-timeout" /> + <textbox id="status4evar-status-timeout-value" preference="status4evar-pref-status-timeout" type="number" size="4" + onsyncfrompreference="return status4evarPrefs.statusTimeoutSync();" /> + <label id="status4evar-status-timeout-unit">&status4evar.unit.seconds;</label> + </hbox> + + <checkbox id="status4evar-status-default-check" preference="status4evar-pref-status-default" label="&status4evar.status.default.label;" /> + + <checkbox id="status4evar-status-network-check" preference="status4evar-pref-status-network" label="&status4evar.status.network.label;" + onsyncfrompreference="return status4evarPrefs.statusNetworkSync();" /> + + <hbox align="center" class="indent"> + <checkbox id="status4evar-status-network-xhr-check" preference="status4evar-pref-status-network-xhr" label="&status4evar.status.network.xhr.label;" /> + </hbox> + + <checkbox id="toolkit-dom-status-change-check" preference="toolkit-pref-dom-status-change" label="&toolkit.dom.status.change.label;" /> + </groupbox> + + <groupbox id="status4evar-status-general-linkOver"> + <caption label="&status4evar.status.general.linkOver.caption;" /> + + <hbox align="center"> + <label id="status4evar-status-linkOver-label" control="status4evar-status-linkOver-menu">&status4evar.status.linkOver.label;</label> + <menulist id="status4evar-status-linkOver-menu" preference="status4evar-pref-status-linkOver" sizetopopup="always"> + <menupopup> + <menuitem label="&status4evar.option.none;" value="0" /> + <menuitem label="&status4evar.option.toolbar;" value="1" /> + <menuitem label="&status4evar.option.popup;" value="3" /> + </menupopup> + </menulist> + </hbox> + + <hbox align="center"> + <label id="status4evar-status-linkOver-delay-show-label" control="status4evar-status-linkOver-delay-show-value">&status4evar.status.linkOver.delay.show.label;</label> + <textbox id="status4evar-status-linkOver-delay-show-value" preference="status4evar-pref-status-linkOver-delay-show" type="number" size="5" /> + <label id="status4evar-status-linkOver-delay-show-unit">&status4evar.unit.milliseconds;</label> + </hbox> + + <hbox align="center"> + <label id="status4evar-status-linkOver-delay-hide-label" control="status4evar-status-linkOver-delay-hide-value">&status4evar.status.linkOver.delay.hide.label;</label> + <textbox id="status4evar-status-linkOver-delay-hide-value" preference="status4evar-pref-status-linkOver-delay-hide" type="number" size="5" /> + <label id="status4evar-status-linkOver-delay-hide-unit">&status4evar.unit.milliseconds;</label> + </hbox> + </groupbox> + + </tabpanel> + + <tabpanel id="status4evar-tabpanel-status-toolbar" orient="vertical"> + <hbox align="center"> + <checkbox id="status4evar-status-toolbar-maxLength-check" label="&status4evar.status.toolbar.maxLength.label;" + command="status4evar-command-status-toolbar-maxLength" /> + <textbox id="status4evar-status-toolbar-maxLength-value" preference="status4evar-pref-status-toolbar-maxLength" type="number" size="4" + onsyncfrompreference="return status4evarPrefs.textLengthSync();" /> + <label id="status4evar-status-toolbar-maxLength-unit">&status4evar.unit.px;</label> + </hbox> + </tabpanel> + + <tabpanel id="status4evar-tabpanel-status-popup" orient="vertical"> + <checkbox id="status4evar-status-popup-invertMirror-check" preference="status4evar-pref-status-popup-invertMirror" label="&status4evar.status.popup.invertMirror.label;" /> + + <checkbox id="status4evar-status-popup-mouseMirror-check" preference="status4evar-pref-status-popup-mouseMirror" label="&status4evar.status.popup.mouseMirror.label;" /> + </tabpanel> + + </tabpanels> + </tabbox> + </prefpane> + + <prefpane id="status4evar-pane-progress" label="&status4evar.pane.progress;"> + <preferences> + <preference id="status4evar-pref-progress-toolbar-force" name="status4evar.progress.toolbar.force" type="bool" /> + <preference id="status4evar-pref-progress-toolbar-style" name="status4evar.progress.toolbar.style" type="bool" + onchange="status4evarPrefs.progressToolbarStyleChanged();" /> + <preference id="status4evar-pref-progress-toolbar-css" name="status4evar.progress.toolbar.css" type="string" + onchange="status4evarPrefs.progressToolbarCSSChanged();" /> + </preferences> + + <commandset id="status4evar-commandset-status"> + </commandset> + + <checkbox id="status4evar-progress-toolbar-force-check" preference="status4evar-pref-progress-toolbar-force" label="&status4evar.progress.toolbar.force.label;" /> + + <checkbox id="status4evar-progress-toolbar-style-check" preference="status4evar-pref-progress-toolbar-style" label="&status4evar.progress.style.label;" + onsyncfrompreference="return status4evarPrefs.progressToolbarStyleSync();" /> + + <vbox class="css-bg-editor" preference="status4evar-pref-progress-toolbar-css" preference-editable="true" flex="1"> + <progressmeter id="status4evar-progress-bar" value="75" flex="1" /> + </vbox> + </prefpane> + + <prefpane id="status4evar-pane-download" label="&status4evar.pane.download;"> + <preferences> + <preference id="status4evar-pref-download-button-action" name="status4evar.download.button.action" type="int" /> + <preference id="status4evar-pref-download-color-active" name="status4evar.download.color.active" type="string" /> + <preference id="status4evar-pref-download-color-paused" name="status4evar.download.color.paused" type="string" /> + <preference id="status4evar-pref-download-force" name="status4evar.download.force" type="bool" /> + <preference id="status4evar-pref-download-label" name="status4evar.download.label" type="int" /> + <preference id="status4evar-pref-download-label-force" name="status4evar.download.label.force" type="bool" /> + <preference id="status4evar-pref-download-notify-animate" name="status4evar.download.notify.animate" type="bool" /> + <preference id="status4evar-pref-download-notify-timeout" name="status4evar.download.notify.timeout" type="int" /> + <preference id="status4evar-pref-download-progress" name="status4evar.download.progress" type="int" /> + <preference id="status4evar-pref-download-tooltip" name="status4evar.download.tooltip" type="int" /> + + <preference id="status4evar-pref-download-button-action-command" name="status4evar.download.button.action.command" type="string"/> + </preferences> + + <commandset id="status4evar-commandset-download"> + <command id="status4evar-command-download-progress" oncommand="status4evarPrefs.downloadProgressToggle();" /> + </commandset> + + <checkbox id="status4evar-download-force-check" preference="status4evar-pref-download-force" label="&status4evar.download.force.label;" /> + + <checkbox id="status4evar-download-label-force-check" preference="status4evar-pref-download-label-force" label="&status4evar.download.label.force.label;" /> + + <hbox align="center"> + <label id="status4evar-download-label-label" control="status4evar-download-label-menu">&status4evar.download.label.label;</label> + <menulist id="status4evar-download-label-menu" preference="status4evar-pref-download-label" sizetopopup="always"> + <menupopup> + <menuitem value="0" label="&status4evar.option.dlcount;" /> + <menuitem value="1" label="&status4evar.option.dltime;" /> + <menuitem value="2" label="&status4evar.option.both;" /> + </menupopup> + </menulist> + </hbox> + + <hbox align="center"> + <label id="status4evar-download-tooltip-label" control="status4evar-download-tooltip-menu">&status4evar.download.tooltip.label;</label> + <menulist id="status4evar-download-tooltip-menu" preference="status4evar-pref-download-tooltip" sizetopopup="always"> + <menupopup> + <menuitem value="0" label="&status4evar.option.dlcount;" /> + <menuitem value="1" label="&status4evar.option.dltime;" /> + <menuitem value="2" label="&status4evar.option.both;" /> + </menupopup> + </menulist> + </hbox> + + <hbox align="center"> + <label id="status4evar-download-button-action-label" control="status4evar-download-button-action-menu">&status4evar.download.button.action.label;</label> + <menulist id="status4evar-download-button-action-menu" preference="status4evar-pref-download-button-action" sizetopopup="always"> + <menupopup> + <menuitem value="0" label="&status4evar.option.nothing;" /> + <menuitem value="1" label="&status4evar.option.firefoxdefault;" /> + <menuitem value="2" label="&status4evar.option.download.library;" /> + <menuitem value="3" label="&status4evar.option.download.tab;" /> + <menuitem value="4" label="&status4evar.option.download.thirdparty;" id="status4evar-download-button-action-menu-thirdparty" /> + </menupopup> + </menulist> + </hbox> + + <hbox align="center"> + <label id="status4evar-download-notify-timeout-label" control="status4evar-download-notify-timeout-value">&status4evar.download.notify.timeout.label;</label> + <textbox id="status4evar-download-notify-timeout-value" preference="status4evar-pref-download-notify-timeout" type="number" size="3" /> + <label id="status4evar-download-notify-timeout-unit">&status4evar.unit.seconds;</label> + </hbox> + + <checkbox id="status4evar-download-notify-animate-check" preference="status4evar-pref-download-notify-animate" label="&status4evar.download.notify.animate.label;" /> + + <checkbox id="status4evar-download-progress-check" command="status4evar-command-download-progress" label="&status4evar.download.progress.label;" /> + + <vbox class="indent"> + <hbox align="center"> + <radiogroup id="status4evar-download-progress-radiogroup" preference="status4evar-pref-download-progress" + onsyncfrompreference="return status4evarPrefs.downloadProgressSync();"> + <radio value="1" label="&status4evar.download.progress.average.label;" /> + <radio value="2" label="&status4evar.download.progress.max.label;" /> + <radio value="3" label="&status4evar.download.progress.min.label;" /> + </radiogroup> + </hbox> + + <hbox align="center"> + <label id="status4evar-download-color-active-label" control="status4evar-download-color-active-picker">&status4evar.download.color.active.label;</label> + <colorpicker id="status4evar-download-color-active-picker" preference="status4evar-pref-download-color-active" type="button" /> + </hbox> + + <hbox align="center"> + <label id="status4evar-download-color-paused-label" control="status4evar-download-color-paused-picker">&status4evar.download.color.paused.label;</label> + <colorpicker id="status4evar-download-color-paused-picker" preference="status4evar-pref-download-color-paused" type="button" /> + </hbox> + </vbox> + </prefpane> + + <prefpane id="status4evar-pane-addonbar" label="&status4evar.pane.statusbar;"> + <preferences> + <preference id="status4evar-pref-addonbar-borderStyle" name="status4evar.addonbar.borderStyle" type="bool" /> + <preference id="status4evar-pref-addonbar-closeButton" name="status4evar.addonbar.closeButton" type="bool" /> + <preference id="status4evar-pref-addonbar-windowGripper" name="status4evar.addonbar.windowGripper" type="bool" /> + </preferences> + + <checkbox id="status4evar-addonbar-borderStyle-check" preference="status4evar-pref-addonbar-borderStyle" label="&status4evar.addonbar.borderStyle;" /> + + <checkbox id="status4evar-addonbar-closeButton-check" preference="status4evar-pref-addonbar-closeButton" label="&status4evar.addonbar.closeButton;" /> + + <checkbox id="status4evar-addonbar-windowGripper-check" preference="status4evar-pref-addonbar-windowGripper" label="&status4evar.addonbar.windowGripper;" /> + </prefpane> + + <prefpane id="status4evar-pane-advanced" label="&status4evar.pane.advanced;"> + <preferences> + <preference id="status4evar-pref-advanced-status-detectFullScreen" name="status4evar.advanced.status.detectFullScreen" type="bool" /> + <preference id="status4evar-pref-advanced-status-detectVideo" name="status4evar.advanced.status.detectVideo" type="bool" /> + <preference id="browser-pref-urlbar-trimming-enabled" name="browser.urlbar.trimURLs" type="bool" /> + </preferences> + + <vbox flex="1"> + <groupbox id="status4evar-status-urlbar-builtin"> + <caption label="&status4evar.status.urlbar.firefox.builtin.caption;" /> + + <checkbox id="browser-urlbar-trimming-enabled-ckeck" preference="browser-pref-urlbar-trimming-enabled" label="&browser.urlbar.trimming.enabled.label;" /> + </groupbox> + + <groupbox id="status4evar-advanced-status"> + <caption label="&status4evar.pane.status;" /> + + <checkbox id="status4evar-advanced-status-detectFullScreen-check" preference="status4evar-pref-advanced-status-detectFullScreen" label="&status4evar.advanced.status.detectFullScreen;" /> + <checkbox id="status4evar-advanced-status-detectVideo-check" preference="status4evar-pref-advanced-status-detectVideo" label="&status4evar.advanced.status.detectVideo;" /> + </groupbox> + </vbox> + </prefpane> </prefwindow> diff --git a/application/palemoon/components/statusbar/content/tabbrowser.xml b/application/palemoon/components/statusbar/content/tabbrowser.xml index 5119fa58a..2f475771d 100644 --- a/application/palemoon/components/statusbar/content/tabbrowser.xml +++ b/application/palemoon/components/statusbar/content/tabbrowser.xml @@ -9,210 +9,210 @@ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl"> - <binding id="statuspanel" display="xul:hbox" extends="chrome://browser/content/tabbrowser.xml#statuspanel"> - <implementation> - <!-- --> - <!-- Inverted mirror handling --> - <!-- --> - - <field name="_invertMirror"><![CDATA[ - false - ]]></field> - - <property name="invertMirror"> - <setter><![CDATA[ - this._invertMirror = val; - this.mirror = this._isMirrored; - return val; - ]]></setter> - <getter><![CDATA[ - return this._invertMirror; - ]]></getter> - </property> - - <!-- --> - <!-- Mouse mirror handling --> - <!-- --> - - <field name="_mouseMirror"><![CDATA[ - true - ]]></field> - - <field name="_mouseMirrorListen"><![CDATA[ - false - ]]></field> - - <property name="mouseMirror"> - <setter><![CDATA[ - this._mouseMirror = val; - this.setupMouseMirror(this.value); - return val; - ]]></setter> - <getter><![CDATA[ - return this._mouseMirror; - ]]></getter> - </property> - - <method name="setupMouseMirror"> - <parameter name="val"/> - <body><![CDATA[ - if(val && this._mouseMirror) - { - this._calcMouseTargetRect(); - if(!this._mouseMirrorListen) - { - MousePosTracker.addListener(this); - this._mouseMirrorListen = true; - } - } - else - { - this.mirror = false; - if(this._mouseMirrorListen) - { - MousePosTracker.removeListener(this); - this._mouseMirrorListen = false; - } - } - ]]></body> - </method> - - <method name="_calcMouseTargetRect"> - <body><![CDATA[ - let alignRight = false; - let isRTL = (getComputedStyle(document.documentElement).direction == "rtl"); - if((this._invertMirror && !isRTL) || (!this._invertMirror && isRTL)) - { - alignRight = true; - } - - let rect = this.getBoundingClientRect(); - this._mouseTargetRect = - { - top: rect.top, - bottom: rect.bottom, - left: ((alignRight) ? window.innerWidth - rect.width : 0), - right: ((alignRight) ? window.innerWidth : rect.width) - }; - ]]></body> - </method> - - <method name="onMouseEnter"> - <body><![CDATA[ - this.mirror = true; - ]]></body> - </method> - - <method name="onMouseLeave"> - <body><![CDATA[ - this.mirror = false; - ]]></body> - </method> - - <!-- --> - <!-- Mirror handling --> - <!-- --> - - <field name="_isMirrored"><![CDATA[ - false - ]]></field> - - <property name="mirror"> - <setter><![CDATA[ - this._isMirrored = val; - if(this._invertMirror) - { - val = !val; - } - - this.setBooleanAttr("mirror", val); - ]]></setter> - <getter><![CDATA[ - return this._isMirrored; - ]]></getter> - </property> - - <method name="_mirror"> - <body><![CDATA[ - this.mirror = !this._isMirrored; - ]]></body> - </method> - - <!-- --> - <!-- Value handling --> - <!-- --> - - <property name="label"> - <setter><![CDATA[ - if(window.caligon && window.caligon.status4evar) - { - window.caligon.status4evar.statusService.setStatusText(val); - } - return undefined; - ]]></setter> - <getter><![CDATA[ - if(window.caligon && window.caligon.status4evar) - { - return window.caligon.status4evar.statusService.getStatusText(); - } - return ""; - ]]></getter> - </property> - - <property name="value"> - <setter><![CDATA[ - this.setValue(val); - this.setupMouseMirror(val); - return val; - ]]></setter> - <getter><![CDATA[ - return ((this.hasAttribute("inactive")) ? "" : this.getAttribute("label")); - ]]></getter> - </property> - - <method name="setValue"> - <parameter name="val"/> - <body><![CDATA[ - if((this.getAttribute("type") || "").indexOf("network") > -1 && (this.getAttribute("previoustype") || "").indexOf("network") > -1) - { - this.style.minWidth = getComputedStyle(this).width; - } - else - { - this.style.minWidth = ""; - } - - if(val) - { - this.setAttribute("label", val); - this.setBooleanAttr("inactive", false); - } - else - { - this.setBooleanAttr("inactive", true); - } - ]]></body> - </method> - - <!-- --> - <!-- Helpers --> - <!-- --> - - <method name="setBooleanAttr"> - <parameter name="name"/> - <parameter name="val"/> - <body><![CDATA[ - if(val) - { - this.setAttribute(name, "true"); - } - else - { - this.removeAttribute(name); - } - ]]></body> - </method> - </implementation> - </binding> + <binding id="statuspanel" display="xul:hbox" extends="chrome://browser/content/tabbrowser.xml#statuspanel"> + <implementation> + <!-- --> + <!-- Inverted mirror handling --> + <!-- --> + + <field name="_invertMirror"><![CDATA[ + false + ]]></field> + + <property name="invertMirror"> + <setter><![CDATA[ + this._invertMirror = val; + this.mirror = this._isMirrored; + return val; + ]]></setter> + <getter><![CDATA[ + return this._invertMirror; + ]]></getter> + </property> + + <!-- --> + <!-- Mouse mirror handling --> + <!-- --> + + <field name="_mouseMirror"><![CDATA[ + true + ]]></field> + + <field name="_mouseMirrorListen"><![CDATA[ + false + ]]></field> + + <property name="mouseMirror"> + <setter><![CDATA[ + this._mouseMirror = val; + this.setupMouseMirror(this.value); + return val; + ]]></setter> + <getter><![CDATA[ + return this._mouseMirror; + ]]></getter> + </property> + + <method name="setupMouseMirror"> + <parameter name="val"/> + <body><![CDATA[ + if(val && this._mouseMirror) + { + this._calcMouseTargetRect(); + if(!this._mouseMirrorListen) + { + MousePosTracker.addListener(this); + this._mouseMirrorListen = true; + } + } + else + { + this.mirror = false; + if(this._mouseMirrorListen) + { + MousePosTracker.removeListener(this); + this._mouseMirrorListen = false; + } + } + ]]></body> + </method> + + <method name="_calcMouseTargetRect"> + <body><![CDATA[ + let alignRight = false; + let isRTL = (getComputedStyle(document.documentElement).direction == "rtl"); + if((this._invertMirror && !isRTL) || (!this._invertMirror && isRTL)) + { + alignRight = true; + } + + let rect = this.getBoundingClientRect(); + this._mouseTargetRect = + { + top: rect.top, + bottom: rect.bottom, + left: ((alignRight) ? window.innerWidth - rect.width : 0), + right: ((alignRight) ? window.innerWidth : rect.width) + }; + ]]></body> + </method> + + <method name="onMouseEnter"> + <body><![CDATA[ + this.mirror = true; + ]]></body> + </method> + + <method name="onMouseLeave"> + <body><![CDATA[ + this.mirror = false; + ]]></body> + </method> + + <!-- --> + <!-- Mirror handling --> + <!-- --> + + <field name="_isMirrored"><![CDATA[ + false + ]]></field> + + <property name="mirror"> + <setter><![CDATA[ + this._isMirrored = val; + if(this._invertMirror) + { + val = !val; + } + + this.setBooleanAttr("mirror", val); + ]]></setter> + <getter><![CDATA[ + return this._isMirrored; + ]]></getter> + </property> + + <method name="_mirror"> + <body><![CDATA[ + this.mirror = !this._isMirrored; + ]]></body> + </method> + + <!-- --> + <!-- Value handling --> + <!-- --> + + <property name="label"> + <setter><![CDATA[ + if(window.caligon && window.caligon.status4evar) + { + window.caligon.status4evar.statusService.setStatusText(val); + } + return undefined; + ]]></setter> + <getter><![CDATA[ + if(window.caligon && window.caligon.status4evar) + { + return window.caligon.status4evar.statusService.getStatusText(); + } + return ""; + ]]></getter> + </property> + + <property name="value"> + <setter><![CDATA[ + this.setValue(val); + this.setupMouseMirror(val); + return val; + ]]></setter> + <getter><![CDATA[ + return ((this.hasAttribute("inactive")) ? "" : this.getAttribute("label")); + ]]></getter> + </property> + + <method name="setValue"> + <parameter name="val"/> + <body><![CDATA[ + if((this.getAttribute("type") || "").indexOf("network") > -1 && (this.getAttribute("previoustype") || "").indexOf("network") > -1) + { + this.style.minWidth = getComputedStyle(this).width; + } + else + { + this.style.minWidth = ""; + } + + if(val) + { + this.setAttribute("label", val); + this.setBooleanAttr("inactive", false); + } + else + { + this.setBooleanAttr("inactive", true); + } + ]]></body> + </method> + + <!-- --> + <!-- Helpers --> + <!-- --> + + <method name="setBooleanAttr"> + <parameter name="name"/> + <parameter name="val"/> + <body><![CDATA[ + if(val) + { + this.setAttribute(name, "true"); + } + else + { + this.removeAttribute(name); + } + ]]></body> + </method> + </implementation> + </binding> </bindings> diff --git a/application/palemoon/components/statusbar/status4evar.idl b/application/palemoon/components/statusbar/status4evar.idl index d14fcbcd1..534dea31c 100644 --- a/application/palemoon/components/statusbar/status4evar.idl +++ b/application/palemoon/components/statusbar/status4evar.idl @@ -9,49 +9,49 @@ interface nsIDOMWindow; [scriptable, uuid(33d0433d-07be-4dc4-87fd-954057310efd)] interface nsIStatus4Evar : nsISupports { - readonly attribute boolean addonbarBorderStyle; - readonly attribute boolean addonbarCloseButton; - readonly attribute boolean addonbarLegacyShim; - readonly attribute boolean addonbarWindowGripper; - - readonly attribute boolean advancedStatusDetectFullScreen; - readonly attribute boolean advancedStatusDetectVideo; - - readonly attribute long downloadButtonAction; - readonly attribute ACString downloadButtonActionCommand; - readonly attribute ACString downloadColorActive; - readonly attribute ACString downloadColorPaused; - readonly attribute boolean downloadForce; - readonly attribute long downloadLabel; - readonly attribute boolean downloadLabelForce; - readonly attribute boolean downloadNotifyAnimate; - readonly attribute long downloadNotifyTimeout; - readonly attribute long downloadProgress; - readonly attribute long downloadTooltip; - - readonly attribute boolean firstRun; - readonly attribute boolean firstRunAustralis; - - readonly attribute ACString progressToolbarCSS; - readonly attribute boolean progressToolbarForce; - readonly attribute boolean progressToolbarStyle; - readonly attribute boolean progressToolbarStyleAdvanced; - - readonly attribute long status; - readonly attribute boolean statusDefault; - readonly attribute boolean statusNetwork; - readonly attribute boolean statusNetworkXHR; - readonly attribute long statusTimeout; - readonly attribute long statusLinkOver; - readonly attribute long statusLinkOverDelayShow; - readonly attribute long statusLinkOverDelayHide; - - readonly attribute long statusToolbarMaxLength; - - readonly attribute boolean statusToolbarInvertMirror; - readonly attribute boolean statusToolbarMouseMirror; - - void resetPrefs(); - void updateWindow(in nsIDOMWindow win); + readonly attribute boolean addonbarBorderStyle; + readonly attribute boolean addonbarCloseButton; + readonly attribute boolean addonbarLegacyShim; + readonly attribute boolean addonbarWindowGripper; + + readonly attribute boolean advancedStatusDetectFullScreen; + readonly attribute boolean advancedStatusDetectVideo; + + readonly attribute long downloadButtonAction; + readonly attribute ACString downloadButtonActionCommand; + readonly attribute ACString downloadColorActive; + readonly attribute ACString downloadColorPaused; + readonly attribute boolean downloadForce; + readonly attribute long downloadLabel; + readonly attribute boolean downloadLabelForce; + readonly attribute boolean downloadNotifyAnimate; + readonly attribute long downloadNotifyTimeout; + readonly attribute long downloadProgress; + readonly attribute long downloadTooltip; + + readonly attribute boolean firstRun; + readonly attribute boolean firstRunAustralis; + + readonly attribute ACString progressToolbarCSS; + readonly attribute boolean progressToolbarForce; + readonly attribute boolean progressToolbarStyle; + readonly attribute boolean progressToolbarStyleAdvanced; + + readonly attribute long status; + readonly attribute boolean statusDefault; + readonly attribute boolean statusNetwork; + readonly attribute boolean statusNetworkXHR; + readonly attribute long statusTimeout; + readonly attribute long statusLinkOver; + readonly attribute long statusLinkOverDelayShow; + readonly attribute long statusLinkOverDelayHide; + + readonly attribute long statusToolbarMaxLength; + + readonly attribute boolean statusToolbarInvertMirror; + readonly attribute boolean statusToolbarMouseMirror; + + void resetPrefs(); + void updateWindow(in nsIDOMWindow win); }; diff --git a/application/palemoon/components/statusbar/status4evar.js b/application/palemoon/components/statusbar/status4evar.js index abc6c9175..4aa2e3e78 100644 --- a/application/palemoon/components/statusbar/status4evar.js +++ b/application/palemoon/components/statusbar/status4evar.js @@ -18,677 +18,677 @@ function Status_4_Evar(){} Status_4_Evar.prototype = { - classID: Components.ID("{33d0433d-07be-4dc4-87fd-954057310efd}"), - QueryInterface: XPCOMUtils.generateQI([ - CI.nsISupportsWeakReference, - CI.nsIObserver, - CI.nsIStatus4Evar - ]), - - prefs: null, - - addonbarBorderStyle: false, - addonbarCloseButton: false, - addonbarWindowGripper: true, - - advancedStatusDetectFullScreen: true, - advancedStatusDetectVideo: true, - - downloadButtonAction: 1, - downloadButtonActionCommand: "", - downloadColorActive: null, - downloadColorPaused: null, - downloadForce: false, - downloadLabel: 0, - downloadLabelForce: true, - downloadNotifyAnimate: true, - downloadNotifyTimeout: 60000, - downloadProgress: 1, - downloadTooltip: 1, - - firstRun: true, - - progressToolbarCSS: null, - progressToolbarForce: false, - progressToolbarStyle: false, - - status: 1, - statusDefault: true, - statusNetwork: true, - statusTimeout: 10000, - statusLinkOver: 1, - statusLinkOverDelayShow: 70, - statusLinkOverDelayHide: 150, - - statusToolbarMaxLength: 0, - - statusToolbarInvertMirror: false, - statusToolbarMouseMirror: true, - - pref_registry: - { - "addonbar.borderStyle": - { - update: function() - { - this.addonbarBorderStyle = this.prefs.getBoolPref("addonbar.borderStyle"); - }, - updateWindow: function(win) - { - let browser_bottom_box = win.caligon.status4evar.getters.browserBottomBox; - if(browser_bottom_box) - { - this.setBoolElementAttribute(browser_bottom_box, "s4eboarder", this.addonbarBorderStyle); - } - } - }, - - "addonbar.closeButton": - { - update: function() - { - this.addonbarCloseButton = this.prefs.getBoolPref("addonbar.closeButton"); - }, - updateWindow: function(win) - { - let addonbar_close_button = win.caligon.status4evar.getters.addonbarCloseButton; - if(addonbar_close_button) - { - addonbar_close_button.hidden = !this.addonbarCloseButton; - } - } - }, - - "addonbar.windowGripper": - { - update: function() - { - this.addonbarWindowGripper = this.prefs.getBoolPref("addonbar.windowGripper"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.toolbars.updateWindowGripper(true); - } - }, - - "advanced.status.detectFullScreen": - { - update: function() - { - this.advancedStatusDetectFullScreen = this.prefs.getBoolPref("advanced.status.detectFullScreen"); - } - }, - - "advanced.status.detectVideo": - { - update: function() - { - this.advancedStatusDetectVideo = this.prefs.getBoolPref("advanced.status.detectVideo"); - } - }, - - "download.button.action": - { - update: function() - { - this.downloadButtonAction = this.prefs.getIntPref("download.button.action"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.downloadStatus.updateBinding(); - } - }, - - "download.button.action.command": - { - update: function() - { - this.downloadButtonActionCommand = this.prefs.getCharPref("download.button.action.command"); - } - }, - - "download.color.active": - { - update: function() - { - this.downloadColorActive = this.prefs.getCharPref("download.color.active"); - }, - updateDynamicStyle: function(sheet) - { - sheet.cssRules[2].style.backgroundColor = this.downloadColorActive; - } - }, - - "download.color.paused": - { - update: function() - { - this.downloadColorPaused = this.prefs.getCharPref("download.color.paused"); - }, - updateDynamicStyle: function(sheet) - { - sheet.cssRules[3].style.backgroundColor = this.downloadColorPaused; - } - }, - - "download.force": - { - update: function() - { - this.downloadForce = this.prefs.getBoolPref("download.force"); - }, - updateWindow: function(win) - { - let download_button = win.caligon.status4evar.getters.downloadButton; - if(download_button) - { - this.setBoolElementAttribute(download_button, "forcevisible", this.downloadForce); - } - - let download_notify_anchor = win.caligon.status4evar.getters.downloadNotifyAnchor; - this.setBoolElementAttribute(download_notify_anchor, "forcevisible", this.downloadForce); - } - }, - - "download.label": - { - update: function() - { - this.downloadLabel = this.prefs.getIntPref("download.label"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.downloadStatus.updateButton(); - } - }, - - "download.label.force": - { - update: function() - { - this.downloadLabelForce = this.prefs.getBoolPref("download.label.force"); - }, - updateWindow: function(win) - { - let download_button = win.caligon.status4evar.getters.downloadButton; - if(download_button) - { - this.setBoolElementAttribute(download_button, "forcelabel", this.downloadLabelForce); - } - } - }, - - "download.notify.animate": - { - update: function() - { - this.downloadNotifyAnimate = this.prefs.getBoolPref("download.notify.animate"); - } - }, - - "download.notify.timeout": - { - update: function() - { - this.downloadNotifyTimeout = (this.prefs.getIntPref("download.notify.timeout") * 1000); - } - }, - - "download.progress": - { - update: function() - { - this.downloadProgress = this.prefs.getIntPref("download.progress"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.downloadStatus.updateButton(); - } - }, - - "download.tooltip": - { - update: function() - { - this.downloadTooltip = this.prefs.getIntPref("download.tooltip"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.downloadStatus.updateButton(); - } - }, - - "progress.toolbar.css": - { - update: function() - { - this.progressToolbarCSS = this.prefs.getCharPref("progress.toolbar.css"); - }, - updateDynamicStyle: function(sheet) - { - sheet.cssRules[1].style.background = this.progressToolbarCSS; - } - }, - - "progress.toolbar.force": - { - update: function() - { - this.progressToolbarForce = this.prefs.getBoolPref("progress.toolbar.force"); - }, - updateWindow: function(win) - { - let toolbar_progress = win.caligon.status4evar.getters.toolbarProgress; - if(toolbar_progress) - { - this.setBoolElementAttribute(toolbar_progress, "forcevisible", this.progressToolbarForce); - } - } - }, - - "progress.toolbar.style": - { - update: function() - { - this.progressToolbarStyle = this.prefs.getBoolPref("progress.toolbar.style"); - }, - updateWindow: function(win) - { - let toolbar_progress = win.caligon.status4evar.getters.toolbarProgress; - if(toolbar_progress) - { - this.setBoolElementAttribute(toolbar_progress, "s4estyle", this.progressToolbarStyle); - } - } - }, - - "status": - { - update: function() - { - this.status = this.prefs.getIntPref("status"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.statusService.clearStatusField(); - win.caligon.status4evar.statusService.updateStatusField(true); - } - }, - - "status.default": - { - update: function() - { - this.statusDefault = this.prefs.getBoolPref("status.default"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.statusService.buildTextOrder(); - win.caligon.status4evar.statusService.updateStatusField(true); - } - }, - - "status.linkOver": - { - update: function() - { - this.statusLinkOver = this.prefs.getIntPref("status.linkOver"); - } - }, - - "status.linkOver.delay.show": - { - update: function() - { - this.statusLinkOverDelayShow = this.prefs.getIntPref("status.linkOver.delay.show"); - } - }, - - "status.linkOver.delay.hide": - { - update: function() - { - this.statusLinkOverDelayHide = this.prefs.getIntPref("status.linkOver.delay.hide"); - } - }, - - "status.network": - { - update: function() - { - this.statusNetwork = this.prefs.getBoolPref("status.network"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.statusService.buildTextOrder(); - } - }, - - "status.network.xhr": - { - update: function() - { - this.statusNetworkXHR = this.prefs.getBoolPref("status.network.xhr"); - }, - updateWindow: function(win) - { - win.caligon.status4evar.statusService.buildTextOrder(); - } - }, - - "status.timeout": - { - update: function() - { - this.statusTimeout = (this.prefs.getIntPref("status.timeout") * 1000); - }, - updateWindow: function(win) - { - win.caligon.status4evar.statusService.updateStatusField(true); - } - }, - - "status.toolbar.maxLength": - { - update: function() - { - this.statusToolbarMaxLength = this.prefs.getIntPref("status.toolbar.maxLength"); - }, - updateWindow: function(win) - { - let status_widget = win.caligon.status4evar.getters.statusWidget; - if(status_widget) - { - status_widget.maxWidth = (this.statusToolbarMaxLength || ""); - } - } - }, - - "status.popup.invertMirror": - { - update: function() - { - this.statusToolbarInvertMirror = this.prefs.getBoolPref("status.popup.invertMirror"); - }, - updateWindow: function(win) - { - let statusOverlay = win.caligon.status4evar.getters.statusOverlay; - if(statusOverlay) - { - statusOverlay.invertMirror = this.statusToolbarInvertMirror; - } - } - }, - - "status.popup.mouseMirror": - { - update: function() - { - this.statusToolbarMouseMirror = this.prefs.getBoolPref("status.popup.mouseMirror"); - }, - updateWindow: function(win) - { - let statusOverlay = win.caligon.status4evar.getters.statusOverlay; - if(statusOverlay) - { - statusOverlay.mouseMirror = this.statusToolbarMouseMirror; - } - } - } - - }, - - // nsIObserver - observe: function(subject, topic, data) - { - try - { - switch(topic) - { - case "profile-after-change": - this.startup(); - break; - case "quit-application": - this.shutdown(); - break; - case "nsPref:changed": - this.updatePref(data, true); - break; - } - } - catch(e) - { - CU.reportError(e); - } - }, - - startup: function() - { - this.prefs = Services.prefs.getBranch("status4evar.").QueryInterface(CI.nsIPrefBranch2); - - this.firstRun = this.prefs.getBoolPref("firstRun"); - if(this.firstRun) - { - this.prefs.setBoolPref("firstRun", false); - } - - this.migrate(); - - for(let pref in this.pref_registry) - { - let pro = this.pref_registry[pref]; - - pro.update = pro.update.bind(this); - if(pro.updateWindow) - { - pro.updateWindow = pro.updateWindow.bind(this); - } - if(pro.updateDynamicStyle) - { - pro.updateDynamicStyle = pro.updateDynamicStyle.bind(this); - } - - this.prefs.addObserver(pref, this, true); - - this.updatePref(pref, false); - } - - Services.obs.addObserver(this, "quit-application", true); - }, - - shutdown: function() - { - Services.obs.removeObserver(this, "quit-application"); - - for(let pref in this.pref_registry) - { - this.prefs.removeObserver(pref, this); - } - - this.prefs = null; - }, - - migrate: function() - { - if(!this.firstRun) - { - let migration = 0; - try - { - migration = this.prefs.getIntPref("migration"); - } - catch(e) {} - - switch(migration) - { - case 5: - this.migrateBoolPref("status.detectFullScreen", "advanced.status.detectFullScreen"); - case 6: - let oldDownloadAction = this.prefs.getIntPref("download.button.action"); - let newDownloadAction = 1; - switch(oldDownloadAction) - { - case 2: - newDownloadAction = 1; - break; - case 3: - newDownloadAction = 2; - break; - case 4: - newDownloadAction = 1; - break; - } - this.prefs.setIntPref("download.button.action", newDownloadAction); - case 7: - let progressLocation = this.prefs.getIntPref("status"); - if (progressLocation == 2) - this.prefs.setIntPref("status", 1); - let linkOverLocation = this.prefs.getIntPref("status.linkOver"); - if (linkOverLocation == 2) - this.prefs.setIntPref("status.linkOver", 1); - break; - case CURRENT_MIGRATION: - break; - } - } - - this.prefs.setIntPref("migration", CURRENT_MIGRATION); - }, - - migrateBoolPref: function(oldPref, newPref) - { - if(this.prefs.prefHasUserValue(oldPref)) - { - this.prefs.setBoolPref(newPref, this.prefs.getBoolPref(oldPref)); - this.prefs.clearUserPref(oldPref); - } - }, - - migrateIntPref: function(oldPref, newPref) - { - if(this.prefs.prefHasUserValue(oldPref)) - { - this.prefs.setIntPref(newPref, this.prefs.getIntPref(oldPref)); - this.prefs.clearUserPref(oldPref); - } - }, - - migrateCharPref: function(oldPref, newPref) - { - if(this.prefs.prefHasUserValue(oldPref)) - { - this.prefs.setCharPref(newPref, this.prefs.getCharPref(oldPref)); - this.prefs.clearUserPref(oldPref); - } - }, - - updatePref: function(pref, updateWindows) - { - if(!(pref in this.pref_registry)) - { - return; - } - let pro = this.pref_registry[pref]; - - pro.update(); - - if(updateWindows) - { - let windowsEnum = Services.wm.getEnumerator("navigator:browser"); - while(windowsEnum.hasMoreElements()) - { - this.updateWindow(windowsEnum.getNext(), pro); - } - } - - if(pro.alsoUpdate) - { - pro.alsoUpdate.forEach(function (alsoPref) - { - this.updatePref(alsoPref); - }, this); - } - }, - - // Updtate a browser window - updateWindow: function(win, pro) - { - if(!(win instanceof CI.nsIDOMWindow) - || !(win.document.documentElement.getAttribute("windowtype") == "navigator:browser")) - { - return; - } - - if(pro) - { - this.handlePro(win, pro); - } - else - { - for(let pref in this.pref_registry) - { - this.handlePro(win, this.pref_registry[pref]); - } - } - }, - - handlePro: function(win, pro) - { - if(pro.updateWindow) - { - pro.updateWindow(win); - } - - if(pro.updateDynamicStyle) - { - let styleSheets = win.document.styleSheets; - for(let i = 0; i < styleSheets.length; i++) - { - let styleSheet = styleSheets[i]; - if(styleSheet.href == "chrome://browser/skin/statusbar/dynamic.css") - { - pro.updateDynamicStyle(styleSheet); - break; - } - } - } - }, - - setBoolElementAttribute: function(elem, attr, val) - { - if(val) - { - elem.setAttribute(attr, "true"); - } - else - { - elem.removeAttribute(attr); - } - }, - - setStringElementAttribute: function(elem, attr, val) - { - if(val) - { - elem.setAttribute(attr, val); - } - else - { - elem.removeAttribute(attr); - } - }, - - resetPrefs: function() - { - let childPrefs = this.prefs.getChildList(""); - childPrefs.forEach(function(pref) - { - if(this.prefs.prefHasUserValue(pref)) - { - this.prefs.clearUserPref(pref); - } - }, this); - } + classID: Components.ID("{33d0433d-07be-4dc4-87fd-954057310efd}"), + QueryInterface: XPCOMUtils.generateQI([ + CI.nsISupportsWeakReference, + CI.nsIObserver, + CI.nsIStatus4Evar + ]), + + prefs: null, + + addonbarBorderStyle: false, + addonbarCloseButton: false, + addonbarWindowGripper: true, + + advancedStatusDetectFullScreen: true, + advancedStatusDetectVideo: true, + + downloadButtonAction: 1, + downloadButtonActionCommand: "", + downloadColorActive: null, + downloadColorPaused: null, + downloadForce: false, + downloadLabel: 0, + downloadLabelForce: true, + downloadNotifyAnimate: true, + downloadNotifyTimeout: 60000, + downloadProgress: 1, + downloadTooltip: 1, + + firstRun: true, + + progressToolbarCSS: null, + progressToolbarForce: false, + progressToolbarStyle: false, + + status: 1, + statusDefault: true, + statusNetwork: true, + statusTimeout: 10000, + statusLinkOver: 1, + statusLinkOverDelayShow: 70, + statusLinkOverDelayHide: 150, + + statusToolbarMaxLength: 0, + + statusToolbarInvertMirror: false, + statusToolbarMouseMirror: true, + + pref_registry: + { + "addonbar.borderStyle": + { + update: function() + { + this.addonbarBorderStyle = this.prefs.getBoolPref("addonbar.borderStyle"); + }, + updateWindow: function(win) + { + let browser_bottom_box = win.caligon.status4evar.getters.browserBottomBox; + if(browser_bottom_box) + { + this.setBoolElementAttribute(browser_bottom_box, "s4eboarder", this.addonbarBorderStyle); + } + } + }, + + "addonbar.closeButton": + { + update: function() + { + this.addonbarCloseButton = this.prefs.getBoolPref("addonbar.closeButton"); + }, + updateWindow: function(win) + { + let addonbar_close_button = win.caligon.status4evar.getters.addonbarCloseButton; + if(addonbar_close_button) + { + addonbar_close_button.hidden = !this.addonbarCloseButton; + } + } + }, + + "addonbar.windowGripper": + { + update: function() + { + this.addonbarWindowGripper = this.prefs.getBoolPref("addonbar.windowGripper"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.toolbars.updateWindowGripper(true); + } + }, + + "advanced.status.detectFullScreen": + { + update: function() + { + this.advancedStatusDetectFullScreen = this.prefs.getBoolPref("advanced.status.detectFullScreen"); + } + }, + + "advanced.status.detectVideo": + { + update: function() + { + this.advancedStatusDetectVideo = this.prefs.getBoolPref("advanced.status.detectVideo"); + } + }, + + "download.button.action": + { + update: function() + { + this.downloadButtonAction = this.prefs.getIntPref("download.button.action"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.downloadStatus.updateBinding(); + } + }, + + "download.button.action.command": + { + update: function() + { + this.downloadButtonActionCommand = this.prefs.getCharPref("download.button.action.command"); + } + }, + + "download.color.active": + { + update: function() + { + this.downloadColorActive = this.prefs.getCharPref("download.color.active"); + }, + updateDynamicStyle: function(sheet) + { + sheet.cssRules[2].style.backgroundColor = this.downloadColorActive; + } + }, + + "download.color.paused": + { + update: function() + { + this.downloadColorPaused = this.prefs.getCharPref("download.color.paused"); + }, + updateDynamicStyle: function(sheet) + { + sheet.cssRules[3].style.backgroundColor = this.downloadColorPaused; + } + }, + + "download.force": + { + update: function() + { + this.downloadForce = this.prefs.getBoolPref("download.force"); + }, + updateWindow: function(win) + { + let download_button = win.caligon.status4evar.getters.downloadButton; + if(download_button) + { + this.setBoolElementAttribute(download_button, "forcevisible", this.downloadForce); + } + + let download_notify_anchor = win.caligon.status4evar.getters.downloadNotifyAnchor; + this.setBoolElementAttribute(download_notify_anchor, "forcevisible", this.downloadForce); + } + }, + + "download.label": + { + update: function() + { + this.downloadLabel = this.prefs.getIntPref("download.label"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.downloadStatus.updateButton(); + } + }, + + "download.label.force": + { + update: function() + { + this.downloadLabelForce = this.prefs.getBoolPref("download.label.force"); + }, + updateWindow: function(win) + { + let download_button = win.caligon.status4evar.getters.downloadButton; + if(download_button) + { + this.setBoolElementAttribute(download_button, "forcelabel", this.downloadLabelForce); + } + } + }, + + "download.notify.animate": + { + update: function() + { + this.downloadNotifyAnimate = this.prefs.getBoolPref("download.notify.animate"); + } + }, + + "download.notify.timeout": + { + update: function() + { + this.downloadNotifyTimeout = (this.prefs.getIntPref("download.notify.timeout") * 1000); + } + }, + + "download.progress": + { + update: function() + { + this.downloadProgress = this.prefs.getIntPref("download.progress"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.downloadStatus.updateButton(); + } + }, + + "download.tooltip": + { + update: function() + { + this.downloadTooltip = this.prefs.getIntPref("download.tooltip"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.downloadStatus.updateButton(); + } + }, + + "progress.toolbar.css": + { + update: function() + { + this.progressToolbarCSS = this.prefs.getCharPref("progress.toolbar.css"); + }, + updateDynamicStyle: function(sheet) + { + sheet.cssRules[1].style.background = this.progressToolbarCSS; + } + }, + + "progress.toolbar.force": + { + update: function() + { + this.progressToolbarForce = this.prefs.getBoolPref("progress.toolbar.force"); + }, + updateWindow: function(win) + { + let toolbar_progress = win.caligon.status4evar.getters.toolbarProgress; + if(toolbar_progress) + { + this.setBoolElementAttribute(toolbar_progress, "forcevisible", this.progressToolbarForce); + } + } + }, + + "progress.toolbar.style": + { + update: function() + { + this.progressToolbarStyle = this.prefs.getBoolPref("progress.toolbar.style"); + }, + updateWindow: function(win) + { + let toolbar_progress = win.caligon.status4evar.getters.toolbarProgress; + if(toolbar_progress) + { + this.setBoolElementAttribute(toolbar_progress, "s4estyle", this.progressToolbarStyle); + } + } + }, + + "status": + { + update: function() + { + this.status = this.prefs.getIntPref("status"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.statusService.clearStatusField(); + win.caligon.status4evar.statusService.updateStatusField(true); + } + }, + + "status.default": + { + update: function() + { + this.statusDefault = this.prefs.getBoolPref("status.default"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.statusService.buildTextOrder(); + win.caligon.status4evar.statusService.updateStatusField(true); + } + }, + + "status.linkOver": + { + update: function() + { + this.statusLinkOver = this.prefs.getIntPref("status.linkOver"); + } + }, + + "status.linkOver.delay.show": + { + update: function() + { + this.statusLinkOverDelayShow = this.prefs.getIntPref("status.linkOver.delay.show"); + } + }, + + "status.linkOver.delay.hide": + { + update: function() + { + this.statusLinkOverDelayHide = this.prefs.getIntPref("status.linkOver.delay.hide"); + } + }, + + "status.network": + { + update: function() + { + this.statusNetwork = this.prefs.getBoolPref("status.network"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.statusService.buildTextOrder(); + } + }, + + "status.network.xhr": + { + update: function() + { + this.statusNetworkXHR = this.prefs.getBoolPref("status.network.xhr"); + }, + updateWindow: function(win) + { + win.caligon.status4evar.statusService.buildTextOrder(); + } + }, + + "status.timeout": + { + update: function() + { + this.statusTimeout = (this.prefs.getIntPref("status.timeout") * 1000); + }, + updateWindow: function(win) + { + win.caligon.status4evar.statusService.updateStatusField(true); + } + }, + + "status.toolbar.maxLength": + { + update: function() + { + this.statusToolbarMaxLength = this.prefs.getIntPref("status.toolbar.maxLength"); + }, + updateWindow: function(win) + { + let status_widget = win.caligon.status4evar.getters.statusWidget; + if(status_widget) + { + status_widget.maxWidth = (this.statusToolbarMaxLength || ""); + } + } + }, + + "status.popup.invertMirror": + { + update: function() + { + this.statusToolbarInvertMirror = this.prefs.getBoolPref("status.popup.invertMirror"); + }, + updateWindow: function(win) + { + let statusOverlay = win.caligon.status4evar.getters.statusOverlay; + if(statusOverlay) + { + statusOverlay.invertMirror = this.statusToolbarInvertMirror; + } + } + }, + + "status.popup.mouseMirror": + { + update: function() + { + this.statusToolbarMouseMirror = this.prefs.getBoolPref("status.popup.mouseMirror"); + }, + updateWindow: function(win) + { + let statusOverlay = win.caligon.status4evar.getters.statusOverlay; + if(statusOverlay) + { + statusOverlay.mouseMirror = this.statusToolbarMouseMirror; + } + } + } + + }, + + // nsIObserver + observe: function(subject, topic, data) + { + try + { + switch(topic) + { + case "profile-after-change": + this.startup(); + break; + case "quit-application": + this.shutdown(); + break; + case "nsPref:changed": + this.updatePref(data, true); + break; + } + } + catch(e) + { + CU.reportError(e); + } + }, + + startup: function() + { + this.prefs = Services.prefs.getBranch("status4evar.").QueryInterface(CI.nsIPrefBranch2); + + this.firstRun = this.prefs.getBoolPref("firstRun"); + if(this.firstRun) + { + this.prefs.setBoolPref("firstRun", false); + } + + this.migrate(); + + for(let pref in this.pref_registry) + { + let pro = this.pref_registry[pref]; + + pro.update = pro.update.bind(this); + if(pro.updateWindow) + { + pro.updateWindow = pro.updateWindow.bind(this); + } + if(pro.updateDynamicStyle) + { + pro.updateDynamicStyle = pro.updateDynamicStyle.bind(this); + } + + this.prefs.addObserver(pref, this, true); + + this.updatePref(pref, false); + } + + Services.obs.addObserver(this, "quit-application", true); + }, + + shutdown: function() + { + Services.obs.removeObserver(this, "quit-application"); + + for(let pref in this.pref_registry) + { + this.prefs.removeObserver(pref, this); + } + + this.prefs = null; + }, + + migrate: function() + { + if(!this.firstRun) + { + let migration = 0; + try + { + migration = this.prefs.getIntPref("migration"); + } + catch(e) {} + + switch(migration) + { + case 5: + this.migrateBoolPref("status.detectFullScreen", "advanced.status.detectFullScreen"); + case 6: + let oldDownloadAction = this.prefs.getIntPref("download.button.action"); + let newDownloadAction = 1; + switch(oldDownloadAction) + { + case 2: + newDownloadAction = 1; + break; + case 3: + newDownloadAction = 2; + break; + case 4: + newDownloadAction = 1; + break; + } + this.prefs.setIntPref("download.button.action", newDownloadAction); + case 7: + let progressLocation = this.prefs.getIntPref("status"); + if (progressLocation == 2) + this.prefs.setIntPref("status", 1); + let linkOverLocation = this.prefs.getIntPref("status.linkOver"); + if (linkOverLocation == 2) + this.prefs.setIntPref("status.linkOver", 1); + break; + case CURRENT_MIGRATION: + break; + } + } + + this.prefs.setIntPref("migration", CURRENT_MIGRATION); + }, + + migrateBoolPref: function(oldPref, newPref) + { + if(this.prefs.prefHasUserValue(oldPref)) + { + this.prefs.setBoolPref(newPref, this.prefs.getBoolPref(oldPref)); + this.prefs.clearUserPref(oldPref); + } + }, + + migrateIntPref: function(oldPref, newPref) + { + if(this.prefs.prefHasUserValue(oldPref)) + { + this.prefs.setIntPref(newPref, this.prefs.getIntPref(oldPref)); + this.prefs.clearUserPref(oldPref); + } + }, + + migrateCharPref: function(oldPref, newPref) + { + if(this.prefs.prefHasUserValue(oldPref)) + { + this.prefs.setCharPref(newPref, this.prefs.getCharPref(oldPref)); + this.prefs.clearUserPref(oldPref); + } + }, + + updatePref: function(pref, updateWindows) + { + if(!(pref in this.pref_registry)) + { + return; + } + let pro = this.pref_registry[pref]; + + pro.update(); + + if(updateWindows) + { + let windowsEnum = Services.wm.getEnumerator("navigator:browser"); + while(windowsEnum.hasMoreElements()) + { + this.updateWindow(windowsEnum.getNext(), pro); + } + } + + if(pro.alsoUpdate) + { + pro.alsoUpdate.forEach(function (alsoPref) + { + this.updatePref(alsoPref); + }, this); + } + }, + + // Updtate a browser window + updateWindow: function(win, pro) + { + if(!(win instanceof CI.nsIDOMWindow) + || !(win.document.documentElement.getAttribute("windowtype") == "navigator:browser")) + { + return; + } + + if(pro) + { + this.handlePro(win, pro); + } + else + { + for(let pref in this.pref_registry) + { + this.handlePro(win, this.pref_registry[pref]); + } + } + }, + + handlePro: function(win, pro) + { + if(pro.updateWindow) + { + pro.updateWindow(win); + } + + if(pro.updateDynamicStyle) + { + let styleSheets = win.document.styleSheets; + for(let i = 0; i < styleSheets.length; i++) + { + let styleSheet = styleSheets[i]; + if(styleSheet.href == "chrome://browser/skin/statusbar/dynamic.css") + { + pro.updateDynamicStyle(styleSheet); + break; + } + } + } + }, + + setBoolElementAttribute: function(elem, attr, val) + { + if(val) + { + elem.setAttribute(attr, "true"); + } + else + { + elem.removeAttribute(attr); + } + }, + + setStringElementAttribute: function(elem, attr, val) + { + if(val) + { + elem.setAttribute(attr, val); + } + else + { + elem.removeAttribute(attr); + } + }, + + resetPrefs: function() + { + let childPrefs = this.prefs.getChildList(""); + childPrefs.forEach(function(pref) + { + if(this.prefs.prefHasUserValue(pref)) + { + this.prefs.clearUserPref(pref); + } + }, this); + } }; const NSGetFactory = XPCOMUtils.generateNSGetFactory([Status_4_Evar]); diff --git a/application/palemoon/installer/windows/nsis/shared.nsh b/application/palemoon/installer/windows/nsis/shared.nsh index 29136f47a..294e3e6fc 100644 --- a/application/palemoon/installer/windows/nsis/shared.nsh +++ b/application/palemoon/installer/windows/nsis/shared.nsh @@ -390,7 +390,7 @@ !macroend !define SetHandlers "!insertmacro SetHandlers" -; Adds the HKLM\Software\Clients\StartMenuInternet\FIREFOX.EXE registry +; Adds the HKLM\Software\Clients\StartMenuInternet\PALEMOON.EXE registry ; entries (does not use SHCTX). ; ; The values for StartMenuInternet are only valid under HKLM and there can only @@ -770,11 +770,11 @@ !macro RemoveDeprecatedKeys StrCpy $0 "SOFTWARE\Classes" ; Remove support for launching gopher urls from the shell during install or - ; update if the DefaultIcon is from firefox.exe. + ; update if the DefaultIcon is from palemoon.exe. ${RegCleanAppHandler} "gopher" ; Remove support for launching chrome urls from the shell during install or - ; update if the DefaultIcon is from firefox.exe (Bug 301073). + ; update if the DefaultIcon is from palemoon.exe (Bug 301073). ${RegCleanAppHandler} "chrome" ; Remove protocol handler registry keys added by the MS shim diff --git a/application/palemoon/modules/AutoCompletePopup.jsm b/application/palemoon/modules/AutoCompletePopup.jsm new file mode 100644 index 000000000..c3698f905 --- /dev/null +++ b/application/palemoon/modules/AutoCompletePopup.jsm @@ -0,0 +1,293 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +this.EXPORTED_SYMBOLS = [ "AutoCompletePopup" ]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +// nsITreeView implementation that feeds the autocomplete popup +// with the search data. +var AutoCompleteTreeView = { + // nsISupports + QueryInterface: XPCOMUtils.generateQI([Ci.nsITreeView, + Ci.nsIAutoCompleteController]), + + // Private variables + treeBox: null, + results: [], + + // nsITreeView + selection: null, + + get rowCount() { return this.results.length; }, + setTree: function(treeBox) { this.treeBox = treeBox; }, + getCellText: function(idx, column) { return this.results[idx].value }, + isContainer: function(idx) { return false; }, + getCellValue: function(idx, column) { return false }, + isContainerOpen: function(idx) { return false; }, + isContainerEmpty: function(idx) { return false; }, + isSeparator: function(idx) { return false; }, + isSorted: function() { return false; }, + isEditable: function(idx, column) { return false; }, + canDrop: function(idx, orientation, dt) { return false; }, + getLevel: function(idx) { return 0; }, + getParentIndex: function(idx) { return -1; }, + hasNextSibling: function(idx, after) { return idx < this.results.length - 1 }, + toggleOpenState: function(idx) { }, + getCellProperties: function(idx, column) { return this.results[idx].style || ""; }, + getRowProperties: function(idx) { return ""; }, + getImageSrc: function(idx, column) { return null; }, + getProgressMode : function(idx, column) { }, + cycleHeader: function(column) { }, + cycleCell: function(idx, column) { }, + selectionChanged: function() { }, + performAction: function(action) { }, + performActionOnCell: function(action, index, column) { }, + getColumnProperties: function(column) { return ""; }, + + // nsIAutoCompleteController + get matchCount() { + return this.rowCount; + }, + + handleEnter: function(aIsPopupSelection) { + AutoCompletePopup.handleEnter(aIsPopupSelection); + }, + + stopSearch: function() {}, + + // Internal JS-only API + clearResults: function() { + this.results = []; + }, + + setResults: function(results) { + this.results = results; + }, +}; + +this.AutoCompletePopup = { + MESSAGES: [ + "FormAutoComplete:SelectBy", + "FormAutoComplete:GetSelectedIndex", + "FormAutoComplete:SetSelectedIndex", + "FormAutoComplete:MaybeOpenPopup", + "FormAutoComplete:ClosePopup", + "FormAutoComplete:Disconnect", + "FormAutoComplete:RemoveEntry", + "FormAutoComplete:Invalidate", + ], + + init: function() { + for (let msg of this.MESSAGES) { + Services.mm.addMessageListener(msg, this); + } + }, + + uninit: function() { + for (let msg of this.MESSAGES) { + Services.mm.removeMessageListener(msg, this); + } + }, + + handleEvent: function(evt) { + switch (evt.type) { + case "popupshowing": { + this.sendMessageToBrowser("FormAutoComplete:PopupOpened"); + break; + } + + case "popuphidden": { + this.sendMessageToBrowser("FormAutoComplete:PopupClosed"); + this.openedPopup = null; + this.weakBrowser = null; + evt.target.removeEventListener("popuphidden", this); + evt.target.removeEventListener("popupshowing", this); + break; + } + } + }, + + // Along with being called internally by the receiveMessage handler, + // this function is also called directly by the login manager, which + // uses a single message to fill in the autocomplete results. See + // "RemoteLogins:autoCompleteLogins". + showPopupWithResults: function({ browser, rect, dir, results }) { + if (!results.length || this.openedPopup) { + // We shouldn't ever be showing an empty popup, and if we + // already have a popup open, the old one needs to close before + // we consider opening a new one. + return; + } + + let window = browser.ownerDocument.defaultView; + let tabbrowser = window.gBrowser; + if (Services.focus.activeWindow != window || + tabbrowser.selectedBrowser != browser) { + // We were sent a message from a window or tab that went into the + // background, so we'll ignore it for now. + return; + } + + this.weakBrowser = Cu.getWeakReference(browser); + this.openedPopup = browser.autoCompletePopup; + this.openedPopup.hidden = false; + // don't allow the popup to become overly narrow + this.openedPopup.setAttribute("width", Math.max(100, rect.width)); + this.openedPopup.style.direction = dir; + + AutoCompleteTreeView.setResults(results); + this.openedPopup.view = AutoCompleteTreeView; + this.openedPopup.selectedIndex = -1; + this.openedPopup.invalidate(); + + if (results.length) { + // Reset fields that were set from the last time the search popup was open + this.openedPopup.mInput = null; + this.openedPopup.showCommentColumn = false; + this.openedPopup.showImageColumn = false; + this.openedPopup.addEventListener("popuphidden", this); + this.openedPopup.addEventListener("popupshowing", this); + this.openedPopup.openPopupAtScreenRect("after_start", rect.left, rect.top, + rect.width, rect.height, false, + false); + } else { + this.closePopup(); + } + }, + + invalidate(results) { + if (!this.openedPopup) { + return; + } + + if (!results.length) { + this.closePopup(); + } else { + AutoCompleteTreeView.setResults(results); + // We need to re-set the view in order for the + // tree to know the view has changed. + this.openedPopup.view = AutoCompleteTreeView; + this.openedPopup.invalidate(); + } + }, + + closePopup() { + if (this.openedPopup) { + // Note that hidePopup() closes the popup immediately, + // so popuphiding or popuphidden events will be fired + // and handled during this call. + this.openedPopup.hidePopup(); + } + AutoCompleteTreeView.clearResults(); + }, + + removeLogin(login) { + Services.logins.removeLogin(login); + }, + + receiveMessage: function(message) { + if (!message.target.autoCompletePopup) { + // Returning false to pacify ESLint, but this return value is + // ignored by the messaging infrastructure. + return false; + } + + switch (message.name) { + case "FormAutoComplete:SelectBy": { + this.openedPopup.selectBy(message.data.reverse, message.data.page); + break; + } + + case "FormAutoComplete:GetSelectedIndex": { + if (this.openedPopup) { + return this.openedPopup.selectedIndex; + } + // If the popup was closed, then the selection + // has not changed. + return -1; + } + + case "FormAutoComplete:SetSelectedIndex": { + let { index } = message.data; + if (this.openedPopup) { + this.openedPopup.selectedIndex = index; + } + break; + } + + case "FormAutoComplete:MaybeOpenPopup": { + let { results, rect, dir } = message.data; + this.showPopupWithResults({ browser: message.target, rect, dir, + results }); + break; + } + + case "FormAutoComplete:Invalidate": { + let { results } = message.data; + this.invalidate(results); + break; + } + + case "FormAutoComplete:ClosePopup": { + this.closePopup(); + break; + } + + case "FormAutoComplete:Disconnect": { + // The controller stopped controlling the current input, so clear + // any cached data. This is necessary cause otherwise we'd clear data + // only when starting a new search, but the next input could not support + // autocomplete and it would end up inheriting the existing data. + AutoCompleteTreeView.clearResults(); + break; + } + } + // Returning false to pacify ESLint, but this return value is + // ignored by the messaging infrastructure. + return false; + }, + + /** + * Despite its name, this handleEnter is only called when the user clicks on + * one of the items in the popup since the popup is rendered in the parent process. + * The real controller's handleEnter is called directly in the content process + * for other methods of completing a selection (e.g. using the tab or enter + * keys) since the field with focus is in that process. + */ + handleEnter(aIsPopupSelection) { + if (this.openedPopup) { + this.sendMessageToBrowser("FormAutoComplete:HandleEnter", { + selectedIndex: this.openedPopup.selectedIndex, + isPopupSelection: aIsPopupSelection, + }); + } + }, + + /** + * If a browser exists that AutoCompletePopup knows about, + * sends it a message. Otherwise, this is a no-op. + * + * @param {string} msgName + * The name of the message to send. + * @param {object} data + * The optional data to send with the message. + */ + sendMessageToBrowser(msgName, data) { + let browser = this.weakBrowser ? this.weakBrowser.get() + : null; + if (browser) { + browser.messageManager.sendAsyncMessage(msgName, data); + } + }, + + stopSearch: function() {} +} diff --git a/application/palemoon/modules/PopupNotifications.jsm b/application/palemoon/modules/PopupNotifications.jsm index d2faf52c3..15c8915ed 100644 --- a/application/palemoon/modules/PopupNotifications.jsm +++ b/application/palemoon/modules/PopupNotifications.jsm @@ -4,9 +4,9 @@ this.EXPORTED_SYMBOLS = ["PopupNotifications"]; -var Cc = Components.classes, Ci = Components.interfaces; +var Cc = Components.classes, Ci = Components.interfaces, Cu = Components.utils; -Components.utils.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); const NOTIFICATION_EVENT_DISMISSED = "dismissed"; const NOTIFICATION_EVENT_REMOVED = "removed"; @@ -33,6 +33,18 @@ function getAnchorFromBrowser(aBrowser) { return null; } +function getNotificationFromElement(aElement) { + // Need to find the associated notification object, which is a bit tricky + // since it isn't associated with the element directly - this is kind of + // gross and very dependent on the structure of the popupnotification + // binding's content. + let notificationEl; + let parent = aElement; + while (parent && (parent = aElement.ownerDocument.getBindingParent(parent))) + notificationEl = parent; + return notificationEl; +} + /** * Notification object describes a single popup notification. * @@ -194,7 +206,8 @@ PopupNotifications.prototype = { * - label (string): the button's label. * - accessKey (string): the button's accessKey. * - callback (function): a callback to be invoked when the button is - * pressed. + * pressed, is passed an object that contains the following fields: + * - checkboxChecked: (boolean) If the optional checkbox is checked. * If null, the notification will not have a button, and * secondaryActions will be ignored. * @param secondaryActions @@ -234,6 +247,26 @@ PopupNotifications.prototype = { * removed when they would have otherwise been dismissed * (i.e. any time the popup is closed due to user * interaction). + * checkbox: An object that allows you to add a checkbox and + * control its behavior with these fields: + * label: + * (required) Label to be shown next to the checkbox. + * checked: + * (optional) Whether the checkbox should be checked + * by default. Defaults to false. + * checkedState: + * (optional) An object that allows you to customize + * the notification state when the checkbox is checked. + * disableMainAction: + * (optional) Whether the mainAction is disabled. + * Defaults to false. + * warningLabel: + * (optional) A (warning) text that is shown below the + * checkbox. Pass null to hide. + * uncheckedState: + * (optional) An object that allows you to customize + * the notification state when the checkbox is not checked. + * Has the same attributes as checkedState. * popupIconURL: * A string. URL of the image to be displayed in the popup. * Normally specified in CSS using list-style-image and the @@ -552,6 +585,25 @@ PopupNotifications.prototype = { } } + let checkbox = n.options.checkbox; + if (checkbox && checkbox.label) { + let checked = n._checkboxChecked != null ? n._checkboxChecked : !!checkbox.checked; + + popupnotification.setAttribute("checkboxhidden", "false"); + popupnotification.setAttribute("checkboxchecked", checked); + popupnotification.setAttribute("checkboxlabel", checkbox.label); + + popupnotification.setAttribute("checkboxcommand", "PopupNotifications._onCheckboxCommand(event);"); + + if (checked) { + this._setNotificationUIState(popupnotification, checkbox.checkedState); + } else { + this._setNotificationUIState(popupnotification, checkbox.uncheckedState); + } + } else { + popupnotification.setAttribute("checkboxhidden", "true"); + } + this.panel.appendChild(popupnotification); // The popupnotification may be hidden if we got it from the chrome @@ -560,6 +612,32 @@ PopupNotifications.prototype = { }, this); }, + _setNotificationUIState(notification, state={}) { + notification.setAttribute("mainactiondisabled", state.disableMainAction || "false"); + + if (state.warningLabel) { + notification.setAttribute("warninglabel", state.warningLabel); + notification.setAttribute("warninghidden", "false"); + } else { + notification.setAttribute("warninghidden", "true"); + } + }, + + _onCheckboxCommand(event) { + let notificationEl = getNotificationFromElement(event.originalTarget); + let checked = notificationEl.checkbox.checked; + let notification = notificationEl.notification; + + // Save checkbox state to be able to persist it when re-opening the doorhanger. + notification._checkboxChecked = checked; + + if (checked) { + this._setNotificationUIState(notificationEl, notification.options.checkbox.checkedState); + } else { + this._setNotificationUIState(notificationEl, notification.options.checkbox.uncheckedState); + } + }, + _showPanel: function PopupNotifications_showPanel(notificationsToShow, anchorElement) { this.panel.hidden = false; @@ -752,8 +830,12 @@ PopupNotifications.prototype = { }, _fireCallback: function PopupNotifications_fireCallback(n, event) { - if (n.options.eventCallback) - n.options.eventCallback.call(n, event); + try { + if (n.options.eventCallback) + n.options.eventCallback.call(n, event); + } catch (error) { + Cu.reportError(error); + } }, _onPopupHidden: function PopupNotifications_onPopupHidden(event) { @@ -789,15 +871,7 @@ PopupNotifications.prototype = { }, _onButtonCommand: function PopupNotifications_onButtonCommand(event) { - // Need to find the associated notification object, which is a bit tricky - // since it isn't associated with the button directly - this is kind of - // gross and very dependent on the structure of the popupnotification - // binding's content. - let target = event.originalTarget; - let notificationEl; - let parent = target; - while (parent && (parent = target.ownerDocument.getBindingParent(parent))) - notificationEl = parent; + let notificationEl = getNotificationFromElement(event.originalTarget); if (!notificationEl) throw "PopupNotifications_onButtonCommand: couldn't find notification element"; @@ -819,7 +893,14 @@ PopupNotifications.prototype = { timeSinceShown + "ms"); return; } - notification.mainAction.callback.call(); + + try { + notification.mainAction.callback.call(undefined, { + checkboxChecked: notificationEl.checkbox.checked + }); + } catch (error) { + Cu.reportError(error); + } this._remove(notification); this._update(); @@ -830,8 +911,16 @@ PopupNotifications.prototype = { if (!target.action || !target.notification) throw "menucommand target has no associated action/notification"; + let notificationEl = target.parentElement; event.stopPropagation(); - target.action.callback.call(); + + try { + target.action.callback.call(undefined, { + checkboxChecked: notificationEl.checkbox.checked + }); + } catch (error) { + Cu.reportError(error); + } this._remove(target.notification); this._update(); diff --git a/application/palemoon/modules/moz.build b/application/palemoon/modules/moz.build index f7717ef89..67fd22338 100644 --- a/application/palemoon/modules/moz.build +++ b/application/palemoon/modules/moz.build @@ -9,6 +9,7 @@ EXTRA_JS_MODULES += [ 'promise.js' ] EXTRA_JS_MODULES += [ + 'AutoCompletePopup.jsm', 'BrowserNewTabPreloader.jsm', 'CharsetMenu.jsm', 'FormSubmitObserver.jsm', diff --git a/application/palemoon/themes/linux/autocomplete.css b/application/palemoon/themes/linux/autocomplete.css new file mode 100644 index 000000000..ab926851d --- /dev/null +++ b/application/palemoon/themes/linux/autocomplete.css @@ -0,0 +1,210 @@ +/* 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/. */ + +/* ===== autocomplete.css ================================================= + == Styles used by the autocomplete widget. + ======================================================================= */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +/* ::::: autocomplete ::::: */ + +/* .padded is used by autocomplete widgets that don't have an icon. Gross. -dwh */ +textbox:not(.padded) { + cursor: default; + padding: 0; +} + +textbox[enablehistory="true"] { + -moz-appearance: none; + border: 0; + background-color: transparent; +} + +textbox[nomatch="true"][highlightnonmatches="true"] { + color: red; +} + +.private-autocomplete-textbox-container { + -moz-box-align: center; +} + +textbox[enablehistory="true"] > .autocomplete-textbox-container { + -moz-appearance: menulist-textfield; +} + +textbox:not(.padded) .textbox-input-box { + margin: 0 3px; +} + +.textbox-input-box { + -moz-box-align: center; +} + +/* ::::: autocomplete popups ::::: */ + +panel[type="private-autocomplete"], +panel[type="private-autocomplete-richlistbox"], +.private-autocomplete-history-popup { + border-width: 1px; + -moz-border-top-colors: ThreeDDarkShadow; + -moz-border-right-colors: ThreeDDarkShadow; + -moz-border-bottom-colors: ThreeDDarkShadow; + -moz-border-left-colors: ThreeDDarkShadow; + padding: 0; + background-color: -moz-Field; +} + +.private-autocomplete-history-popup { + max-height: 180px; +} + +/* ::::: tree ::::: */ + +.private-autocomplete-tree { + -moz-appearance: none !important; + border: none !important; + background-color: transparent !important; + color: MenuText; +} + +.private-autocomplete-treecol { + -moz-appearance: none !important; + margin: 0 !important; + border: none !important; + padding: 0 !important; +} + +/* GTK calculates space for a sort arrow */ +.private-autocomplete-treecol > .treecol-sortdirection { + -moz-appearance: none !important; +} + +.private-autocomplete-treebody::-moz-tree-cell-text { + -moz-padding-start: 8px; +} + +treechildren.private-autocomplete-treebody::-moz-tree-row(selected) { + background-color: Highlight; +} + +treechildren.private-autocomplete-treebody::-moz-tree-cell-text(selected) { + color: HighlightText !important; +} + +.private-autocomplete-treebody::-moz-tree-image(treecolAutoCompleteValue) { + max-width: 16px; + height: 16px; +} + +/* ::::: richlistbox autocomplete ::::: */ + +.private-autocomplete-richlistbox { + -moz-appearance: none; + margin: 1px; + background-color: transparent; +} + +.private-autocomplete-richlistitem[selected="true"] { + background-color: Highlight; + color: HighlightText; +} + +.private-autocomplete-richlistitem { + padding: 6px 2px; + color: MenuText; +} + +.ac-url-box { + /* When setting a vertical margin here, half of that needs to be added + .ac-title-box's translateY for when .ac-url-box is hidden (see below). */ + margin-top: 1px; +} + +.private-autocomplete-richlistitem[actiontype="keyword"] .ac-url-box, +.private-autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box, +.private-autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box, +.private-autocomplete-richlistitem[type~="autofill"] .ac-url-box { + visibility: hidden; +} + +.private-autocomplete-richlistitem[actiontype="keyword"] .ac-title-box, +.private-autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box, +.private-autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box, +.private-autocomplete-richlistitem[type~="autofill"] .ac-title-box { + /* Center the title by moving it down by half of .ac-url-box's height, + including vertical margins (if any). */ + transform: translateY(.5em); +} + +.ac-site-icon { + width: 16px; + height: 16px; + margin-bottom: -2px; + -moz-margin-start: 3px; + -moz-margin-end: 6px; +} + +.ac-type-icon { + width: 16px; + height: 16px; + -moz-margin-start: 6px; + -moz-margin-end: 4px; +} + +.ac-extra > .ac-result-type-tag { + margin: 0 4px; +} + +.ac-extra > .ac-comment { + padding-right: 4px; +} + +.ac-ellipsis-after { + margin: 0 !important; + padding: 0; + min-width: 1em; +} + +.ac-normal-text { + margin: 0 !important; + padding: 0; +} + +.ac-normal-text > html|span { + margin: 0 !important; + padding: 0; +} + +html|span.ac-emphasize-text { + box-shadow: inset 0 0 1px 1px rgba(0,0,0,0.1); + background-color: rgba(0,0,0,0.05); + border-radius: 2px; + text-shadow: 0 0 currentColor; /*faux bold effect*/ +} + +.ac-url-text > html|span.ac-emphasize-text, +.ac-action-text > html|span.ac-emphasize-text { + box-shadow: none; +} + +.ac-normal-text[selected="true"] > html|span.ac-emphasize-text { + box-shadow: inset 0 0 1px 1px rgba(255,255,255,0.3); + background-color: rgba(255,255,255,0.2); +} + +.ac-title, .ac-url { + overflow: hidden; +} + +/* ::::: textboxes inside toolbarpaletteitems ::::: */ + +toolbarpaletteitem > toolbaritem > textbox > hbox > hbox > html|*.textbox-input { + visibility: hidden; +} + +toolbarpaletteitem > toolbaritem > * > textbox > hbox > hbox > html|*.textbox-input { + visibility: hidden; +} diff --git a/application/palemoon/themes/linux/browser.css b/application/palemoon/themes/linux/browser.css index 334062613..4f4964db8 100644 --- a/application/palemoon/themes/linux/browser.css +++ b/application/palemoon/themes/linux/browser.css @@ -2096,12 +2096,12 @@ toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon { } %endif -.toolbarbutton-badge-container { +.toolbarbutton-badge-stack { margin: 5px 3px; position: relative; } -toolbar[iconsize="small"] .toolbarbutton-badge-container { +toolbar[iconsize="small"] .toolbarbutton-badge-stack { margin: 0; } diff --git a/application/palemoon/themes/linux/jar.mn b/application/palemoon/themes/linux/jar.mn index f1339b803..7e67d0129 100644 --- a/application/palemoon/themes/linux/jar.mn +++ b/application/palemoon/themes/linux/jar.mn @@ -16,6 +16,7 @@ browser.jar: #ifdef MOZ_SERVICES_SYNC skin/classic/browser/aboutSyncTabs.css #endif +* skin/classic/browser/autocomplete.css skin/classic/browser/actionicon-tab.png * skin/classic/browser/browser.css skin/classic/browser/click-to-play-warning-stripes.png diff --git a/application/palemoon/themes/osx/autocomplete.css b/application/palemoon/themes/osx/autocomplete.css new file mode 100644 index 000000000..a50dbd823 --- /dev/null +++ b/application/palemoon/themes/osx/autocomplete.css @@ -0,0 +1,198 @@ +/* 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"); + +/* .padded is used by autocomplete widgets that don't have an icon. Gross. -dwh */ +textbox:not(.padded) { + cursor: default; + padding: 0; +} + +textbox[nomatch="true"][highlightnonmatches="true"] { + color: red; +} + +textbox:not(.padded) .textbox-input-box { + margin: 0 3px; +} + +.textbox-input-box { + -moz-box-align: center; +} + +/* ::::: history button ::::: */ + +.private-autocomplete-history-dropmarker { + -moz-appearance: none !important; + border: none !important; + background-color: transparent !important; + padding: 0px; + list-style-image: url("chrome://global/skin/icons/autocomplete-dropmarker.png"); + margin: 0px; +} + +/* ::::: autocomplete popups ::::: */ + +panel[type="private-autocomplete"], +panel[type="private-autocomplete-richlistbox"], +.private-autocomplete-history-popup { + padding: 0px !important; + color: -moz-FieldText; + background-color: -moz-Field; + font: icon; + -moz-appearance: none; +} + +.private-autocomplete-history-popup { + max-height: 180px; +} + +/* ::::: tree ::::: */ + +.private-autocomplete-tree { + -moz-appearance: none !important; + border: none !important; + background-color: transparent !important; +} + +.private-autocomplete-treecol { + -moz-appearance: none !important; + margin: 0 !important; + border: none !important; + padding: 0 !important; +} + +.private-autocomplete-treebody::-moz-tree-cell-text { + padding-left: 2px; +} + +.private-autocomplete-treebody::-moz-tree-row { + border-top: none; +} + +treechildren.private-autocomplete-treebody::-moz-tree-row(selected) { + background-color: Highlight; +} + +treechildren.private-autocomplete-treebody::-moz-tree-cell-text(selected) { + color: HighlightText !important; +} + +.private-autocomplete-treebody::-moz-tree-image(treecolAutoCompleteValue) { + max-width: 16px; + height: 16px; +} + +/* ::::: richlistbox autocomplete ::::: */ + +.private-autocomplete-richlistbox { + -moz-appearance: none; + margin: 0; +} + +.private-autocomplete-richlistitem[selected="true"] { + background-color: Highlight; + color: HighlightText; + background-image: linear-gradient(rgba(255,255,255,0.3), transparent); +} + +.private-autocomplete-richlistitem { + padding: 5px 2px; +} + +.ac-url-box { + /* When setting a vertical margin here, half of that needs to be added + .ac-title-box's translateY for when .ac-url-box is hidden (see below). */ + margin-top: 1px; +} + +.private-autocomplete-richlistitem[actiontype="keyword"] .ac-url-box, +.private-autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box, +.private-autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box, +.private-autocomplete-richlistitem[type~="autofill"] .ac-url-box { + visibility: hidden; +} + +.private-autocomplete-richlistitem[actiontype="keyword"] .ac-title-box, +.private-autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box, +.private-autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box, +.private-autocomplete-richlistitem[type~="autofill"] .ac-title-box { + /* Center the title by moving it down by half of .ac-url-box's height, + including vertical margins (if any). */ + transform: translateY(.5em); +} + +.ac-site-icon { + width: 16px; + height: 16px; + margin-bottom: -1px; + -moz-margin-start: 7px; + -moz-margin-end: 5px; +} + +.ac-type-icon { + width: 16px; + height: 16px; + -moz-margin-start: 6px; + -moz-margin-end: 4px; +} + +.ac-url-box > .ac-site-icon, +.ac-url-box > .ac-type-icon { + /* Otherwise the spacer is big enough to stretch its container */ + height: auto; +} + +.ac-extra > .ac-result-type-tag { + margin: 0 4px; +} + +.ac-extra > .ac-comment { + padding-right: 4px; +} + +.ac-ellipsis-after { + margin: 0 !important; + padding: 0; + min-width: 1.1em; +} + +.ac-normal-text { + margin: 0 !important; + padding: 0; +} + +.ac-normal-text > html|span { + margin: 0 !important; + padding: 0; +} + +html|span.ac-emphasize-text { + box-shadow: inset 0 0 1px 1px rgba(208,208,208,0.4); + background-color: rgba(208,208,208,0.2); + border-radius: 2px; + text-shadow: 0 0 currentColor; +} + +.ac-url-text > html|span.ac-emphasize-text, +.ac-action-text > html|span.ac-emphasize-text { + box-shadow: inset 0 0 1px 1px rgba(183,210,226,0.4); + background-color: rgba(183,210,226,0.3); +} + +.ac-title, .ac-url { + overflow: hidden; +} + +/* ::::: textboxes inside toolbarpaletteitems ::::: */ + +toolbarpaletteitem > toolbaritem > textbox > hbox > hbox > html|*.textbox-input { + visibility: hidden; +} + +toolbarpaletteitem > toolbaritem > * > textbox > hbox > hbox > html|*.textbox-input { + visibility: hidden; +} diff --git a/application/palemoon/themes/osx/browser.css b/application/palemoon/themes/osx/browser.css index a66ddacfc..8d709d8e1 100644 --- a/application/palemoon/themes/osx/browser.css +++ b/application/palemoon/themes/osx/browser.css @@ -452,7 +452,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { } @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-container, +@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-stack, @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon, @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { padding: 2px 6px; @@ -470,7 +470,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { } @navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container, +@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack, @navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon { padding: 3px 7px; } @@ -521,7 +521,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon, @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon, @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container, +@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-stack, @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon { background-image: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.5)); border-color: hsla(210,54%,20%,.25) hsla(210,54%,20%,.3) hsla(210,54%,20%,.35); @@ -544,7 +544,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active > .toolbarbutton-icon, @navbarLargeIcons@ .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon, @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container { +@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack { background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)); background-color: hsla(210,54%,20%,.15); border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4); @@ -2371,23 +2371,23 @@ toolbar[brighttext] #addonbar-closebutton { } %endif -.toolbarbutton-badge-container { +.toolbarbutton-badge-stack { margin: 0; padding: 0; position: relative; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-container { +@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-stack { padding: 2px 5px; } -.toolbarbutton-1 > .toolbarbutton-badge-container > .toolbar-icon { +.toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbar-icon { position: absolute; top: 2px; right: 2px; } -.toolbarbutton-badge-container > .toolbarbutton-icon[label]:not([label=""]) { +.toolbarbutton-badge-stack > .toolbarbutton-icon[label]:not([label=""]) { -moz-margin-end: 0; } diff --git a/application/palemoon/themes/osx/jar.mn b/application/palemoon/themes/osx/jar.mn index 904da3788..186cd8a75 100644 --- a/application/palemoon/themes/osx/jar.mn +++ b/application/palemoon/themes/osx/jar.mn @@ -15,6 +15,7 @@ browser.jar: #ifdef MOZ_SERVICES_SYNC skin/classic/browser/aboutSyncTabs.css #endif +* skin/classic/browser/autocomplete.css skin/classic/browser/actionicon-tab.png skin/classic/browser/appmenu-icons.png skin/classic/browser/appmenu-dropmarker.png diff --git a/application/palemoon/themes/windows/autocomplete.css b/application/palemoon/themes/windows/autocomplete.css new file mode 100644 index 000000000..b3cab44c8 --- /dev/null +++ b/application/palemoon/themes/windows/autocomplete.css @@ -0,0 +1,238 @@ +/* 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/. */ + +/* ===== autocomplete.css ================================================= + == Styles used by the autocomplete widget. + ======================================================================= */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +/* ::::: autocomplete ::::: */ + +/* .padded is used by autocomplete widgets that don't have an icon. Gross. -dwh */ +textbox:not(.padded) { + cursor: default; + padding: 0; +} + +textbox[nomatch="true"][highlightnonmatches="true"] { + color: red; +} + +.private-autocomplete-textbox-container { + -moz-box-align: center; +} + +textbox:not(.padded) .textbox-input-box { + margin: 0 3px; +} + +.textbox-input-box { + -moz-box-align: center; +} + +/* ::::: autocomplete popups ::::: */ + +panel[type="private-autocomplete"], +panel[type="private-autocomplete-richlistbox"], +.private-autocomplete-history-popup { + -moz-appearance: none; + border-width: 1px; + -moz-border-top-colors: ThreeDShadow; + -moz-border-right-colors: ThreeDShadow; + -moz-border-bottom-colors: ThreeDShadow; + -moz-border-left-colors: ThreeDShadow; + padding: 0; + color: -moz-FieldText; + background-color: -moz-Field; +} + +.private-autocomplete-history-popup { + max-height: 180px; +} + +/* ::::: tree ::::: */ + +.private-autocomplete-tree { + -moz-appearance: none !important; + border: none !important; + background-color: transparent !important; +} + +.private-autocomplete-treecol { + -moz-appearance: none !important; + margin: 0 !important; + border: none !important; + padding: 0 !important; +} + +/* GTK calculates space for a sort arrow */ +.private-autocomplete-treecol > .treecol-sortdirection { + -moz-appearance: none !important; +} + +.private-autocomplete-treebody::-moz-tree-cell-text { + -moz-padding-start: 8px; +} + +treechildren.private-autocomplete-treebody::-moz-tree-row(selected) { + background-color: Highlight; +} + +treechildren.private-autocomplete-treebody::-moz-tree-cell-text(selected) { + color: HighlightText !important; +} + +.private-autocomplete-treebody::-moz-tree-image(treecolAutoCompleteValue) { + max-width: 16px; + height: 16px; +} + +/* ::::: richlistbox autocomplete ::::: */ + +.private-autocomplete-richlistbox { + -moz-appearance: none; + margin: 0; +} + +.private-autocomplete-richlistitem { + padding: 1px; +} + +.private-autocomplete-richlistitem[selected="true"] { + background-color: Highlight; + color: HighlightText; +} + +%ifdef XP_WIN +@media (-moz-os-version: windows-vista) and (-moz-windows-default-theme), + (-moz-os-version: windows-win7) and (-moz-windows-default-theme) { + .private-autocomplete-richlistitem[selected="true"] { + color: inherit; + background-color: transparent; + /* four gradients for the bevel highlights on each edge, one for blue background */ + background-image: + linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, transparent 3px), + linear-gradient(to right, rgba(255,255,255,0.5) 3px, transparent 3px), + linear-gradient(to left, rgba(255,255,255,0.5) 3px, transparent 3px), + linear-gradient(to top, rgba(255,255,255,0.4) 3px, transparent 3px), + linear-gradient(to bottom, rgba(163,196,247,0.3), rgba(122,180,246,0.3)); + background-clip: content-box; + border-radius: 6px; + outline: 1px solid rgb(124,163,206); + -moz-outline-radius: 3px; + outline-offset: -2px; + } +} +%endif + +.ac-title-box { + margin-top: 4px; +} + +.ac-url-box { + /* When setting a vertical margin here, half of that needs to be added + .ac-title-box's translateY for when .ac-url-box is hidden (see below). */ + margin: 1px 0 4px; +} + +.private-autocomplete-richlistitem[actiontype="keyword"] .ac-url-box, +.private-autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box, +.private-autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box, +.private-autocomplete-richlistitem[type~="autofill"] .ac-url-box { + visibility: hidden; +} + +.private-autocomplete-richlistitem[actiontype="keyword"] .ac-title-box, +.private-autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box, +.private-autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box, +.private-autocomplete-richlistitem[type~="autofill"] .ac-title-box { + /* Center the title by moving it down by half of .ac-url-box's height, + including vertical margins (if any). */ + transform: translateY(calc(.5em + 2px)); +} + +.ac-site-icon { + width: 16px; + height: 16px; + margin: 0 5px -2px; +} + +.ac-type-icon { + width: 16px; + height: 16px; + -moz-margin-start: 6px; + -moz-margin-end: 4px; + margin-bottom: -1px; +} + +.ac-url-box > .ac-site-icon, +.ac-url-box > .ac-type-icon { + /* Otherwise the spacer is big enough to stretch its container */ + height: auto; +} + +.ac-extra > .ac-result-type-tag { + margin: 0 4px; +} + +.ac-extra > .ac-comment { + padding-right: 4px; +} + +.ac-ellipsis-after { + margin: 0 !important; + padding: 0; + min-width: 1em; +} + +.ac-normal-text { + margin: 0 !important; + padding: 0; +} + +.ac-normal-text > html|span { + margin: 0 !important; + padding: 0; +} + +html|span.ac-emphasize-text { + box-shadow: inset 0 0 1px 1px rgba(208,208,208,0.5); + background-color: rgba(208,208,208,0.3); + border-radius: 2px; + text-shadow: 0 0 currentColor; +} + +@media (-moz-windows-default-theme) { + @media not all and (-moz-os-version: windows-xp) { + html|span.ac-emphasize-text { + box-shadow: inset 0 0 1px 1px rgba(0,0,0,0.1); + background-color: rgba(0,0,0,0.05); + } + } + + @media (-moz-os-version: windows-xp) { + .ac-url-text > html|span.ac-emphasize-text, + .ac-action-text > html|span.ac-emphasize-text { + box-shadow: inset 0 0 1px 1px rgba(202,214,201,0.3); + background-color: rgba(202,214,201,0.2); + } + } +} + +.ac-title, .ac-url { + overflow: hidden; +} + +/* ::::: textboxes inside toolbarpaletteitems ::::: */ + +toolbarpaletteitem > toolbaritem > textbox > hbox > hbox > html|*.textbox-input { + visibility: hidden; +} + +toolbarpaletteitem > toolbaritem > * > textbox > hbox > hbox > html|*.textbox-input { + visibility: hidden; +} + diff --git a/application/palemoon/themes/windows/browser.css b/application/palemoon/themes/windows/browser.css index a64955f0f..1c51accae 100644 --- a/application/palemoon/themes/windows/browser.css +++ b/application/palemoon/themes/windows/browser.css @@ -825,7 +825,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { } @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-container, +@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-stack, @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon, @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { padding: 2px 6px; @@ -848,7 +848,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { } @navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container, +@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack, @navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon { padding: 3px 7px; } @@ -897,7 +897,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { } @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container, +@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-stack, @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon, @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { background-image: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.5)); @@ -916,7 +916,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { } @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container, +@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack, @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active > .toolbarbutton-icon, @navbarLargeIcons@ .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon { background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)); @@ -2845,23 +2845,23 @@ toolbar[brighttext] #addonbar-closebutton { } %endif -.toolbarbutton-badge-container { +.toolbarbutton-badge-stack { margin: 0; padding: 0; position: relative; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-container { +@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-stack { padding: 2px 5px; } -.toolbarbutton-1 > .toolbarbutton-badge-container > .toolbar-icon { +.toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbar-icon { position: absolute; top: 2px; right: 2px; } -.toolbarbutton-badge-container > .toolbarbutton-icon[label]:not([label=""]) { +.toolbarbutton-badge-stack > .toolbarbutton-icon[label]:not([label=""]) { -moz-margin-end: 0; } diff --git a/application/palemoon/themes/windows/jar.mn b/application/palemoon/themes/windows/jar.mn index 30643570b..a66714b13 100644 --- a/application/palemoon/themes/windows/jar.mn +++ b/application/palemoon/themes/windows/jar.mn @@ -15,6 +15,7 @@ browser.jar: #ifdef MOZ_SERVICES_SYNC skin/classic/browser/aboutSyncTabs.css #endif +* skin/classic/browser/autocomplete.css skin/classic/browser/actionicon-tab.png skin/classic/browser/appmenu-icons.png skin/classic/browser/appmenu-dropmarker.png diff --git a/application/xulrunner/README.xulrunner b/application/xulrunner/README.xulrunner new file mode 100644 index 000000000..424b7a615 --- /dev/null +++ b/application/xulrunner/README.xulrunner @@ -0,0 +1,13 @@ +XULRunner is a package which can be used to run applications written in HTML +or XUL. It can also be used to embed the gecko rendering engine into +binary applications. + +XULRunner is not a product; it is a tool which can be used to create products. +It is a byproduct of Firefox development and the Mozilla community does not +have a strong commitment to support XULRunner development apart from Firefox +development. + +For more information about using XULRunner or how to use this binary package, +see the Mozilla Developer Center article: + +https://developer.mozilla.org/en/XULRunner diff --git a/application/xulrunner/app.mozbuild b/application/xulrunner/app.mozbuild new file mode 100644 index 000000000..7b8316016 --- /dev/null +++ b/application/xulrunner/app.mozbuild @@ -0,0 +1,13 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include('/toolkit/toolkit.mozbuild') + +if CONFIG['MOZ_EXTENSIONS']: + DIRS += ['/extensions'] + +DIRS += [ + '/application/xulrunner', +] diff --git a/application/xulrunner/app/Makefile.in b/application/xulrunner/app/Makefile.in new file mode 100644 index 000000000..98e377d69 --- /dev/null +++ b/application/xulrunner/app/Makefile.in @@ -0,0 +1,75 @@ +# vim:set ts=8 sw=8 sts=8 et: +# 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/. + +GARBAGE += $(addprefix $(DIST)/bin/defaults/pref/,xulrunner.js) + +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) +TK_LIBS := -framework Cocoa $(TK_LIBS) +endif + +ifndef MOZ_WINCONSOLE +ifdef MOZ_DEBUG +MOZ_WINCONSOLE = 1 +else +MOZ_WINCONSOLE = 0 +endif +endif + +# This switches $(INSTALL) to copy mode, like $(SYSINSTALL), so things that +# shouldn't get 755 perms need $(IFLAGS1) for either way of calling nsinstall. +NSDISTMODE = copy + +include $(topsrcdir)/config/config.mk + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DXULRUNNER_ICO='"$(DIST)/branding/xulrunner.ico"' -DDOCUMENT_ICO='"$(DIST)/branding/document.ico"' + +ifdef MOZ_WIDGET_GTK +libs:: + $(INSTALL) $(IFLAGS1) $(DIST)/branding/default16.png $(DIST)/bin/chrome/icons/default + $(INSTALL) $(IFLAGS1) $(DIST)/branding/default32.png $(DIST)/bin/chrome/icons/default + $(INSTALL) $(IFLAGS1) $(DIST)/branding/default48.png $(DIST)/bin/chrome/icons/default +endif + +# XXX applications would need to supply this file +#export:: brand.dtd.in +# $(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $^ -o brand.dtd) + +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) + +FRAMEWORK_NAME = XUL +FRAMEWORK_VERSION = $(MOZILLA_VERSION) + +FRAMEWORK_DIR = \ + $(DIST)/$(FRAMEWORK_NAME).framework/Versions/$(FRAMEWORK_VERSION) + +$(FRAMEWORK_DIR)/Resources: + $(NSINSTALL) -D $@ + +tools:: $(PROGRAM) $(FRAMEWORK_DIR)/Resources + $(NSINSTALL) $(srcdir)/macbuild/InfoPlist.strings $(FRAMEWORK_DIR)/Resources + sed -e 's/APP_VERSION/$(APP_VERSION)/' $(srcdir)/macbuild/Info.plist.in > $(FRAMEWORK_DIR)/Info.plist + rsync -av $(DIST)/bin/ $(FRAMEWORK_DIR) --exclude mangle --exclude shlibsign + rm -f $(DIST)/$(FRAMEWORK_NAME).framework/Versions/Current \ + $(DIST)/$(FRAMEWORK_NAME).framework/libxpcom.dylib \ + $(DIST)/$(FRAMEWORK_NAME).framework/XUL \ + $(DIST)/$(FRAMEWORK_NAME).framework/xulrunner + ln -s $(FRAMEWORK_VERSION) $(DIST)/$(FRAMEWORK_NAME).framework/Versions/Current + ln -s Versions/Current/libxpcom.dylib $(DIST)/$(FRAMEWORK_NAME).framework/libxpcom.dylib + ln -s Versions/Current/XUL $(DIST)/$(FRAMEWORK_NAME).framework/XUL + ln -s Versions/Current/xulrunner $(DIST)/$(FRAMEWORK_NAME).framework/xulrunner + +clean clobber:: + rm -rf $(DIST)/$(FRAMEWORK_NAME).framework +endif + +README_FILE = $(srcdir)/../README.xulrunner + +libs:: + $(INSTALL) $(IFLAGS1) $(README_FILE) $(DIST)/bin + $(INSTALL) $(IFLAGS1) $(topsrcdir)/LICENSE $(DIST)/bin + $(INSTALL) $(IFLAGS1) $(srcdir)/install_app.py $(DIST)/bin + diff --git a/application/xulrunner/app/default16.png b/application/xulrunner/app/default16.png Binary files differnew file mode 100644 index 000000000..e74f5cf2e --- /dev/null +++ b/application/xulrunner/app/default16.png diff --git a/application/xulrunner/app/default32.png b/application/xulrunner/app/default32.png Binary files differnew file mode 100644 index 000000000..914509054 --- /dev/null +++ b/application/xulrunner/app/default32.png diff --git a/application/xulrunner/app/default48.png b/application/xulrunner/app/default48.png Binary files differnew file mode 100644 index 000000000..5fd71e110 --- /dev/null +++ b/application/xulrunner/app/default48.png diff --git a/application/xulrunner/app/document.ico b/application/xulrunner/app/document.ico Binary files differnew file mode 100644 index 000000000..311116324 --- /dev/null +++ b/application/xulrunner/app/document.ico diff --git a/application/xulrunner/app/install_app.py b/application/xulrunner/app/install_app.py new file mode 100644 index 000000000..6be8c5ecb --- /dev/null +++ b/application/xulrunner/app/install_app.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +# Min version of python is 2.7 +import sys +if ((sys.version_info.major != 2) or (sys.version_info.minor < 7)): + raise Exception("You need to use Python version 2.7 or higher") + +import os, shutil, re, zipfile +from ConfigParser import SafeConfigParser + +# Platform-specific support +# see https://developer.mozilla.org/en/XULRunner/Deploying_XULRunner_1.8 +if sys.platform.startswith('linux') or sys.platform == "win32": + def installApp(appLocation, installDir, appName, greDir): + zipApp, iniParser, appName = validateArguments(appLocation, installDir, appName, greDir) + if (zipApp): + zipApp.extractAll(installDir) + else: + shutil.copytree(appLocation, installDir) + shutil.copy2(os.path.join(greDir, xulrunnerStubName), + os.path.join(installDir, appName)) + copyGRE(greDir, os.path.join(installDir, "xulrunner")) + +if sys.platform.startswith('linux'): + xulrunnerStubName = "xulrunner-stub" + + def makeAppName(leafName): + return leafName.lower() + +elif sys.platform == "win32": + xulrunnerStubName = "xulrunner-stub.exe" + + def makeAppName(leafName): + return leafName + ".exe" + +elif sys.platform == "darwin": + xulrunnerStubName = "xulrunner-stub" + + def installApp(appLocation, installDir, appName, greDir): + zipApp, iniparser, appName = validateArguments(appLocation, installDir, appName, greDir) + installDir += "/" + appName + ".app" + resourcesDir = os.path.join(installDir, "Contents/Resources") + if (zipApp): + zipApp.extractAll(resourcesDir) + else: + shutil.copytree(appLocation, resourcesDir) + MacOSDir = os.path.join(installDir, "Contents/MacOS") + os.makedirs(MacOSDir) + shutil.copy2(os.path.join(greDir, xulrunnerStubName), MacOSDir) + copyGRE(greDir, + os.path.join(installDir, "Contents/Frameworks/XUL.framework")) + + # Contents/Info.plist + contents = """<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> +<key>CFBundleInfoDictionaryVersion</key> +<string>6.0</string> +<key>CFBundlePackageType</key> +<string>APPL</string> +<key>CFBundleSignature</key> +<string>????</string> +<key>CFBundleExecutable</key> +<string>xulrunner</string> +<key>NSAppleScriptEnabled</key> +<true/> +<key>CFBundleGetInfoString</key> +<string>$infoString</string> +<key>CFBundleName</key> +<string>$appName</string> +<key>CFBundleShortVersionString</key> +<string>$version</string> +<key>CFBundleVersion</key> +<string>$version.$buildID</string> +<key>CFBundleIdentifier</key> +<string>$reverseVendor</string> +</dict> +</plist> +""" + version = iniparser.get("App", "Version") + buildID = iniparser.get("App", "BuildID") + infoString = appName + " " + version + reverseVendor = "com.vendor.unknown" + appID = iniparser.get("App", "ID") + colonIndex = appID.find("@") + 1 + if (colonIndex != 0): + vendor = appID[colonIndex:] + reverseVendor = ".".join(vendor.split(".")[::-1]) + contents = contents.replace("$infoString", infoString) + contents = contents.replace("$appName", appName) + contents = contents.replace("$version", version) + contents = contents.replace("$buildID", buildID) + contents = contents.replace("$reverseVendor", reverseVendor) + infoPList = open(os.path.join(installDir, "Contents/Info.plist"), "w+b") + infoPList.write(contents) + infoPList.close() + + def makeAppName(leafName): + return leafName + +else: + # Implement xulrunnerStubName, installApp and makeAppName as above. + raise Exception("This operating system isn't supported for install_app.py yet!") +# End platform-specific support + +def resolvePath(path): + return os.path.realpath(path) + +def requireINIOption(iniparser, section, option): + if not (iniparser.has_option(section, option)): + raise Exception("application.ini must have a " + option + " option under the " + section + " section") + +def checkAppINI(appLocation): + if (os.path.isdir(appLocation)): + zipApp = None + appINIPath = os.path.join(appLocation, "application.ini") + if not (os.path.isfile(appINIPath)): + raise Exception(appINIPath + " does not exist") + appINI = open(appINIPath) + elif (zipfile.is_zipfile(appLocation)): + zipApp = zipfile.ZipFile(appLocation) + if not ("application.ini" in zipApp.namelist()): + raise Exception("jar:" + appLocation + "!/application.ini does not exist") + appINI = zipApp.open("application.ini") + else: + raise Exception("appLocation must be a directory containing application.ini or a zip file with application.ini at its root") + + # application.ini verification + iniparser = SafeConfigParser() + iniparser.readfp(appINI) + if not (iniparser.has_section("App")): + raise Exception("application.ini must have an App section") + if not (iniparser.has_section("Gecko")): + raise Exception("application.ini must have a Gecko section") + requireINIOption(iniparser, "App", "Name") + requireINIOption(iniparser, "App", "Version") + requireINIOption(iniparser, "App", "BuildID") + requireINIOption(iniparser, "App", "ID") + requireINIOption(iniparser, "Gecko", "MinVersion") + + return zipApp, iniparser + pass + +def copyGRE(greDir, targetDir): + shutil.copytree(greDir, targetDir, symlinks=True) + +def validateArguments(appLocation, installDir, appName, greDir): + # application directory / zip verification + appLocation = resolvePath(appLocation) + + # target directory + installDir = resolvePath(installDir) + + if (os.path.exists(installDir)): + raise Exception("installDir must not exist: " + cmds.installDir) + + greDir = resolvePath(greDir) + xulrunnerStubPath = os.path.isfile(os.path.join(greDir, xulrunnerStubName)) + if not xulrunnerStubPath: + raise Exception("XULRunner stub executable not found: " + os.path.join(greDir, xulrunnerStubName)) + + # appName + zipApp, iniparser = checkAppINI(appLocation) + if not appName: + appName = iniparser.get("App", "Name") + appName = makeAppName(appName) + pattern = re.compile("[\\\/\:*?\"<>|\x00]") + if pattern.search(appName): + raise Exception("App name has illegal characters for at least one operating system") + return zipApp, iniparser, appName + +def handleCommandLine(): + import argparse + + # Argument parsing. + parser = argparse.ArgumentParser( + description="XULRunner application installer", + usage="""install_app.py appLocation installDir greDir [--appName APPNAME] + install_app.py -h + install_app.py --version + """ + ) + parser.add_argument( + "appLocation", + action="store", + help="The directory or ZIP file containing application.ini as a top-level child file" + ) + parser.add_argument( + "installDir", + action="store", + help="The directory to install the application to" + ) + parser.add_argument( + "--greDir", + action="store", + help="The directory containing the Gecko SDK (usually where this Python script lives)", + default=os.path.dirname(sys.argv[0]) + ) + parser.add_argument( + "--appName", + action="store", + help="The name of the application to install" + ) + parser.add_argument("--version", action="version", version="%(prog)s 1.0") + + # The command code. + cmds = parser.parse_args() + try: + installApp(cmds.appLocation, cmds.installDir, cmds.appName, cmds.greDir) + except exn: + shutil.rmtree(cmds.installDir) + raise exn + print cmds.appName + " application installed to " + cmds.installDir + +if __name__ == '__main__': + handleCommandLine() diff --git a/application/xulrunner/app/macbuild/Info.plist.in b/application/xulrunner/app/macbuild/Info.plist.in new file mode 100644 index 000000000..69676b80c --- /dev/null +++ b/application/xulrunner/app/macbuild/Info.plist.in @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>xulrunner-bin</string> + <key>CFBundleIdentifier</key> + <string>org.mozilla.xulrunner</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>XULRunner</string> + <key>CFBundlePackageType</key> + <string>FMWK</string> + <key>CFBundleSignature</key> + <string>MOZB</string> + <key>CFBundleVersion</key> + <string>APP_VERSION</string> + <key>LSMinimumSystemVersion</key> + <string>10.5</string> + <key>LSMinimumSystemVersionByArchitecture</key> + <dict> + <key>i386</key> + <string>10.5.0</string> + <key>x86_64</key> + <string>10.6.0</string> + </dict> +</dict> +</plist> diff --git a/application/xulrunner/app/macbuild/InfoPlist.strings b/application/xulrunner/app/macbuild/InfoPlist.strings Binary files differnew file mode 100644 index 000000000..5d9eefd51 --- /dev/null +++ b/application/xulrunner/app/macbuild/InfoPlist.strings diff --git a/application/xulrunner/app/moz.build b/application/xulrunner/app/moz.build new file mode 100644 index 000000000..1c9cb117c --- /dev/null +++ b/application/xulrunner/app/moz.build @@ -0,0 +1,70 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +GeckoProgram('xulrunner') + +SOURCES += [ + 'nsXULRunnerApp.cpp', +] + +DEFINES['XULRUNNER_PROGNAME'] = '"xulrunner"' +if CONFIG['MOZ_DEBUG']: + DEFINES['DEBUG'] = True + +LOCAL_INCLUDES += [ + '/toolkit/profile', + '/toolkit/xre', + '/xpcom/base', + '/xpcom/build', +] + +if CONFIG['_MSC_VER']: + # Always enter a Windows program through wmain, whether or not we're + # a console application. + WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup'] + +# Control the default heap size. +# This is the heap returned by GetProcessHeap(). +# As we use the CRT heap, the default size is too large and wastes VM. +# +# The default heap size is 1MB on Win32. +# The heap will grow if need be. +# +# Set it to 256k. See bug 127069. +if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']: + LDFLAGS += ['/HEAP:0x40000'] + +if CONFIG['OS_ARCH'] == 'WINNT': + RCINCLUDE = 'splash.rc' + OS_LIBS += [ + 'comctl32', + 'comdlg32', + 'uuid', + 'shell32', + 'ole32', + 'oleaut32', + 'version', + 'winspool', + ] + +DISABLE_STL_WRAPPING = True + +JS_PREFERENCE_PP_FILES += [ + 'xulrunner.js', +] + +if CONFIG['OS_ARCH'] == 'WINNT': + BRANDING_FILES += [ + 'document.ico', + 'xulrunner.ico', + ] + +if CONFIG['MOZ_WIDGET_GTK']: + BRANDING_FILES += [ + 'default16.png', + 'default32.png', + 'default48.png', + ] diff --git a/application/xulrunner/app/nsXULRunnerApp.cpp b/application/xulrunner/app/nsXULRunnerApp.cpp new file mode 100644 index 000000000..d86317a85 --- /dev/null +++ b/application/xulrunner/app/nsXULRunnerApp.cpp @@ -0,0 +1,294 @@ +/* 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/. */ + +#include "nsXULAppAPI.h" +#include "nsXPCOMGlue.h" +#include <stdio.h> +#include <stdlib.h> +#ifdef XP_WIN +#include <windows.h> +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif +#define strcasecmp _stricmp +#endif + +#include "nsAppRunner.h" +#include "nsIFile.h" +#include "nsCOMPtr.h" +#include "nsMemory.h" +#include "nsCRTGlue.h" +#include "nsStringAPI.h" +#include "nsServiceManagerUtils.h" +#include "plstr.h" +#include "prprf.h" +#include "prenv.h" +#include "nsINIParser.h" + +#ifdef XP_WIN +#define XRE_DONT_SUPPORT_XPSP2 // See https://bugzil.la/1023941#c32 +#include "nsWindowsWMain.cpp" +#endif + +#include "BinaryPath.h" + +#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL + +using namespace mozilla; + +/** + * Output a string to the user. This method is really only meant to be used to + * output last-ditch error messages designed for developers NOT END USERS. + * + * @param isError + * Pass true to indicate severe errors. + * @param fmt + * printf-style format string followed by arguments. + */ +static void Output(bool isError, const char *fmt, ... ) +{ + va_list ap; + va_start(ap, fmt); + +#if (defined(XP_WIN) && !MOZ_WINCONSOLE) + wchar_t msg[2048]; + _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap); + + UINT flags = MB_OK; + if (isError) + flags |= MB_ICONERROR; + else + flags |= MB_ICONINFORMATION; + + MessageBoxW(nullptr, msg, L"XULRunner", flags); +#else + vfprintf(stderr, fmt, ap); +#endif + + va_end(ap); +} + +/** + * Return true if |arg| matches the given argument name. + */ +static bool IsArg(const char* arg, const char* s) +{ + if (*arg == '-') + { + if (*++arg == '-') + ++arg; + return !strcasecmp(arg, s); + } + +#if defined(XP_WIN) + if (*arg == '/') + return !strcasecmp(++arg, s); +#endif + + return false; +} + +static nsresult +GetGREVersion(const char *argv0, + nsACString *aMilestone, + nsACString *aVersion) +{ + if (aMilestone) + aMilestone->AssignLiteral("<Error>"); + if (aVersion) + aVersion->AssignLiteral("<Error>"); + + nsCOMPtr<nsIFile> iniFile; + nsresult rv = BinaryPath::GetFile(argv0, getter_AddRefs(iniFile)); + if (NS_FAILED(rv)) + return rv; + + iniFile->SetNativeLeafName(NS_LITERAL_CSTRING("platform.ini")); + + nsINIParser parser; + rv = parser.Init(iniFile); + if (NS_FAILED(rv)) + return rv; + + if (aMilestone) { + rv = parser.GetString("Build", "Milestone", *aMilestone); + if (NS_FAILED(rv)) + return rv; + } + if (aVersion) { + rv = parser.GetString("Build", "BuildID", *aVersion); + if (NS_FAILED(rv)) + return rv; + } + return NS_OK; +} + +static void Usage(const char *argv0) +{ + nsAutoCString milestone; + GetGREVersion(argv0, &milestone, nullptr); + + // display additional information (XXX make localizable?) + Output(false, + "Mozilla XULRunner %s\n\n" + "Usage: " XULRUNNER_PROGNAME " [OPTIONS]\n" + " " XULRUNNER_PROGNAME " APP-FILE [APP-OPTIONS...]\n" + "\n" + "OPTIONS\n" + " --app specify APP-FILE (optional)\n" + " -h, --help show this message\n" + " -v, --version show version\n" + " --gre-version print the GRE version string on stdout\n" + "\n" + "APP-FILE\n" + " Application initialization file.\n" + "\n" + "APP-OPTIONS\n" + " Application specific options.\n", + milestone.get()); +} + +XRE_GetFileFromPathType XRE_GetFileFromPath; +XRE_CreateAppDataType XRE_CreateAppData; +XRE_FreeAppDataType XRE_FreeAppData; +XRE_mainType XRE_main; + +static const nsDynamicFunctionLoad kXULFuncs[] = { + { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, + { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, + { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, + { "XRE_main", (NSFuncPtr*) &XRE_main }, + { nullptr, nullptr } +}; + +class AutoAppData +{ +public: + AutoAppData(nsIFile* aINIFile) : mAppData(nullptr) { + nsresult rv = XRE_CreateAppData(aINIFile, &mAppData); + if (NS_FAILED(rv)) + mAppData = nullptr; + } + ~AutoAppData() { + if (mAppData) + XRE_FreeAppData(mAppData); + } + + operator nsXREAppData*() const { return mAppData; } + nsXREAppData* operator -> () const { return mAppData; } + +private: + nsXREAppData* mAppData; +}; + +int main(int argc, char* argv[]) +{ + char exePath[MAXPATHLEN]; + nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath); + if (NS_FAILED(rv)) { + Output(true, "Couldn't calculate the application directory.\n"); + return 255; + } + + char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); + if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_DLL) - 1)) + return 255; + + strcpy(++lastSlash, XPCOM_DLL); + + rv = XPCOMGlueStartup(exePath); + if (NS_FAILED(rv)) { + Output(true, "Couldn't load XPCOM.\n"); + return 255; + } + + if (argc > 1 && (IsArg(argv[1], "h") || + IsArg(argv[1], "help") || + IsArg(argv[1], "?"))) + { + Usage(argv[0]); + return 0; + } + + if (argc == 2 && (IsArg(argv[1], "v") || IsArg(argv[1], "version"))) + { + nsAutoCString milestone; + nsAutoCString version; + GetGREVersion(argv[0], &milestone, &version); + Output(false, "Mozilla XULRunner %s - %s\n", + milestone.get(), version.get()); + return 0; + } + + rv = XPCOMGlueLoadXULFunctions(kXULFuncs); + if (NS_FAILED(rv)) { + Output(true, "Couldn't load XRE functions.\n"); + return 255; + } + + if (argc > 1) { + nsAutoCString milestone; + rv = GetGREVersion(argv[0], &milestone, nullptr); + if (NS_FAILED(rv)) + return 2; + + if (IsArg(argv[1], "gre-version")) { + if (argc != 2) { + Usage(argv[0]); + return 1; + } + + printf("%s\n", milestone.get()); + return 0; + } + + if (IsArg(argv[1], "install-app")) { + Output(true, "--install-app support has been removed. Use 'python install-app.py' instead.\n"); + return 1; + } + } + + const char *appDataFile = getenv("XUL_APP_FILE"); + + if (!(appDataFile && *appDataFile)) { + if (argc < 2) { + Usage(argv[0]); + return 1; + } + + if (IsArg(argv[1], "app")) { + if (argc == 2) { + Usage(argv[0]); + return 1; + } + argv[1] = argv[0]; + ++argv; + --argc; + } + + appDataFile = argv[1]; + argv[1] = argv[0]; + ++argv; + --argc; + + static char kAppEnv[MAXPATHLEN]; + snprintf(kAppEnv, MAXPATHLEN, "XUL_APP_FILE=%s", appDataFile); + putenv(kAppEnv); + } + + nsCOMPtr<nsIFile> appDataLF; + rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appDataLF)); + if (NS_FAILED(rv)) { + Output(true, "Error: unrecognized application.ini path.\n"); + return 2; + } + + AutoAppData appData(appDataLF); + if (!appData) { + Output(true, "Error: couldn't parse application.ini.\n"); + return 2; + } + + return XRE_main(argc, argv, appData, 0); +} diff --git a/application/xulrunner/app/splash.rc b/application/xulrunner/app/splash.rc new file mode 100644 index 000000000..4374383ba --- /dev/null +++ b/application/xulrunner/app/splash.rc @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <windows.h> +#include "nsNativeAppSupportWin.h" + +1 24 "xulrunner.exe.manifest" + +IDI_APPICON ICON XULRUNNER_ICO +IDI_DOCUMENT ICON DOCUMENT_ICO +IDI_APPLICATION ICON XULRUNNER_ICO + +STRINGTABLE DISCARDABLE +BEGIN +#ifdef DEBUG + IDS_STARTMENU_APPNAME, "Firefox Debug" +#else + IDS_STARTMENU_APPNAME, "Firefox" +#endif +END diff --git a/application/xulrunner/app/xulrunner.exe.manifest b/application/xulrunner/app/xulrunner.exe.manifest new file mode 100644 index 000000000..b08eea074 --- /dev/null +++ b/application/xulrunner/app/xulrunner.exe.manifest @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="*" + name="Mozilla.XULRunner" + type="win32" +/> +<description>Mozilla XULRunner</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="*" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"> + <ms_asmv3:security> + <ms_asmv3:requestedPrivileges> + <ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" /> + </ms_asmv3:requestedPrivileges> + </ms_asmv3:security> +</ms_asmv3:trustInfo> + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <application> + <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> + <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> + <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> + <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> + <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> + </application> + </compatibility> +</assembly> diff --git a/application/xulrunner/app/xulrunner.ico b/application/xulrunner/app/xulrunner.ico Binary files differnew file mode 100644 index 000000000..0518438a0 --- /dev/null +++ b/application/xulrunner/app/xulrunner.ico diff --git a/application/xulrunner/app/xulrunner.js b/application/xulrunner/app/xulrunner.js new file mode 100644 index 000000000..509bb48a5 --- /dev/null +++ b/application/xulrunner/app/xulrunner.js @@ -0,0 +1,26 @@ +/* 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/. */ + +#filter substitution + +// We need to override the default values of these preferences since all.js +// assumes these are in the navigator package, which for us is nonexistent. +// XXX(darin): perhaps all.js should not be seamonkey specific +pref("general.useragent.locale", "@AB_CD@"); +pref("xpinstall.dialog.confirm", "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"); +pref("xpinstall.dialog.progress.chrome", "chrome://mozapps/content/extensions/extensions.xul"); +pref("xpinstall.dialog.progress.skin", "chrome://mozapps/content/extensions/extensions.xul"); +pref("xpinstall.dialog.progress.type.chrome", "Extension:Manager"); +pref("xpinstall.dialog.progress.type.skin", "Extension:Manager"); +pref("xpinstall.enabled", true); +#ifdef XP_WIN +pref("browser.preferences.instantApply", false); +#else +pref("browser.preferences.instantApply", true); +#endif +#ifdef XP_MACOSX +pref("browser.preferences.animateFadeIn", true); +#else +pref("browser.preferences.animateFadeIn", false); +#endif diff --git a/application/xulrunner/config/mozconfig b/application/xulrunner/config/mozconfig new file mode 100644 index 000000000..9fa972cac --- /dev/null +++ b/application/xulrunner/config/mozconfig @@ -0,0 +1,9 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This file specifies the build flags for XULRunner. You can use it by adding: +# . $topsrcdir/xulrunner/config/mozconfig +# to the top of your mozconfig file. + +ac_add_options --enable-application=xulrunner diff --git a/browser/extensions/formautofill/jar.mn b/application/xulrunner/config/mozconfigs/common index 0cba721ef..a6811c575 100644 --- a/browser/extensions/formautofill/jar.mn +++ b/application/xulrunner/config/mozconfigs/common @@ -2,6 +2,6 @@ # 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/. -[features/formautofill@mozilla.org] chrome.jar: -% resource formautofill %content/ - content/ (content/*) +# This file is included at the top of all xulrunner mozconfigs + +. "$topsrcdir/build/mozconfig.common" diff --git a/application/xulrunner/config/mozconfigs/common.override b/application/xulrunner/config/mozconfigs/common.override new file mode 100644 index 000000000..8d719a5b5 --- /dev/null +++ b/application/xulrunner/config/mozconfigs/common.override @@ -0,0 +1,8 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This file is included at the bottom of all xulrunner mozconfigs + +. "$topsrcdir/build/mozconfig.common.override" +. "$topsrcdir/build/mozconfig.cache" diff --git a/application/xulrunner/config/mozconfigs/linux32/xulrunner b/application/xulrunner/config/mozconfigs/linux32/xulrunner new file mode 100644 index 000000000..171674f8c --- /dev/null +++ b/application/xulrunner/config/mozconfigs/linux32/xulrunner @@ -0,0 +1,9 @@ +export MOZILLA_OFFICIAL=1 +export JAVA_HOME=/tools/jdk + +ac_add_options --enable-application=xulrunner +ac_add_options --disable-tests + +. $topsrcdir/build/unix/mozconfig.linux32 + +. "$topsrcdir/xulrunner/config/mozconfigs/common.override" diff --git a/application/xulrunner/config/mozconfigs/linux32/xulrunner-qt b/application/xulrunner/config/mozconfigs/linux32/xulrunner-qt new file mode 100644 index 000000000..54e4ecb8f --- /dev/null +++ b/application/xulrunner/config/mozconfigs/linux32/xulrunner-qt @@ -0,0 +1,15 @@ +export MOZILLA_OFFICIAL=1 +export JAVA_HOME=/tools/jdk + +ac_add_options --enable-application=xulrunner +ac_add_options --disable-tests + +. $topsrcdir/build/unix/mozconfig.linux32 + +# QT Options +export PKG_CONFIG_PATH=/tools/qt-4.6.3/qt/lib/pkgconfig +ac_add_options --with-qtdir=/tools/qt-4.6.3/qt +ac_add_options --enable-default-toolkit=cairo-qt +ac_add_options --disable-crashreporter + +. "$topsrcdir/xulrunner/config/mozconfigs/common.override" diff --git a/application/xulrunner/config/mozconfigs/linux64/xulrunner b/application/xulrunner/config/mozconfigs/linux64/xulrunner new file mode 100644 index 000000000..c18a12f67 --- /dev/null +++ b/application/xulrunner/config/mozconfigs/linux64/xulrunner @@ -0,0 +1,9 @@ +export MOZILLA_OFFICIAL=1 +export JAVA_HOME=/tools/jdk + +ac_add_options --enable-application=xulrunner +ac_add_options --disable-tests + +. $topsrcdir/build/unix/mozconfig.linux + +. "$topsrcdir/xulrunner/config/mozconfigs/common.override" diff --git a/application/xulrunner/config/mozconfigs/macosx-universal/xulrunner b/application/xulrunner/config/mozconfigs/macosx-universal/xulrunner new file mode 100644 index 000000000..ac7e24fe2 --- /dev/null +++ b/application/xulrunner/config/mozconfigs/macosx-universal/xulrunner @@ -0,0 +1,9 @@ +. $topsrcdir/build/macosx/universal/mozconfig + +export MOZILLA_OFFICIAL=1 + +ac_add_options --enable-application=xulrunner +ac_add_options --disable-tests +ac_add_options --with-xulrunner-stub-name=xulrunner-stub + +. "$topsrcdir/xulrunner/config/mozconfigs/common.override" diff --git a/application/xulrunner/config/mozconfigs/win32/xulrunner b/application/xulrunner/config/mozconfigs/win32/xulrunner new file mode 100644 index 000000000..4c8b596a5 --- /dev/null +++ b/application/xulrunner/config/mozconfigs/win32/xulrunner @@ -0,0 +1,16 @@ +. "$topsrcdir/xulrunner/config/mozconfigs/common" + +export MOZILLA_OFFICIAL=1 +export JAVA_HOME=/d/jdk1.6.0_14 + +ac_add_options --enable-application=xulrunner +ac_add_options --enable-jemalloc +ac_add_options --disable-tests + +if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then + . $topsrcdir/build/win32/mozconfig.vs2013-win64 +else + . $topsrcdir/build/win32/mozconfig.vs2010 +fi + +. "$topsrcdir/xulrunner/config/mozconfigs/common.override" diff --git a/application/xulrunner/config/mozconfigs/win64/xulrunner b/application/xulrunner/config/mozconfigs/win64/xulrunner new file mode 100644 index 000000000..7dbade2bb --- /dev/null +++ b/application/xulrunner/config/mozconfigs/win64/xulrunner @@ -0,0 +1,15 @@ +. "$topsrcdir/xulrunner/config/mozconfigs/common" + +ac_add_options --target=x86_64-pc-mingw32 +ac_add_options --host=x86_64-pc-mingw32 + +export MOZILLA_OFFICIAL=1 +export JAVA_HOME=/d/jdk1.6.0_14 + +ac_add_options --enable-application=xulrunner +ac_add_options --enable-jemalloc +ac_add_options --disable-tests + +. $topsrcdir/build/win64/mozconfig.vs2013 + +. "$topsrcdir/xulrunner/config/mozconfigs/common.override" diff --git a/application/xulrunner/configure.in b/application/xulrunner/configure.in new file mode 100644 index 000000000..825faaddd --- /dev/null +++ b/application/xulrunner/configure.in @@ -0,0 +1,11 @@ +dnl -*- Mode: Autoconf; tab-width: 2; indent-tabs-mode: nil; -*- +dnl vi: set tabstop=2 shiftwidth=2 expandtab: +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl Things we need to carry from confvars.sh +AC_SUBST(MOZ_XULRUNNER) +AC_DEFINE(MOZ_XULRUNNER) + +dnl Optional parts of the build. diff --git a/application/xulrunner/confvars.sh b/application/xulrunner/confvars.sh new file mode 100644 index 000000000..a317df2a6 --- /dev/null +++ b/application/xulrunner/confvars.sh @@ -0,0 +1,28 @@ +#! /bin/sh +# 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/. + +MOZ_XULRUNNER=1 +MC_OFFICIAL=1 + +MOZ_APP_NAME=xulrunner +MOZ_APP_DISPLAYNAME=XULRunner +MOZ_APP_VERSION=$MOZILLA_VERSION +MOZ_CHROME_FILE_FORMAT=omni + +MOZ_UPDATER=1 + +if test "$OS_ARCH" = "WINNT"; then + MOZ_MAINTENANCE_SERVICE= +fi + +MOZ_PLACES=1 +MOZ_WEBRTC=1 +MOZ_WEBGL_CONFORMANT=1 + +MOZ_EXTENSIONS_DEFAULT=" gio" + +MOZ_SERVICES_COMMON=1 +MOZ_SERVICES_SYNC=1 +MOZ_SERVICES_HEALTHREPORT= diff --git a/application/xulrunner/examples/moz.build b/application/xulrunner/examples/moz.build new file mode 100644 index 000000000..a1782b42f --- /dev/null +++ b/application/xulrunner/examples/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['simple'] diff --git a/application/xulrunner/examples/simple/application.ini b/application/xulrunner/examples/simple/application.ini new file mode 100644 index 000000000..39c051422 --- /dev/null +++ b/application/xulrunner/examples/simple/application.ini @@ -0,0 +1,43 @@ +#filter substitution +[App] +; +; This field specifies your organization's name. This field is recommended, +; but optional. +Vendor=MozillaTest +; +; This field specifies your application's name. This field is required. +Name=Simple +; +; This field specifies your application's version. This field is required. +Version=0.1 +; +; This field specifies your application's build ID (timestamp). This field is +; required. +BuildID=20070625 +; +; This field specifies a compact copyright notice for your application. This +; field is optional. +Copyright=Copyright (c) 2004 Mozilla.org +; +; This ID is just an example. Every XUL app ought to have it's own unique ID. +; You can use the microsoft "guidgen" or "uuidgen" tools, or go on +; irc.mozilla.org and /msg botbot uuid. This field is optional. +ID={3aea3f07-ffe3-4060-bb03-bff3a5365e90} + +[Gecko] +; +; This field is required. It specifies the minimum Gecko version that this +; application requires. +MinVersion=@MOZILLA_VERSION_U@ +; +; This field is optional. It specifies the maximum Gecko version that this +; application requires. It should be specified if your application uses +; unfrozen interfaces. +MaxVersion=@MOZILLA_VERSION_U@ + +[Shell] +; +; This field specifies the location of your application's main icon with file +; extension excluded. NOTE: Unix style file separators are required. This +; field is optional. +Icon=chrome/icons/default/simple diff --git a/application/xulrunner/examples/simple/components/moz.build b/application/xulrunner/examples/simple/components/moz.build new file mode 100644 index 000000000..8ff468534 --- /dev/null +++ b/application/xulrunner/examples/simple/components/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['public', 'src'] diff --git a/application/xulrunner/examples/simple/components/public/moz.build b/application/xulrunner/examples/simple/components/public/moz.build new file mode 100644 index 000000000..3a611f85a --- /dev/null +++ b/application/xulrunner/examples/simple/components/public/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +XPIDL_SOURCES += [ + 'nsISimpleTest.idl', +] + +XPIDL_MODULE = 'simple' + +XPI_NAME = 'simple' diff --git a/application/xulrunner/examples/simple/components/public/nsISimpleTest.idl b/application/xulrunner/examples/simple/components/public/nsISimpleTest.idl new file mode 100644 index 000000000..99b9b86af --- /dev/null +++ b/application/xulrunner/examples/simple/components/public/nsISimpleTest.idl @@ -0,0 +1,15 @@ +/* vim:set ts=2 sw=2 sts=2 et cin: */ +/* 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/. */ + +#include "nsISupports.idl" + +[scriptable, uuid(f2f71d91-0451-47ec-aaa0-166663a7711a)] +interface nsISimpleTest : nsISupports +{ + /** + * This interface adds two numbers together and returns the result. + */ + long add(in long a, in long b); +}; diff --git a/application/xulrunner/examples/simple/components/src/SimpleTest.cpp b/application/xulrunner/examples/simple/components/src/SimpleTest.cpp new file mode 100644 index 000000000..06249abdd --- /dev/null +++ b/application/xulrunner/examples/simple/components/src/SimpleTest.cpp @@ -0,0 +1,54 @@ +/* vim:set ts=2 sw=2 sts=2 et cin: */ +/* 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/. */ + +#include <stdio.h> +#include "nsISimpleTest.h" +#include "mozilla/ModuleUtils.h" + +class SimpleTest : public nsISimpleTest +{ + ~SimpleTest() {} +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLETEST +}; + +NS_IMPL_ISUPPORTS(SimpleTest, nsISimpleTest) + +NS_IMETHODIMP +SimpleTest::Add(int32_t a, int32_t b, int32_t *r) +{ + printf("add(%d,%d) from C++\n", a, b); + + *r = a + b; + return NS_OK; +} + +NS_GENERIC_FACTORY_CONSTRUCTOR(SimpleTest) + +// 5e14b432-37b6-4377-923b-c987418d8429 +#define SIMPLETEST_CID \ + { 0x5e14b432, 0x37b6, 0x4377, \ + { 0x92, 0x3b, 0xc9, 0x87, 0x41, 0x8d, 0x84, 0x29 } } + +NS_DEFINE_NAMED_CID(SIMPLETEST_CID); + +static const mozilla::Module::CIDEntry kSimpleCIDs[] = { + { &kSIMPLETEST_CID, false, nullptr, SimpleTestConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kSimpleContracts[] = { + { "@test.mozilla.org/simple-test;1?impl=c++", &kSIMPLETEST_CID }, + { nullptr } +}; + +static const mozilla::Module kSimpleModule = { + mozilla::Module::kVersion, + kSimpleCIDs, + kSimpleContracts +}; + +NSMODULE_DEFN(SimpleTestModule) = &kSimpleModule; diff --git a/application/xulrunner/examples/simple/components/src/SimpleTest.js b/application/xulrunner/examples/simple/components/src/SimpleTest.js new file mode 100644 index 000000000..e6cf90660 --- /dev/null +++ b/application/xulrunner/examples/simple/components/src/SimpleTest.js @@ -0,0 +1,27 @@ +/* vim:set ts=2 sw=2 sts=2 et cin: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +function SimpleTest() { +} + +SimpleTest.prototype = { + classID: Components.ID("{4177e257-a0dc-49b9-a774-522a000a49fa}"), + + QueryInterface: function(iid) { + if (iid.equals(Components.interfaces.nsISimpleTest) || + iid.equals(Components.interfaces.nsISupports)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + add: function(a, b) { + dump("add(" + a + "," + b + ") from JS\n"); + return a + b; + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SimpleTest]); diff --git a/application/xulrunner/examples/simple/components/src/SimpleTest.manifest b/application/xulrunner/examples/simple/components/src/SimpleTest.manifest new file mode 100644 index 000000000..c7388b9d7 --- /dev/null +++ b/application/xulrunner/examples/simple/components/src/SimpleTest.manifest @@ -0,0 +1,2 @@ +component {4177e257-a0dc-49b9-a774-522a000a49fa} SimpleTest.js +contract @test.mozilla.org/simple-test;1?impl=js {4177e257-a0dc-49b9-a774-522a000a49fa} diff --git a/browser/extensions/aushelper/moz.build b/application/xulrunner/examples/simple/components/src/moz.build index a4ff06055..153bfdd0c 100644 --- a/browser/extensions/aushelper/moz.build +++ b/application/xulrunner/examples/simple/components/src/moz.build @@ -4,13 +4,18 @@ # 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/. -DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION'] - -FINAL_TARGET_FILES.features['aushelper@mozilla.org'] += [ - 'bootstrap.js' +SOURCES += [ + 'SimpleTest.cpp', ] -FINAL_TARGET_PP_FILES.features['aushelper@mozilla.org'] += [ - 'install.rdf.in' +XPCOMBinaryComponent('simpletest') + +EXTRA_COMPONENTS += [ + 'SimpleTest.js', + 'SimpleTest.manifest', ] + +XPI_NAME = 'simple' + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wshadow'] diff --git a/application/xulrunner/examples/simple/content/contents.rdf b/application/xulrunner/examples/simple/content/contents.rdf new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/application/xulrunner/examples/simple/content/contents.rdf diff --git a/application/xulrunner/examples/simple/content/simple.js b/application/xulrunner/examples/simple/content/simple.js new file mode 100644 index 000000000..acf6f1029 --- /dev/null +++ b/application/xulrunner/examples/simple/content/simple.js @@ -0,0 +1,17 @@ +/* vim:set ts=2 sw=2 sts=2 et cin: */ +/* 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/. */ + +function onButtonClick() { + var textbox = document.getElementById("textbox"); + + var contractid = (textbox.value % 2 == 0) ? + "@test.mozilla.org/simple-test;1?impl=js" : + "@test.mozilla.org/simple-test;1?impl=c++"; + + var test = Components.classes[contractid]. + createInstance(Components.interfaces.nsISimpleTest); + + textbox.value = test.add(textbox.value, 1); +} diff --git a/application/xulrunner/examples/simple/content/simple.xul b/application/xulrunner/examples/simple/content/simple.xul new file mode 100644 index 000000000..6ff915d0c --- /dev/null +++ b/application/xulrunner/examples/simple/content/simple.xul @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +# vim:set ts=8 sw=8 sts=8 noet: +# 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/. + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> + +<!DOCTYPE window SYSTEM "chrome://simple/locale/simple.dtd"> + +<window + id = "simple" + title = "&simple.title;" + xmlns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script src="chrome://simple/content/simple.js"/> + <vbox> + <textbox id="textbox" value="&simple.textValue;" flex="1"/> + <button id="button" label="&simple.buttonLabel;" oncommand="onButtonClick();"/> + </vbox> +</window> diff --git a/application/xulrunner/examples/simple/icons/simple.ico b/application/xulrunner/examples/simple/icons/simple.ico Binary files differnew file mode 100644 index 000000000..16bd7e9d1 --- /dev/null +++ b/application/xulrunner/examples/simple/icons/simple.ico diff --git a/application/xulrunner/examples/simple/jar.mn b/application/xulrunner/examples/simple/jar.mn new file mode 100644 index 000000000..7d141ad1d --- /dev/null +++ b/application/xulrunner/examples/simple/jar.mn @@ -0,0 +1,12 @@ +# 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/. + +simple.jar: +% content simple %content/ + content/simple.xul (content/simple.xul) + content/simple.js (content/simple.js) + +en-US.jar: +% locale simple en-US %locale/en-US/ + locale/en-US/simple.dtd (locale/simple.dtd) diff --git a/application/xulrunner/examples/simple/locale/simple.dtd b/application/xulrunner/examples/simple/locale/simple.dtd new file mode 100644 index 000000000..2fd1c9285 --- /dev/null +++ b/application/xulrunner/examples/simple/locale/simple.dtd @@ -0,0 +1,7 @@ +<!-- 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/. --> + +<!ENTITY simple.title "Simple App"> +<!ENTITY simple.textValue "0"> +<!ENTITY simple.buttonLabel "Increment"> diff --git a/application/xulrunner/examples/simple/moz.build b/application/xulrunner/examples/simple/moz.build new file mode 100644 index 000000000..c88c57a4b --- /dev/null +++ b/application/xulrunner/examples/simple/moz.build @@ -0,0 +1,22 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['components'] + +XPI_NAME = 'simple' + +JAR_MANIFESTS += ['jar.mn'] + +JS_PREFERENCE_FILES += [ + 'simple-prefs.js', +] + +FINAL_TARGET_PP_FILES += [ + 'application.ini', +] + +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + FINAL_TARGET_FILES.chrome.icons.default += ['icons/simple.ico'] diff --git a/browser/extensions/webcompat/bootstrap.js b/application/xulrunner/examples/simple/simple-prefs.js index 19141a0f5..fc92e0df5 100644 --- a/browser/extensions/webcompat/bootstrap.js +++ b/application/xulrunner/examples/simple/simple-prefs.js @@ -2,8 +2,5 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; -function startup() {} -function shutdown() {} -function install() {} -function uninstall() {} +pref("toolkit.defaultChromeURI", "chrome://simple/content/simple.xul"); +pref("general.useragent.extra.simple", "SimpleApp/0.1"); diff --git a/application/xulrunner/installer/Makefile.in b/application/xulrunner/installer/Makefile.in new file mode 100644 index 000000000..04803dddb --- /dev/null +++ b/application/xulrunner/installer/Makefile.in @@ -0,0 +1,148 @@ +# 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/. + +STANDALONE_MAKEFILE := 1 + +NO_PKG_FILES = \ + xulrunner-config \ + regchrome* \ + regxpcom* \ + $(NULL) + +# We want xpcshell, run-mozilla and install_app.py in the SDK but not in the binary package. +ifndef STAGE_SDK +NO_PKG_FILES += \ + xpcshell* \ + run-mozilla* \ + install_app.py \ + $(NULL) +endif + +# If we're on mac, we don't want an end-user-facing DMG, we want a .tar.bz2 +# which developers then use to package their application. + +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) +MOZ_PKG_FORMAT = BZ2 +_APPNAME = XUL.framework +_BINPATH = /$(_APPNAME)/Versions/Current +_RESPATH := $(_BINPATH) +endif + +include $(topsrcdir)/config/rules.mk + +INSTALL_SDK = 1 + +include $(topsrcdir)/toolkit/mozapps/installer/signing.mk +include $(topsrcdir)/toolkit/mozapps/installer/packager.mk + +# Add pkg-config files to the install:: target + +pkg_config_files = \ + libxul.pc \ + libxul-embedding.pc \ + mozilla-js.pc \ + mozilla-plugin.pc \ + $(NULL) + +ifdef MOZ_NATIVE_NSPR +NSPR_NAME=nspr +NSPR_VERSION=$(shell $(NSPR_CONFIG) --version) +else +pkg_config_files += mozilla-nspr.pc +NSPR_NAME=mozilla-nspr +FULL_NSPR_CFLAGS=-I\$${includedir} +FULL_NSPR_LIBS=$(subst $(prefix),\$${sdkdir},$(shell $(DEPTH)/nsprpub/config/nspr-config --libs)) +NSPR_VERSION=$(shell $(DEPTH)/nsprpub/config/nspr-config --version) +endif + +MOZ_XUL_LINK = -lxpcomglue_s -lxul +ifdef JS_SHARED_LIBRARY +MOZ_JS_LINK = -lmozjs +else +MOZ_JS_LINK = $(MOZ_XUL_LINK) +endif + +$(warning FULL_NSPR_CFLAGS=$(FULL_NSPR_CFLAGS)) + +ifndef MOZ_NATIVE_NSS +pkg_config_files += mozilla-nss.pc +endif + +%.pc: $(srcdir)/%.pc.in $(GLOBAL_DEPS) + cat $< | sed \ + -e "s|%prefix%|$(prefix)|" \ + -e "s|%includedir%|$(includedir)|" \ + -e "s|%idldir%|$(idldir)|" \ + -e "s|%sdkdir%|$(sdkdir)|" \ + -e "s|%MOZ_APP_NAME%|$(MOZ_APP_NAME)|" \ + -e "s|%MOZILLA_VERSION%|$(MOZ_APP_VERSION)|" \ + -e "s|%WCHAR_CFLAGS%|$(WCHAR_CFLAGS)|" \ + -e "s|%FULL_NSPR_LIBS%|$(FULL_NSPR_LIBS)|" \ + -e "s|%FULL_NSPR_CFLAGS%|$(FULL_NSPR_CFLAGS)|" \ + -e "s|%NSPR_NAME%|$(NSPR_NAME)|" \ + -e "s|%NSPR_VERSION%|$(NSPR_VERSION)|" \ + -e "s|%MOZ_XUL_LINK%|$(MOZ_XUL_LINK)|" \ + -e "s|%MOZ_JS_LINK%|$(MOZ_JS_LINK)|" > $@ + chmod 644 $@ + +install:: $(pkg_config_files) + @echo pkg_config_file: $(pkg_config_files) + $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(libdir)/pkgconfig + +GARBAGE += $(pkg_config_files) + +GARBAGE += debian/changelog + +DEBDESTDIR=debian/$(MOZ_BUILD_APP) + +GRE_BUILDID = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(DIST)/bin/platform.ini Build BuildID) +MOZ_DEB_TIMESTAMP = "$(shell date +"%a, %d %b %Y %T %z" )" + +DEFINES += \ + -DGRE_MILESTONE=$(GRE_MILESTONE) \ + -DGRE_BUILDID=$(GRE_BUILDID) \ + -DMOZ_DEB_TIMESTAMP=$(MOZ_DEB_TIMESTAMP) \ + -DMOZ_APP_NAME=$(MOZ_APP_NAME) \ + -Dinstalldir=$(installdir) \ + $(NULL) + +ifeq ($(OS_TARGET),Linux) +debian/changelog: $(srcdir)/debian/changelog.in $(DIST)/bin/platform.ini + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) + +debian/xulrunner.links: $(srcdir)/debian/xulrunner.links.in + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) + +debian/xulrunner.service: $(srcdir)/debian/xulrunner.service.in + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) + +debian/prerm: $(srcdir)/debian/prerm.in + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) + +debian/postinst: $(srcdir)/debian/postinst.in + $(call py_action,preprocessor, \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ -o $@) + +package: + $(MAKE) package -C $(DEPTH) + +deb: package debian/changelog debian/xulrunner.service debian/xulrunner.links + $(NSINSTALL) $(topsrcdir)/$(MOZ_BUILD_APP)/installer/debian . + rm -fr $(DEBDESTDIR) + $(NSINSTALL) -D $(DEBDESTDIR)/$(installdir) + cp -pRL $(DEPTH)/dist/$(MOZ_BUILD_APP)/* $(DEBDESTDIR)/$(installdir) + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/dbus-1/services/ + cp debian/$(MOZ_BUILD_APP).service $(DEBDESTDIR)/usr/share/dbus-1/services/org.mozilla.$(MOZ_BUILD_APP).service + dh_link; fakeroot dh_fixperms; fakeroot dh_installdeb; fakeroot dh_shlibdeps; fakeroot dh_gencontrol; fakeroot dh_md5sums; fakeroot dh_builddeb; +endif + +DEB_BUILD_ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH) +# package name comes from xulrunner/installer/debian/changelog.in +DEB_PKG_NAME = $(MOZ_PKG_APPNAME)_$(GRE_MILESTONE)-$(GRE_BUILDID)_$(DEB_BUILD_ARCH).deb +# relative to $(DIST) +UPLOAD_EXTRA_FILES += ../xulrunner/$(DEB_PKG_NAME) diff --git a/application/xulrunner/installer/debian/changelog.in b/application/xulrunner/installer/debian/changelog.in new file mode 100644 index 000000000..1efd55a1d --- /dev/null +++ b/application/xulrunner/installer/debian/changelog.in @@ -0,0 +1,7 @@ +# if the naming changes please modify DEB_PKG_NAME in xulrunner/installer/Makefile.in as well +#filter substitution +xulrunner (@GRE_MILESTONE@-@GRE_BUILDID@) unstable; urgency=low + + * Mozilla Nightly (Closes: #nnnn) <nnnn is the bug number of your ITP> + + -- Mozilla Runtime <mobile-feedback@mozilla.com> @MOZ_DEB_TIMESTAMP@ diff --git a/application/xulrunner/installer/debian/compat b/application/xulrunner/installer/debian/compat new file mode 100644 index 000000000..b8626c4cf --- /dev/null +++ b/application/xulrunner/installer/debian/compat @@ -0,0 +1 @@ +4 diff --git a/application/xulrunner/installer/debian/control b/application/xulrunner/installer/debian/control new file mode 100644 index 000000000..da99aa8d4 --- /dev/null +++ b/application/xulrunner/installer/debian/control @@ -0,0 +1,48 @@ +Source: xulrunner +Section: user/network +Priority: extra +Maintainer: Mobile Feedback <mobile-feedback@mozilla.com> +Build-Depends: debhelper (>= 5) +Standards-Version: 3.7.2 + +Package: xulrunner +Architecture: any +Depends: ${shlibs:Depends} +Description: Web and JavaScript engine used by the Firefox Web browser + The Mozilla runtime is the modern browser engine, also known as "Gecko," that powers Firefox and can be embedded by other applications +XB-Maemo-Display-Name: Mozilla Runtime +XB-Maemo-Icon-26: + MB5!.1PT*&@H````-24A$4@```!H````:"`8```"I2DS.````"7!(67,```L3 + M```+$P$`FIP8```%;$E$051(B:667XQ4U1W'/_>>>V?NG=F9V3^S_W%9<'#! + M/Q1;NQ:EQH@:T2"EH>&A34R;]$U?Q%9-VH:41BUJFV"-B<8'^Z!-VP=E?37& + M5=18L"SACVMVH<M.9W>8V9G9N7-G[O_3AP6$LD"$;W*3<T_R^W[.]Y=S3@Z< + ME90H_)\DE\Y=J]3SHW_\1)6O#FV2NVD'D*\,W<T;JWK.0W>3OA[012N68]LW + MD1W^!8?W_XGANQ^C5?V$(V/_8L.VGU.:.JG\\M@[UPK2SD/V#=U,K=QDW;TF + M#S_[&HZC4,^O9_T6'84VWO[PI]>32/MFV.URZ^;G273UT7^7`3&)#%*!TM"U + MS]ZHTC?\B/SUD7\J>\E?,TC^'4%LA4?DS\O^V]<H<L!I.6`:,5S[:#B^T)?1 + M\MJZ>]YF8:GLB3@/WIQ!,U1F9AH<V]VX&DB1N]'HS6WFN]L>8>"V`6(=O;)S + M8]O<?"!E%/+ZFZ_R_'-[U;4CZTX6NA_8;VZX_X>IWO3W4\,]W;II4CE3MZJS + M9R9JIPICSOBQ,4Z_4+U<HH@H?H"W7CY`@,&NEUY1>M;?GFBC^=2NWR-434HU + M;OY@\]:'8OTW;3]N&@RM74ER1195Z!0S1E^QS5B3CZL[BHJ<L$_L^1T'?[O_ + MDD07_LCQQW]$;M-3M&JEL8EJ[M$?/QN"2*OI[-"JW(AX[&<[J:174NK(D<T- + M(F*"N>EYBJ<7*)VI4%EHL'!ZWG7R\[_AT)Z7+O06YR%_&>PBU;V#RLE]%/]S + M5/A6YK7WIP+1WCLJA"Z:C44*E1H=]SZ*TMF-D=31@?J9&E:Q@EVW<2IUM$Q" + M\U8/W1>MW9)GXMW#Y_R_.;!6(^+SO[VH;/[K%XN'QJ>/C7VR+]CVAY1^XRVJ + M%A?(9`IO=`MS'8-XAH[M!5B-%JUZ`]_U20UT0;-%Z_@I8J&OJ<.]S['QF=RR + MK;M(]^S=R<8-[PA148S\89*WW$GVUN^1T049324I)-;D?VG,E:F7+%+?N9'% + M:I7J=!&W+TLSE<;Y^."?>>^))R].=+%4#+&3,%1"LX?6Z`[\U`W87\]0*Y2H + MN1YU)\0UX]A^2*0+HJ2!.;*2MM4K$%T91,M%B2>VPM;LN5VWC+9T0>P.K!;, + M%8AL"RN10$G$"7K:(1G#C1N8G2F2=XP02/!5B=-R\<(63!>1PH!(K"*W)L<4 + MY>5!;4X/]<5V)AM0KX(J"!(F]722T/.(!KHQLYTT58FN0A!&1&Z(W_+P\B6\ + M`U_BZW%D6U805FX`/E\>%/D&MB/(SX,:@6&"ZQ`T&MC51?SV#*X21Q,0DZ`& + M+J$?X9>K^">F""HE@DH-?!>D;5R^=:%E4;-<'#N!],#WH!D#31`,KB!038)\ + M$5W5<%4)00"A@CST;[P3D_BVA73J$'J`6[\\R)THXVS,T[ZJ`]\#Q8;:/&@Z + M%(`C<;QL%X$O(!T#1<!"!8X>)5I<`,^&R`.$!<Q<83-0I5[X"*7S-M(IJ!6@ + M50-A@&-#N0"#JXFZ^J&B@YF&\@($$AP+\``)A!,P>Q(NN!DN;9_2Q._8CB\, + M(@]:<Q#Y$#H0^-!8A,(T%&?`5T#)0*B"-7T6I$CP_PBS!ZX,HEP@3/3C)D:) + MXA"5(*Q!%"Y]01-D"%*'P`17!3L`KP'2!J(/8'8/>,VK@(A@]CBH:PGM'+)\ + M=EH#G*55JQF(C8"O@]T`IP&1!()).+4+ZE^=,[L2"&`1YKZ$L!=J-X&B0AIH + M`C;(&O@.!&6(3H.<!N8_A9E?06W\*M[+:A!23T/J('2UH$TNG2!#0DI".H#, + M)&1>!-8M9_!MWFTQB*V&Q"AX(V`,@-3`*X*<`O\@^">6HEX?Z$*90/QLO<]2 + :+Z,K%?P/&D=O=_6]@+\`````245.1*Y"8((` + ` diff --git a/application/xulrunner/installer/debian/icon_base64 b/application/xulrunner/installer/debian/icon_base64 new file mode 100644 index 000000000..124fb4ccc --- /dev/null +++ b/application/xulrunner/installer/debian/icon_base64 @@ -0,0 +1,36 @@ +begin 644 -m +MB5!.1PT*&@H````-24A$4@```!H````:"`8```"I2DS.````"7!(67,```L3 +M```+$P$`FIP8```%;$E$051(B:667XQ4U1W'/_>>>V?NG=F9V3^S_W%9<'#! +M/Q1;NQ:EQH@:T2"EH>&A34R;]$U?Q%9-VH:41BUJFV"-B<8'^Z!-VP=E?37& +M5=18L"SACVMVH<M.9W>8V9G9N7-G[O_3AP6$LD"$;W*3<T_R^W[.]Y=S3@Z< +ME90H_)\DE\Y=J]3SHW_\1)6O#FV2NVD'D*\,W<T;JWK.0W>3OA[012N68]LW +MD1W^!8?W_XGANQ^C5?V$(V/_8L.VGU.:.JG\\M@[UPK2SD/V#=U,K=QDW;TF +M#S_[&HZC4,^O9_T6'84VWO[PI]>32/MFV.URZ^;G273UT7^7`3&)#%*!TM"U +MS]ZHTC?\B/SUD7\J>\E?,TC^'4%LA4?DS\O^V]<H<L!I.6`:,5S[:#B^T)?1 +M\MJZ>]YF8:GLB3@/WIQ!,U1F9AH<V]VX&DB1N]'HS6WFN]L>8>"V`6(=O;)S +M8]O<?"!E%/+ZFZ_R_'-[U;4CZTX6NA_8;VZX_X>IWO3W4\,]W;II4CE3MZJS +M9R9JIPICSOBQ,4Z_4+U<HH@H?H"W7CY`@,&NEUY1>M;?GFBC^=2NWR-434HU +M;OY@\]:'8OTW;3]N&@RM74ER1195Z!0S1E^QS5B3CZL[BHJ<L$_L^1T'?[O_ +MDD07_LCQQW]$;M-3M&JEL8EJ[M$?/QN"2*OI[-"JW(AX[&<[J:174NK(D<T- +M(F*"N>EYBJ<7*)VI4%EHL'!ZWG7R\[_AT)Z7+O06YR%_&>PBU;V#RLE]%/]S +M5/A6YK7WIP+1WCLJA"Z:C44*E1H=]SZ*TMF-D=31@?J9&E:Q@EVW<2IUM$Q" +M\U8/W1>MW9)GXMW#Y_R_.;!6(^+SO[VH;/[K%XN'QJ>/C7VR+]CVAY1^XRVJ +M%A?(9`IO=`MS'8-XAH[M!5B-%JUZ`]_U20UT0;-%Z_@I8J&OJ<.]S['QF=RR +MK;M(]^S=R<8-[PA148S\89*WW$GVUN^1T049324I)-;D?VG,E:F7+%+?N9'% +M:I7J=!&W+TLSE<;Y^."?>>^))R].=+%4#+&3,%1"LX?6Z`[\U`W87\]0*Y2H +MN1YU)\0UX]A^2*0+HJ2!.;*2MM4K$%T91,M%B2>VPM;LN5VWC+9T0>P.K!;, +M%8AL"RN10$G$"7K:(1G#C1N8G2F2=XP02/!5B=-R\<(63!>1PH!(K"*W)L<4 +MY>5!;4X/]<5V)AM0KX(J"!(F]722T/.(!KHQLYTT58FN0A!&1&Z(W_+P\B6\ +M`U_BZW%D6U805FX`/E\>%/D&MB/(SX,:@6&"ZQ`T&MC51?SV#*X21Q,0DZ`& +M+J$?X9>K^">F""HE@DH-?!>D;5R^=:%E4;-<'#N!],#WH!D#31`,KB!038)\ +M$5W5<%4)00"A@CST;[P3D_BVA73J$'J`6[\\R)THXVS,T[ZJ`]\#Q8;:/&@Z +M%(`C<;QL%X$O(!T#1<!"!8X>)5I<`,^&R`.$!<Q<83-0I5[X"*7S-M(IJ!6@ +M50-A@&-#N0"#JXFZ^J&B@YF&\@($$AP+\``)A!,P>Q(NN!DN;9_2Q._8CB\, +M(@]:<Q#Y$#H0^-!8A,(T%&?`5T#)0*B"-7T6I$CP_PBS!ZX,HEP@3/3C)D:) +MXA"5(*Q!%"Y]01-D"%*'P`17!3L`KP'2!J(/8'8/>,VK@(A@]CBH:PGM'+)\ +M=EH#G*55JQF(C8"O@]T`IP&1!()).+4+ZE^=,[L2"&`1YKZ$L!=J-X&B0AIH +M`C;(&O@.!&6(3H.<!N8_A9E?06W\*M[+:A!23T/J('2UH$TNG2!#0DI".H#, +M)&1>!-8M9_!MWFTQB*V&Q"AX(V`,@-3`*X*<`O\@^">6HEX?Z$*90/QLO<]2 +:+Z,K%?P/&D=O=_6]@+\`````245.1*Y"8((` +` +end diff --git a/application/xulrunner/installer/debian/menu b/application/xulrunner/installer/debian/menu new file mode 100644 index 000000000..e1ce52201 --- /dev/null +++ b/application/xulrunner/installer/debian/menu @@ -0,0 +1,2 @@ +?package(xulrunner):needs="X11|text|vc|wm" section="Apps/Internet"\ + title="xulrunner" command="/usr/bin/xulrunner" diff --git a/application/xulrunner/installer/debian/postinst.in b/application/xulrunner/installer/debian/postinst.in new file mode 100644 index 000000000..0f06640e2 --- /dev/null +++ b/application/xulrunner/installer/debian/postinst.in @@ -0,0 +1,42 @@ +#literal #! /bin/sh +#filter substitution +# postinst script for moz +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * <postinst> `configure' <most-recently-configured-version> +# * <old-postinst> `abort-upgrade' <new version> +# * <conflictor's-postinst> `abort-remove' `in-favour' <package> +# <new-version> +# * <postinst> `abort-remove' +# * <deconfigured's-postinst> `abort-deconfigure' `in-favour' +# <failed-install-package> <version> `removing' +# <conflicting-package> <version> +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#ifdef MOZ_WIDGET_GTK +gtk-update-icon-cache /usr/share/icons/hicolor +#endif + + +exit 0 + + diff --git a/application/xulrunner/installer/debian/prerm.in b/application/xulrunner/installer/debian/prerm.in new file mode 100644 index 000000000..1d46d382c --- /dev/null +++ b/application/xulrunner/installer/debian/prerm.in @@ -0,0 +1,29 @@ +#literal #! /bin/sh +#filter substitution +# prerm script for moz +# +# see: dh_installdeb(1) + +set -e + +case "$1" in + remove|upgrade|deconfigure) + ;; + + failed-upgrade) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#ifdef MOZ_WIDGET_GTK +gtk-update-icon-cache /usr/share/icons/hicolor +#endif + + +exit 0 + + diff --git a/application/xulrunner/installer/debian/xulrunner.links.in b/application/xulrunner/installer/debian/xulrunner.links.in new file mode 100644 index 000000000..eabac6f51 --- /dev/null +++ b/application/xulrunner/installer/debian/xulrunner.links.in @@ -0,0 +1,2 @@ +#filter substitution +@installdir@/xulrunner /usr/bin/xulrunner diff --git a/application/xulrunner/installer/debian/xulrunner.service.in b/application/xulrunner/installer/debian/xulrunner.service.in new file mode 100644 index 000000000..48d87a1b9 --- /dev/null +++ b/application/xulrunner/installer/debian/xulrunner.service.in @@ -0,0 +1,4 @@ +#filter substitution +[D-BUS Service] +Name=org.mozilla.@MOZ_APP_NAME@ +Exec=@installdir@/xulrunner diff --git a/application/xulrunner/installer/libxul-embedding.pc.in b/application/xulrunner/installer/libxul-embedding.pc.in new file mode 100644 index 000000000..100e0a763 --- /dev/null +++ b/application/xulrunner/installer/libxul-embedding.pc.in @@ -0,0 +1,10 @@ +prefix=%prefix% +sdkdir=%sdkdir% +includedir=%includedir% +idldir=%idldir% + +Name: libxul-embedding +Description: Static library for version-independent embedding of the Mozilla runtime +Version: %MOZILLA_VERSION% +Libs: -L${sdkdir}/lib -lxpcomglue -ldl +Cflags: -DXPCOM_GLUE -I${includedir} %WCHAR_CFLAGS% diff --git a/application/xulrunner/installer/libxul.pc.in b/application/xulrunner/installer/libxul.pc.in new file mode 100644 index 000000000..ccce9aa59 --- /dev/null +++ b/application/xulrunner/installer/libxul.pc.in @@ -0,0 +1,11 @@ +prefix=%prefix% +sdkdir=%sdkdir% +includedir=%includedir% +idldir=%idldir% + +Name: libxul +Description: The Mozilla Runtime and Embedding Engine +Version: %MOZILLA_VERSION% +Requires: %NSPR_NAME% >= %NSPR_VERSION% +Libs: -L${sdkdir}/lib %MOZ_XUL_LINK% +Cflags: -I${includedir} %WCHAR_CFLAGS% diff --git a/application/xulrunner/installer/moz.build b/application/xulrunner/installer/moz.build new file mode 100644 index 000000000..895d11993 --- /dev/null +++ b/application/xulrunner/installer/moz.build @@ -0,0 +1,6 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + diff --git a/application/xulrunner/installer/mozilla-js.pc.in b/application/xulrunner/installer/mozilla-js.pc.in new file mode 100644 index 000000000..55e84ca00 --- /dev/null +++ b/application/xulrunner/installer/mozilla-js.pc.in @@ -0,0 +1,10 @@ +prefix=%prefix% +sdkdir=%sdkdir% +includedir=%includedir% + +Name: JavaScript +Description: The Mozilla JavaScript Library +Version: %MOZILLA_VERSION% +Requires: %NSPR_NAME% >= %NSPR_VERSION% +Libs: -L${sdkdir}/lib %MOZ_JS_LINK% +Cflags: -I${includedir} -DXP_UNIX diff --git a/application/xulrunner/installer/mozilla-nspr.pc.in b/application/xulrunner/installer/mozilla-nspr.pc.in new file mode 100644 index 000000000..7ebd3421c --- /dev/null +++ b/application/xulrunner/installer/mozilla-nspr.pc.in @@ -0,0 +1,11 @@ +prefix=%prefix% +sdkdir=%sdkdir% +includedir=%includedir%/nspr + +Name: NSPR +Description: The Netscape Portable Runtime +Version: %NSPR_VERSION% +Libs: %FULL_NSPR_LIBS% +Cflags: %FULL_NSPR_CFLAGS% + + diff --git a/application/xulrunner/installer/mozilla-nss.pc.in b/application/xulrunner/installer/mozilla-nss.pc.in new file mode 100644 index 000000000..90f14c3ae --- /dev/null +++ b/application/xulrunner/installer/mozilla-nss.pc.in @@ -0,0 +1,10 @@ +prefix=%prefix% +sdkdir=%sdkdir% +includedir=%includedir%/nss + +Name: NSS +Description: Mozilla Network Security Services +Version: %MOZILLA_VERSION% +Requires: %NSPR_NAME% >= %NSPR_VERSION% +Libs: -L${sdkdir}/lib -lsmime3 -lssl3 -lnss3 -lnssutil3 +Cflags: -I${includedir} diff --git a/application/xulrunner/installer/mozilla-plugin.pc.in b/application/xulrunner/installer/mozilla-plugin.pc.in new file mode 100644 index 000000000..7080161b3 --- /dev/null +++ b/application/xulrunner/installer/mozilla-plugin.pc.in @@ -0,0 +1,8 @@ +prefix=%prefix% +sdkdir=%sdkdir% +includedir=%includedir% + +Name: Mozilla Plug-In API +Description: Mozilla Plug-In API +Version: %MOZILLA_VERSION% +Cflags: -I${includedir} -DXP_UNIX diff --git a/application/xulrunner/locales/all-locales b/application/xulrunner/locales/all-locales new file mode 100644 index 000000000..85ef789a6 --- /dev/null +++ b/application/xulrunner/locales/all-locales @@ -0,0 +1,39 @@ +ar +bg +ca +cs +da +de +el +en-GB +es-AR +es-ES +eu +fi +fr +ga-IE +gu-IN +he +hu +hy-AM +it +ja +ja-JP-mac +ko +nb-NO +nl +nn-NO +mk +mn +pa-IN +pl +pt-BR +ro +ru +sk +sl +sq +sv-SE +tr +zh-CN +zh-TW diff --git a/application/xulrunner/moz.build b/application/xulrunner/moz.build new file mode 100644 index 000000000..371f69f5e --- /dev/null +++ b/application/xulrunner/moz.build @@ -0,0 +1,11 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +CONFIGURE_SUBST_FILES += ['installer/Makefile'] + +DIRS += [ + 'app', +] diff --git a/browser/extensions/pocket/locale/moz.build b/application/xulrunner/moz.configure index aac3a838c..72236254f 100644 --- a/browser/extensions/pocket/locale/moz.build +++ b/application/xulrunner/moz.configure @@ -4,4 +4,4 @@ # 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/. -JAR_MANIFESTS += ['jar.mn'] +include('../../toolkit/moz.configure') diff --git a/application/xulrunner/stub/Makefile.in b/application/xulrunner/stub/Makefile.in new file mode 100644 index 000000000..0fa0cccf6 --- /dev/null +++ b/application/xulrunner/stub/Makefile.in @@ -0,0 +1,11 @@ +# 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/. + +ifndef MOZ_WINCONSOLE +ifdef MOZ_DEBUG +MOZ_WINCONSOLE = 1 +else +MOZ_WINCONSOLE = 0 +endif +endif diff --git a/application/xulrunner/stub/moz.build b/application/xulrunner/stub/moz.build new file mode 100644 index 000000000..4fd172f72 --- /dev/null +++ b/application/xulrunner/stub/moz.build @@ -0,0 +1,51 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# The value of XULRUNNER_STUB_NAME is generated by configure to allow XULRunner +# apps to override it using the --with-xulrunner-stub-name=<appname> argument. +# If this configure argument is not present then the default name is +# 'xulrunner-stub'. + +# We don't want to create a dependency on mozglue. +# Statically link against the RTL on windows +GeckoProgram(CONFIG['XULRUNNER_STUB_NAME'], mozglue=None, msvcrt='static') + +SOURCES += [ + 'nsXULStub.cpp', +] + +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + FINAL_TARGET = 'dist/XUL.framework/Versions/%(MOZILLA_VERSION)s' % CONFIG + +DEFINES['XPCOM_GLUE'] = True + +LOCAL_INCLUDES += [ + '/xpcom/base', + '/xpcom/build', +] + +if CONFIG['OS_ARCH'] == 'WINNT': + LOCAL_INCLUDES += ['/toolkit/xre'] + # this is an awful workaround - glandium + USE_LIBS += ['mfbt_staticruntime'] + +if CONFIG['_MSC_VER']: + WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup'] + +if CONFIG['OS_ARCH'] == 'WINNT': + DEFINES['MOZ_XULRUNNER'] = True + RCINCLUDE = 'xulrunner-stub.rc' + +if CONFIG['OS_ARCH'] == 'WINNT': + OS_LIBS += [ + 'shell32', + ] + +DISABLE_STL_WRAPPING = True + +# Need to link with CoreFoundation on Mac +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + OS_LIBS += CONFIG['TK_LIBS'] diff --git a/application/xulrunner/stub/nsXULStub.cpp b/application/xulrunner/stub/nsXULStub.cpp new file mode 100644 index 000000000..8638ae43e --- /dev/null +++ b/application/xulrunner/stub/nsXULStub.cpp @@ -0,0 +1,445 @@ +/* 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/. */ + +#include "nsXPCOMGlue.h" +#include "nsINIParser.h" +#include "nsXPCOMPrivate.h" // for XP MAXPATHLEN +#include "nsXULAppAPI.h" +#include "nsIFile.h" + +#include <stdarg.h> + +#ifdef XP_WIN +#include <windows.h> +#include <io.h> +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif +#define strcasecmp _stricmp +#define PATH_SEPARATOR_CHAR '\\' +#define R_OK 04 +#elif defined(XP_MACOSX) +#include <unistd.h> +#include <sys/stat.h> +#include <CoreFoundation/CoreFoundation.h> +#define PATH_SEPARATOR_CHAR '/' +#else +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#define PATH_SEPARATOR_CHAR '/' +#endif + +#ifdef XP_WIN +#define XRE_DONT_PROTECT_DLL_LOAD +#include "nsWindowsWMain.cpp" +#endif + +#define VERSION_MAXLEN 128 + +static void Output(bool isError, const char *fmt, ... ) +{ + va_list ap; + va_start(ap, fmt); + +#if (defined(XP_WIN) && !MOZ_WINCONSOLE) + char msg[2048]; + + vsnprintf(msg, sizeof(msg), fmt, ap); + + UINT flags = MB_OK; + if (isError) + flags |= MB_ICONERROR; + else + flags |= MB_ICONINFORMATION; + + wchar_t wide_msg[1024]; + MultiByteToWideChar(CP_ACP, + 0, + msg, + -1, + wide_msg, + sizeof(wide_msg) / sizeof(wchar_t)); + + MessageBoxW(nullptr, wide_msg, L"XULRunner", flags); +#else + vfprintf(stderr, fmt, ap); +#endif + + va_end(ap); +} + +/** + * Return true if |arg| matches the given argument name. + */ +static bool IsArg(const char* arg, const char* s) +{ + if (*arg == '-') + { + if (*++arg == '-') + ++arg; + return !strcasecmp(arg, s); + } + +#if defined(XP_WIN) + if (*arg == '/') + return !strcasecmp(++arg, s); +#endif + + return false; +} + +/** + * Return true if |aDir| is a valid file/directory. + */ +static bool FolderExists(const char* aDir) +{ +#ifdef XP_WIN + wchar_t wideDir[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, aDir, -1, wideDir, MAX_PATH); + DWORD fileAttrs = GetFileAttributesW(wideDir); + return fileAttrs != INVALID_FILE_ATTRIBUTES; +#else + return access(aDir, R_OK) == 0; +#endif +} + +static nsresult GetRealPath(const char* appDataFile, char* *aResult) +{ +#ifdef XP_WIN + wchar_t wAppDataFile[MAX_PATH]; + wchar_t wIniPath[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, appDataFile, -1, wAppDataFile, MAX_PATH); + _wfullpath(wIniPath, wAppDataFile, MAX_PATH); + WideCharToMultiByte(CP_UTF8, 0, wIniPath, -1, *aResult, MAX_PATH, 0, 0); +#else + struct stat fileStat; + if (!realpath(appDataFile, *aResult) || stat(*aResult, &fileStat)) + return NS_ERROR_FAILURE; +#endif + if (!*aResult || !**aResult) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +class AutoAppData +{ +public: + AutoAppData(nsIFile* aINIFile) : mAppData(nullptr) { + nsresult rv = XRE_CreateAppData(aINIFile, &mAppData); + if (NS_FAILED(rv)) + mAppData = nullptr; + } + ~AutoAppData() { + if (mAppData) + XRE_FreeAppData(mAppData); + } + + operator nsXREAppData*() const { return mAppData; } + nsXREAppData* operator -> () const { return mAppData; } + +private: + nsXREAppData* mAppData; +}; + +XRE_CreateAppDataType XRE_CreateAppData; +XRE_FreeAppDataType XRE_FreeAppData; +XRE_mainType XRE_main; + +int +main(int argc, char **argv) +{ + nsresult rv; + char *lastSlash; + + char iniPath[MAXPATHLEN]; + char tmpPath[MAXPATHLEN]; + char greDir[MAXPATHLEN]; + bool greFound = false; + +#if defined(XP_MACOSX) + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (!appBundle) + return 1; + + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(appBundle); + if (!resourcesURL) + return 1; + + CFURLRef absResourcesURL = CFURLCopyAbsoluteURL(resourcesURL); + CFRelease(resourcesURL); + if (!absResourcesURL) + return 1; + + CFURLRef iniFileURL = + CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, + absResourcesURL, + CFSTR("application.ini"), + false); + CFRelease(absResourcesURL); + if (!iniFileURL) + return 1; + + CFStringRef iniPathStr = + CFURLCopyFileSystemPath(iniFileURL, kCFURLPOSIXPathStyle); + CFRelease(iniFileURL); + if (!iniPathStr) + return 1; + + CFStringGetCString(iniPathStr, iniPath, sizeof(iniPath), + kCFStringEncodingUTF8); + CFRelease(iniPathStr); + +#else + +#ifdef XP_WIN + wchar_t wide_path[MAX_PATH]; + if (!::GetModuleFileNameW(nullptr, wide_path, MAX_PATH)) + return 1; + + WideCharToMultiByte(CP_UTF8, 0, wide_path,-1, + iniPath, MAX_PATH, nullptr, nullptr); + +#else + // on unix, there is no official way to get the path of the current binary. + // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to + // multiple applications, we will try a series of techniques: + // + // 1) use realpath() on argv[0], which works unless we're loaded from the + // PATH + // 2) manually walk through the PATH and look for ourself + // 3) give up + + struct stat fileStat; + strncpy(tmpPath, argv[0], sizeof(tmpPath)); + lastSlash = strrchr(tmpPath, '/'); + if (lastSlash) { + *lastSlash = 0; + realpath(tmpPath, iniPath); + } else { + const char *path = getenv("PATH"); + if (!path) + return 1; + + char *pathdup = strdup(path); + if (!pathdup) + return 1; + + bool found = false; + char *token = strtok(pathdup, ":"); + while (token) { + sprintf(tmpPath, "%s/%s", token, argv[0]); + if (stat(tmpPath, &fileStat) == 0) { + found = true; + lastSlash = strrchr(tmpPath, '/'); + *lastSlash = 0; + realpath(tmpPath, iniPath); + break; + } + token = strtok(nullptr, ":"); + } + free (pathdup); + if (!found) + return 1; + } + lastSlash = iniPath + strlen(iniPath); + *lastSlash = '/'; +#endif + +#ifndef XP_UNIX + lastSlash = strrchr(iniPath, PATH_SEPARATOR_CHAR); + if (!lastSlash) + return 1; +#endif + + *(++lastSlash) = '\0'; + + // On Linux/Win, look for XULRunner in appdir/xulrunner + + snprintf(greDir, sizeof(greDir), + "%sxulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, + iniPath); + + greFound = FolderExists(greDir); + +#ifdef XP_UNIX + if (greFound) { + char resolved_greDir[MAXPATHLEN] = ""; + if (realpath(greDir, resolved_greDir) && *resolved_greDir) { + strncpy(greDir, resolved_greDir, MAXPATHLEN); + } + } +#endif + + strncpy(lastSlash, "application.ini", sizeof(iniPath) - (lastSlash - iniPath)); + +#endif + + // If -app parameter was passed in, it is now time to take it under + // consideration. + const char *appDataFile; + appDataFile = getenv("XUL_APP_FILE"); + if (!appDataFile || !*appDataFile) + if (argc > 1 && IsArg(argv[1], "app")) { + if (argc == 2) { + Output(false, "specify APP-FILE (optional)\n"); + return 1; + } + argv[1] = argv[0]; + ++argv; + --argc; + + appDataFile = argv[1]; + argv[1] = argv[0]; + ++argv; + --argc; + + char kAppEnv[MAXPATHLEN]; + snprintf(kAppEnv, MAXPATHLEN, "XUL_APP_FILE=%s", appDataFile); + if (putenv(kAppEnv)) + Output(false, "Couldn't set %s.\n", kAppEnv); + + char *result = (char*) calloc(sizeof(char), MAXPATHLEN); + if (NS_FAILED(GetRealPath(appDataFile, &result))) { + Output(true, "Invalid application.ini path.\n"); + return 1; + } + + // We have a valid application.ini path passed in to the -app parameter + // but not yet a valid greDir, so lets look for it also on the same folder + // as the stub. + if (!greFound) { + lastSlash = strrchr(iniPath, PATH_SEPARATOR_CHAR); + if (!lastSlash) + return 1; + + *(++lastSlash) = '\0'; + + snprintf(greDir, sizeof(greDir), "%s" XPCOM_DLL, iniPath); + greFound = FolderExists(greDir); + } + + // copy it back. + strcpy(iniPath, result); + } + + nsINIParser parser; + rv = parser.Init(iniPath); + if (NS_FAILED(rv)) { + fprintf(stderr, "Could not read application.ini\n"); + return 1; + } + + if (!greFound) { +#ifdef XP_MACOSX + // The bundle can be found next to the executable, in the MacOS dir. + CFURLRef exurl = CFBundleCopyExecutableURL(appBundle); + CFURLRef absexurl = nullptr; + if (exurl) { + absexurl = CFURLCopyAbsoluteURL(exurl); + CFRelease(exurl); + } + + if (absexurl) { + char tbuffer[MAXPATHLEN]; + + if (CFURLGetFileSystemRepresentation(absexurl, true, + (UInt8*) tbuffer, + sizeof(tbuffer)) && + access(tbuffer, R_OK | X_OK) == 0) { + if (realpath(tbuffer, greDir)) { + greFound = true; + } + else { + greDir[0] = '\0'; + } + } + + CFRelease(absexurl); + } +#endif + if (!greFound) { + Output(false, "Could not find the Mozilla runtime.\n"); + return 1; + } + } + + rv = XPCOMGlueStartup(greDir); + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_OUT_OF_MEMORY) { + char applicationName[2000] = "this application"; + parser.GetString("App", "Name", applicationName, sizeof(applicationName)); + Output(true, "Not enough memory available to start %s.\n", + applicationName); + } else { + Output(true, "Couldn't load XPCOM.\n"); + } + return 1; + } + + static const nsDynamicFunctionLoad kXULFuncs[] = { + { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, + { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, + { "XRE_main", (NSFuncPtr*) &XRE_main }, + { nullptr, nullptr } + }; + + rv = XPCOMGlueLoadXULFunctions(kXULFuncs); + if (NS_FAILED(rv)) { + Output(true, "Couldn't load XRE functions.\n"); + return 1; + } + + NS_LogInit(); + + int retval; + + { // Scope COMPtr and AutoAppData + nsCOMPtr<nsIFile> iniFile; +#ifdef XP_WIN + // On Windows iniPath is UTF-8 encoded so we need to convert it. + rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(iniPath), false, + getter_AddRefs(iniFile)); +#else + rv = NS_NewNativeLocalFile(nsDependentCString(iniPath), false, + getter_AddRefs(iniFile)); +#endif + if (NS_FAILED(rv)) { + Output(true, "Couldn't find application.ini file.\n"); + return 1; + } + + AutoAppData appData(iniFile); + if (!appData) { + Output(true, "Error: couldn't parse application.ini.\n"); + return 1; + } + + NS_ASSERTION(appData->directory, "Failed to get app directory."); + + if (!appData->xreDirectory) { + // chop "libxul.so" off the GRE path + lastSlash = strrchr(greDir, PATH_SEPARATOR_CHAR); + if (lastSlash) { + *lastSlash = '\0'; + } +#ifdef XP_WIN + // same as iniPath. + NS_NewLocalFile(NS_ConvertUTF8toUTF16(greDir), false, + &appData->xreDirectory); +#else + NS_NewNativeLocalFile(nsDependentCString(greDir), false, + &appData->xreDirectory); +#endif + } + + retval = XRE_main(argc, argv, appData, 0); + } + + NS_LogTerm(); + + return retval; +} diff --git a/application/xulrunner/stub/xulrunner-stub.exe.manifest b/application/xulrunner/stub/xulrunner-stub.exe.manifest new file mode 100644 index 000000000..57c2a7070 --- /dev/null +++ b/application/xulrunner/stub/xulrunner-stub.exe.manifest @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="*" + name="Mozilla.XULRunner.Stub" + type="win32" +/> +<description>Mozilla XULRunner Stub</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="*" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3"> + <ms_asmv3:security> + <ms_asmv3:requestedPrivileges> + <ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" /> + </ms_asmv3:requestedPrivileges> + </ms_asmv3:security> +</ms_asmv3:trustInfo> + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <application> + <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> + <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> + <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> + <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> + <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> + </application> + </compatibility> +</assembly> diff --git a/browser/extensions/flyweb/skin/windows/flyweb.css b/application/xulrunner/stub/xulrunner-stub.rc index c549248da..84c3e47ed 100644 --- a/browser/extensions/flyweb/skin/windows/flyweb.css +++ b/application/xulrunner/stub/xulrunner-stub.rc @@ -1,5 +1,6 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -@import url("chrome://flyweb-shared/skin/flyweb.css"); +1 24 "xulrunner-stub.exe.manifest" diff --git a/application/xulrunner/tools/redit/Makefile.in b/application/xulrunner/tools/redit/Makefile.in new file mode 100644 index 000000000..31c253be8 --- /dev/null +++ b/application/xulrunner/tools/redit/Makefile.in @@ -0,0 +1,11 @@ +# 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/. */ + +ifeq ($(OS_ARCH),WINNT) + +SDK_BINARY = \ + $(PROGRAM) \ + $(NULL) + +endif diff --git a/application/xulrunner/tools/redit/moz.build b/application/xulrunner/tools/redit/moz.build new file mode 100644 index 000000000..812a56578 --- /dev/null +++ b/application/xulrunner/tools/redit/moz.build @@ -0,0 +1,15 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if CONFIG['OS_ARCH'] == 'WINNT': + GeckoProgram('redit') + SOURCES += [ + 'redit.cpp', + ] + for var in ('WIN32_LEAN_AND_MEAN', 'UNICODE', '_UNICODE'): + DEFINES[var] = True + if CONFIG['GNU_CC']: + WIN32_EXE_LDFLAGS += ['-municode'] diff --git a/application/xulrunner/tools/redit/redit.cpp b/application/xulrunner/tools/redit/redit.cpp new file mode 100644 index 000000000..8a96358b2 --- /dev/null +++ b/application/xulrunner/tools/redit/redit.cpp @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// System headers (alphabetical) +#include <fcntl.h> +#include <io.h> +#include <share.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <windows.h> + +// Mozilla headers (alphabetical) +#include "mozilla/FileUtils.h" // ScopedClose +#include "mozilla/UniquePtrExtensions.h" + +/* +Icon files are made up of: + +IconHeader +IconDirEntry1 +IconDirEntry2 +... +IconDirEntryN +IconData1 +IconData2 +... +IconDataN + +Each IconData must be added as a new RT_ICON resource to the exe. Then +an RT_GROUP_ICON resource must be added that contains an equivalent +header: + +IconHeader +IconResEntry1 +IconResEntry2 +... +IconResEntryN +*/ + +#pragma pack(push, 2) +typedef struct +{ + WORD Reserved; + WORD ResourceType; + WORD ImageCount; +} IconHeader; + +typedef struct +{ + BYTE Width; + BYTE Height; + BYTE Colors; + BYTE Reserved; + WORD Planes; + WORD BitsPerPixel; + DWORD ImageSize; + DWORD ImageOffset; +} IconDirEntry; + +typedef struct +{ + BYTE Width; + BYTE Height; + BYTE Colors; + BYTE Reserved; + WORD Planes; + WORD BitsPerPixel; + DWORD ImageSize; + WORD ResourceID; // This field is the one difference to above +} IconResEntry; +#pragma pack(pop) + +namespace { + /** + * ScopedResourceUpdate is a RAII wrapper for Windows resource updating + * + * Instances |EndUpdateResourceW()| their handles when they go out of scope. + * They pass |TRUE| as the second argument to |EndUpdateResourceW()|, which + * causes the resource update to be aborted (changes are discarded). + */ + struct ScopedResourceUpdateTraits + { + typedef HANDLE type; + static type empty() { return nullptr; } + static void release(type handle) { + if(nullptr != handle) { + EndUpdateResourceW(handle, TRUE); // Discard changes + } + } + }; + + typedef mozilla::Scoped<ScopedResourceUpdateTraits> ScopedResourceUpdate; +}; + +#ifdef __MINGW32__ +extern "C" +#endif +int +wmain(int argc, wchar_t** argv) +{ + if (argc != 3) { + printf("Usage: redit <exe file> <icon file>\n"); + return 1; + } + + mozilla::ScopedClose file; + if (0 != _wsopen_s(&file.rwget(), + argv[2], + _O_BINARY | _O_RDONLY, + _SH_DENYWR, + _S_IREAD) + || (-1 == file)) { + fprintf(stderr, "Unable to open icon file.\n"); + return 1; + } + + // Load all the data from the icon file + long filesize = _filelength(file); + auto data = MakeUniqueFallible<BYTE[]>(filesize); + if(!data) { + fprintf(stderr, "Failed to allocate memory for icon file.\n"); + return 1; + } + _read(file, data.get(), filesize); + + IconHeader* header = reinterpret_cast<IconHeader*>(data.get()); + + // Open the target library for updating + ScopedResourceUpdate updateRes(BeginUpdateResourceW(argv[1], FALSE)); + if (nullptr == updateRes) { + fprintf(stderr, "Unable to open library for modification.\n"); + return 1; + } + + // Allocate the group resource entry + long groupSize = sizeof(IconHeader) + + header->ImageCount * sizeof(IconResEntry); + auto group = MakeUniqueFallible<BYTE[]>(groupSize); + if(!group) { + fprintf(stderr, "Failed to allocate memory for new images.\n"); + return 1; + } + memcpy(group.get(), data.get(), sizeof(IconHeader)); + + IconDirEntry* sourceIcon = + reinterpret_cast<IconDirEntry*>(data.get() + + sizeof(IconHeader)); + IconResEntry* targetIcon = + reinterpret_cast<IconResEntry*>(group.get() + + sizeof(IconHeader)); + + for (int id = 1; id <= header->ImageCount; id++) { + // Add the individual icon + if (!UpdateResourceW(updateRes, RT_ICON, MAKEINTRESOURCE(id), + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + data + sourceIcon->ImageOffset, + sourceIcon->ImageSize)) { + fprintf(stderr, "Unable to update resource (RT_ICON).\n"); + return 1; + } + // Copy the data for this icon + // (note that the structs have different sizes) + memcpy(targetIcon, sourceIcon, sizeof(IconResEntry)); + targetIcon->ResourceID = id; + sourceIcon++; + targetIcon++; + } + + if (!UpdateResourceW(updateRes, RT_GROUP_ICON, L"MAINICON", + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + group, groupSize)) { + fprintf(stderr, "Unable to update resource (RT_GROUP_ICON).\n"); + return 1; + } + + // Save the modifications + if(!EndUpdateResourceW(updateRes.forget(), FALSE)) { + fprintf(stderr, "Unable to write changes to library.\n"); + return 1; + } + + return 0; +} diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 0ef9d4ab5..5637d1797 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -156,8 +156,8 @@ pref("app.update.service.enabled", true); // .. etc .. // pref("extensions.update.enabled", true); -pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); -pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); +pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=52.9&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); +pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=52.9&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); pref("extensions.update.interval", 86400); // Check for updates to Extensions and // Themes every day // Non-symmetric (not shared by extensions) extension-specific [update] preferences diff --git a/browser/base/content/browser-syncui.js b/browser/base/content/browser-syncui.js index c5c2995c8..51bcb15d5 100644 --- a/browser/base/content/browser-syncui.js +++ b/browser/base/content/browser-syncui.js @@ -4,10 +4,10 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -if (AppConstants.MOZ_SERVICES_CLOUDSYNC) { - XPCOMUtils.defineLazyModuleGetter(this, "CloudSync", - "resource://gre/modules/CloudSync.jsm"); -} +#ifdef MOZ_SERVICES_CLOUDSYNC +XPCOMUtils.defineLazyModuleGetter(this, "CloudSync", + "resource://gre/modules/CloudSync.jsm"); +#endif XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", "resource://gre/modules/FxAccounts.jsm"); @@ -170,9 +170,13 @@ var gSyncUI = { document.getElementById("sync-setup-state").hidden = true; document.getElementById("sync-syncnow-state").hidden = true; +#ifdef MOZ_SERVICES_CLOUDSYNC if (CloudSync && CloudSync.ready && CloudSync().adapters.count) { document.getElementById("sync-syncnow-state").hidden = false; } else if (loginFailed) { +#else + if (loginFailed) { +#endif // unhiding this element makes the menubar show the login failure state. document.getElementById("sync-reauth-state").hidden = false; } else if (needsSetup) { diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 5879f2a29..485471ee3 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -9,7 +9,9 @@ <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/content/usercontext/usercontext.css" type="text/css"?> +#ifdef MOZ_DEVTOOLS <?xml-stylesheet href="chrome://devtools/skin/devtools-browser.css" type="text/css"?> +#endif <?xml-stylesheet href="chrome://browser/skin/controlcenter/panel.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/customizableui/panelUI.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?> diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 8eb9b034f..ddf695202 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -1158,7 +1158,8 @@ nsContextMenu.prototype = { this.browser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); openUILink(this.mediaURL, e, { disallowInheritPrincipal: true, - referrerURI: referrerURI }); + referrerURI: referrerURI, + forceAllowDataURI: true }); } }, diff --git a/browser/base/content/sync/aboutSyncTabs.js b/browser/base/content/sync/aboutSyncTabs.js index 0c5dbb2d8..f4bb607ea 100644 --- a/browser/base/content/sync/aboutSyncTabs.js +++ b/browser/base/content/sync/aboutSyncTabs.js @@ -7,7 +7,6 @@ var Cu = Components.utils; Cu.import("resource://services-common/utils.js"); Cu.import("resource://services-sync/main.js"); Cu.import("resource:///modules/PlacesUIUtils.jsm"); -Cu.import("resource://gre/modules/AppConstants.jsm"); Cu.import("resource://gre/modules/PlacesUtils.jsm", this); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -15,10 +14,10 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); -if (AppConstants.MOZ_SERVICES_CLOUDSYNC) { - XPCOMUtils.defineLazyModuleGetter(this, "CloudSync", - "resource://gre/modules/CloudSync.jsm"); -} +#ifdef MOZ_SERVICES_CLOUDSYNC +XPCOMUtils.defineLazyModuleGetter(this, "CloudSync", + "resource://gre/modules/CloudSync.jsm"); +#endif var RemoteTabViewer = { _tabsList: null, @@ -184,12 +183,16 @@ var RemoteTabViewer = { } } +#ifdef MOZ_SERVICES_CLOUDSYNC if (CloudSync && CloudSync.ready && CloudSync().tabsReady && CloudSync().tabs.hasRemoteTabs()) { this._generateCloudSyncTabList() .then(complete, complete); } else { complete(); } +#else + complete(); +#endif }, _clearTabList: function () { diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 0b703b6f8..6ceaf773e 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -197,6 +197,7 @@ function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI openLinkIn(url, where, params); } +/* eslint-disable complexity */ function openLinkIn(url, where, params) { if (!where || !url) return; @@ -212,6 +213,7 @@ function openLinkIn(url, where, params) { params.referrerPolicy : Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT); var aRelatedToCurrent = params.relatedToCurrent; var aAllowMixedContent = params.allowMixedContent; + var aForceAllowDataURI = params.forceAllowDataURI; var aInBackground = params.inBackground; var aDisallowInheritPrincipal = params.disallowInheritPrincipal; var aInitiatingDoc = params.initiatingDoc; @@ -378,6 +380,9 @@ function openLinkIn(url, where, params) { if (aIndicateErrorPageLoad) { flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ERROR_LOAD_CHANGES_RV; } + if (aForceAllowDataURI) { + flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FORCE_ALLOW_DATA_URI; + } let {URI_INHERITS_SECURITY_CONTEXT} = Ci.nsIProtocolHandler; if (aForceAboutBlankViewerInCurrent && diff --git a/browser/base/jar.mn b/browser/base/jar.mn index 9cbfe7c15..c58265351 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -87,7 +87,7 @@ browser.jar: content/browser/browser-safebrowsing.js (content/browser-safebrowsing.js) content/browser/browser-sidebar.js (content/browser-sidebar.js) content/browser/browser-social.js (content/browser-social.js) - content/browser/browser-syncui.js (content/browser-syncui.js) +* content/browser/browser-syncui.js (content/browser-syncui.js) * content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml) #ifdef CAN_DRAW_IN_TITLEBAR content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar.js) @@ -138,7 +138,7 @@ browser.jar: content/browser/pageinfo/permissions.js (content/pageinfo/permissions.js) content/browser/pageinfo/security.js (content/pageinfo/security.js) content/browser/sync/aboutSyncTabs.xul (content/sync/aboutSyncTabs.xul) - content/browser/sync/aboutSyncTabs.js (content/sync/aboutSyncTabs.js) +* content/browser/sync/aboutSyncTabs.js (content/sync/aboutSyncTabs.js) content/browser/sync/aboutSyncTabs.css (content/sync/aboutSyncTabs.css) content/browser/sync/aboutSyncTabs-bindings.xml (content/sync/aboutSyncTabs-bindings.xml) content/browser/sync/setup.xul (content/sync/setup.xul) diff --git a/browser/branding/official/locales/en-US/brand.dtd b/browser/branding/official/locales/en-US/brand.dtd index 7bfa07f71..1d2ac791e 100644 --- a/browser/branding/official/locales/en-US/brand.dtd +++ b/browser/branding/official/locales/en-US/brand.dtd @@ -6,4 +6,5 @@ <!ENTITY brandShortName "Basilisk"> <!ENTITY brandFullName "Basilisk"> <!ENTITY vendorShortName "Moonchild"> +<!ENTITY vendorFullName "Moonchild Productions"> <!ENTITY trademarkInfo.part1 "Basilisk, Basilisk Browser and the Basilisk logos are trademarks of Moonchild Productions."> diff --git a/browser/branding/shared/uaoverrides.inc b/browser/branding/shared/uaoverrides.inc index 13a89ed7f..59e413728 100644 --- a/browser/branding/shared/uaoverrides.inc +++ b/browser/branding/shared/uaoverrides.inc @@ -5,7 +5,7 @@ #define GRE_DATE_SLICE Goanna/20170101
#define APP_SLICE Basilisk/@MOZ_APP_VERSION@
-#define GK_VERSION 52.0
+#define GK_VERSION 52.9
#define GK_SLICE Gecko/20100101
#define FX_SLICE Firefox/@GK_VERSION@
@@ -27,6 +27,8 @@ pref("@GUAO_PREF@.accounts.firefox.com", "Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION // The never-ending Facebook debacle...
// UA-Sniffing domains below are pending responses from their operators - temp workaround
+// Daily motion only likes strict Firefox UAs
+pref("@GUAO_PREF@.dailymotion.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) @GK_SLICE@ Firefox/52.0");
// The following requires native mode. Or it blocks.. "too old firefox", breakage, etc.
@@ -35,4 +37,5 @@ pref("@GUAO_PREF@.accounts.firefox.com", "Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION // UA-sniffing domains that are "app/vendor-specific" and do not like Pale Moon
// The following domains do not like the Goanna slice
-
+pref("@GUAO_PREF@.hitbox.tv","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@");
+pref("@GUAO_PREF@.yuku.com","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@ @APP_SLICE@");
diff --git a/browser/components/migration/FirefoxProfileMigrator.js b/browser/components/migration/FirefoxProfileMigrator.js index 60ffcf627..2714cdbcd 100644 --- a/browser/components/migration/FirefoxProfileMigrator.js +++ b/browser/components/migration/FirefoxProfileMigrator.js @@ -7,7 +7,7 @@ "use strict"; /* - * Migrates from a Firefox profile in a lossy manner in order to clean up a + * Migrates from a Basilisk profile in a lossy manner in order to clean up a * user's profile. Data is only migrated where the benefits outweigh the * potential problems caused by importing undesired/invalid configurations * from the source profile. diff --git a/browser/components/migration/MigrationUtils.jsm b/browser/components/migration/MigrationUtils.jsm index 104efe005..e133ec520 100644 --- a/browser/components/migration/MigrationUtils.jsm +++ b/browser/components/migration/MigrationUtils.jsm @@ -726,6 +726,7 @@ this.MigrationUtils = Object.freeze({ "Internet Explorer": "ie", "Microsoft Edge": "edge", "Safari": "safari", + "Basilisk": "firefox", "Firefox": "firefox", "Nightly": "firefox", "Google Chrome": "chrome", // Windows, Linux diff --git a/browser/components/places/content/controller.js b/browser/components/places/content/controller.js index 0d66fbcaf..ebdab60f4 100644 --- a/browser/components/places/content/controller.js +++ b/browser/components/places/content/controller.js @@ -253,7 +253,8 @@ PlacesController.prototype = { } else host = NetUtil.newURI(this._view.selectedNode.uri).host; - ForgetAboutSite.removeDataFromDomain(host); + ForgetAboutSite.removeDataFromDomain(host) + .catch(Components.utils.reportError); break; case "cmd_selectAll": this.selectAll(); diff --git a/browser/components/preferences/in-content/security.js b/browser/components/preferences/in-content/security.js index a8ad28c7e..0d7af39a3 100644 --- a/browser/components/preferences/in-content/security.js +++ b/browser/components/preferences/in-content/security.js @@ -168,12 +168,24 @@ var gSecurityPane = { let safeBrowsingPhishingPref = document.getElementById("browser.safebrowsing.phishing.enabled"); let safeBrowsingMalwarePref = document.getElementById("browser.safebrowsing.malware.enabled"); + let safeBrowsingUIPref = document.getElementById("browser.safebrowsing.UI.enabled"); + let safeBrowsingUISep = document.getElementById("safeBrowsingUISep"); + let safeBrowsingUIGroup = document.getElementById("safeBrowsingUIGroup"); + let blockDownloadsPref = document.getElementById("browser.safebrowsing.downloads.enabled"); let malwareTable = document.getElementById("urlclassifier.malwareTable"); let blockUnwantedPref = document.getElementById("browser.safebrowsing.downloads.remote.block_potentially_unwanted"); let blockUncommonPref = document.getElementById("browser.safebrowsing.downloads.remote.block_uncommon"); + if (safeBrowsingUIPref.value == false) { + safeBrowsingUISep.setAttribute("hidden", "true"); + safeBrowsingUIGroup.setAttribute("hidden", "true"); + } else { + safeBrowsingUISep.removeAttribute("hidden"); + safeBrowsingUIGroup.removeAttribute("hidden"); + } + enableSafeBrowsing.addEventListener("command", function() { safeBrowsingPhishingPref.value = enableSafeBrowsing.checked; safeBrowsingMalwarePref.value = enableSafeBrowsing.checked; diff --git a/browser/components/preferences/in-content/security.xul b/browser/components/preferences/in-content/security.xul index b7bdb9361..5dc8ad5e9 100644 --- a/browser/components/preferences/in-content/security.xul +++ b/browser/components/preferences/in-content/security.xul @@ -28,6 +28,10 @@ name="browser.safebrowsing.phishing.enabled" type="bool"/> + <preference id="browser.safebrowsing.UI.enabled" + name="browser.safebrowsing.UI.enabled" + type="bool"/> + <preference id="browser.safebrowsing.downloads.enabled" name="browser.safebrowsing.downloads.enabled" type="bool"/> @@ -73,8 +77,8 @@ accesskey="&addonExceptions.accesskey;"/> </hbox> - <separator class="thin"/> - <vbox align="start"> + <separator id="safeBrowsingUISep" class="thin"/> + <vbox id="safeBrowsingUIGroup" align="start"> <checkbox id="enableSafeBrowsing" label="&enableSafeBrowsing.label;" accesskey="&enableSafeBrowsing.accesskey;" /> diff --git a/browser/components/sessionstore/content/aboutSessionRestore.js b/browser/components/sessionstore/content/aboutSessionRestore.js index cc8d2da0b..8a9410aa8 100644 --- a/browser/components/sessionstore/content/aboutSessionRestore.js +++ b/browser/components/sessionstore/content/aboutSessionRestore.js @@ -41,7 +41,11 @@ window.onload = function() { return; } - gStateObject = JSON.parse(sessionData.value); + try { + gStateObject = JSON.parse(sessionData.value); + } catch (e) { + Cu.reportError(e); + } // make sure the data is tracked to be restored in case of a subsequent crash var event = document.createEvent("UIEvents"); @@ -68,30 +72,32 @@ function initTreeView() { var winLabel = tabList.getAttribute("_window_label"); gTreeData = []; - gStateObject.windows.forEach(function(aWinData, aIx) { - var winState = { - label: winLabel.replace("%S", (aIx + 1)), - open: true, - checked: true, - ix: aIx - }; - winState.tabs = aWinData.tabs.map(function(aTabData) { - var entry = aTabData.entries[aTabData.index - 1] || { url: "about:blank" }; - var iconURL = aTabData.image || null; - // don't initiate a connection just to fetch a favicon (see bug 462863) - if (/^https?:/.test(iconURL)) - iconURL = "moz-anno:favicon:" + iconURL; - return { - label: entry.title || entry.url, + if (gStateObject) { + gStateObject.windows.forEach(function(aWinData, aIx) { + var winState = { + label: winLabel.replace("%S", (aIx + 1)), + open: true, checked: true, - src: iconURL, - parent: winState + ix: aIx }; - }); - gTreeData.push(winState); - for (let tab of winState.tabs) - gTreeData.push(tab); - }, this); + winState.tabs = aWinData.tabs.map(function(aTabData) { + var entry = aTabData.entries[aTabData.index - 1] || { url: "about:blank" }; + var iconURL = aTabData.image || null; + // don't initiate a connection just to fetch a favicon (see bug 462863) + if (/^https?:/.test(iconURL)) + iconURL = "moz-anno:favicon:" + iconURL; + return { + label: entry.title || entry.url, + checked: true, + src: iconURL, + parent: winState + }; + }); + gTreeData.push(winState); + for (let tab of winState.tabs) + gTreeData.push(tab); + }, this); + } tabList.view = treeView; tabList.view.selection.select(0); diff --git a/browser/components/webextensions/ext-commands.js b/browser/components/webextensions/ext-commands.js index 416544e86..b6e7ab3d1 100644 --- a/browser/components/webextensions/ext-commands.js +++ b/browser/components/webextensions/ext-commands.js @@ -74,15 +74,14 @@ CommandList.prototype = { // For Windows, chrome.runtime expects 'win' while chrome.commands // expects 'windows'. We can special case this for now. let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os; - for (let name of Object.keys(manifest.commands)) { - let command = manifest.commands[name]; - let shortcut = command.suggested_key[os] || command.suggested_key.default; - if (shortcut) { - commands.set(name, { - description: command.description, - shortcut: shortcut.replace(/\s+/g, ""), - }); - } + for (let [name, command] of Object.entries(manifest.commands)) { + let suggested_key = command.suggested_key || {}; + let shortcut = suggested_key[os] || suggested_key.default; + shortcut = shortcut ? shortcut.replace(/\s+/g, "") : null; + commands.set(name, { + description: command.description, + shortcut, + }); } return commands; }, @@ -96,8 +95,10 @@ CommandList.prototype = { let keyset = doc.createElementNS(XUL_NS, "keyset"); keyset.id = `ext-keyset-id-${this.id}`; this.commands.forEach((command, name) => { - let keyElement = this.buildKey(doc, name, command.shortcut); - keyset.appendChild(keyElement); + if (command.shortcut) { + let keyElement = this.buildKey(doc, name, command.shortcut); + keyset.appendChild(keyElement); + } }); doc.documentElement.appendChild(keyset); this.keysetsMap.set(window, keyset); @@ -162,11 +163,12 @@ CommandList.prototype = { // The modifiers are the remaining elements. keyElement.setAttribute("modifiers", this.getModifiersAttribute(parts)); - if (/^[A-Z0-9]$/.test(chromeKey)) { + if (/^[A-Z]$/.test(chromeKey)) { // We use the key attribute for all single digits and characters. keyElement.setAttribute("key", chromeKey); } else { keyElement.setAttribute("keycode", this.getKeycodeAttribute(chromeKey)); + keyElement.setAttribute("event", "keydown"); } return keyElement; @@ -186,6 +188,9 @@ CommandList.prototype = { * @returns {string} The constructed value for the Key's 'keycode' attribute. */ getKeycodeAttribute(chromeKey) { + if (/[0-9]/.test(chromeKey)) { + return `VK_${chromeKey}`; + } return `VK${chromeKey.replace(/([A-Z])/g, "_$&").toUpperCase()}`; }, diff --git a/browser/confvars.sh b/browser/confvars.sh index 03b4cea97..41c0be3d7 100755 --- a/browser/confvars.sh +++ b/browser/confvars.sh @@ -58,7 +58,7 @@ MOZ_WEBEXTENSIONS=1 MOZ_DEVTOOLS=1 MOZ_SERVICES_COMMON=1 MOZ_SERVICES_SYNC=1 -MOZ_SERVICES_HEALTHREPORT=1 +MOZ_SERVICES_HEALTHREPORT= # Disable checking that add-ons are signed by the trusted root MOZ_ADDON_SIGNING=0 diff --git a/browser/extensions/aushelper/bootstrap.js b/browser/extensions/aushelper/bootstrap.js deleted file mode 100644 index f57f621e1..000000000 --- a/browser/extensions/aushelper/bootstrap.js +++ /dev/null @@ -1,189 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -const APP_UPDATE_URL_PREF = "app.update.url"; -const REPLACE_KEY = "%OS_VERSION%"; - -const AUSHELPER_CPU_RESULT_CODE_HISTOGRAM_ID = "AUSHELPER_CPU_RESULT_CODE"; -// The system is not vulnerable to Bug 1296630. -const CPU_NO_BUG1296630 = 1; -// The system is vulnerable to Bug 1296630. -const CPU_YES_BUG1296630 = 2; -// An error occured when checking if the system is vulnerable to Bug 1296630. -const CPU_ERR_BUG1296630 = 3; -// It is unknown whether the system is vulnerable to Bug 1296630 (should never happen). -const CPU_UNKNOWN_BUG1296630 = 4; - -const AUSHELPER_CPU_ERROR_CODE_HISTOGRAM_ID = "AUSHELPER_CPU_ERROR_CODE"; -const CPU_SUCCESS = 0; -const CPU_REG_OPEN_ERROR = 1; -const CPU_VENDOR_ID_ERROR = 2; -const CPU_ID_ERROR = 4; -const CPU_REV_ERROR = 8; - -const AUSHELPER_WEBSENSE_REG_VERSION_SCALAR_NAME = "aushelper.websense_reg_version"; -const AUSHELPER_WEBSENSE_REG_EXISTS_HISTOGRAM_ID = "AUSHELPER_WEBSENSE_REG_EXISTS"; - -const AUSHELPER_WEBSENSE_ERROR_CODE_HISTOGRAM_ID = "AUSHELPER_WEBSENSE_ERROR_CODE"; -const WEBSENSE_SUCCESS = 0; -const WEBSENSE_REG_OPEN_ERROR = 1; -const WEBSENSE_REG_READ_ERROR = 2; -const WEBSENSE_ALREADY_MODIFIED = 4; - -Cu.import("resource://gre/modules/Services.jsm"); - -function startup() { - if (Services.appinfo.OS != "WINNT") { - return; - } - - const regCPUPath = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; - let wrk; - let cpuErrorCode = CPU_SUCCESS; - try { - wrk = Cc["@mozilla.org/windows-registry-key;1"].createInstance(Ci.nsIWindowsRegKey); - wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, regCPUPath, wrk.ACCESS_READ); - } catch (e) { - Cu.reportError("AUSHelper - unable to open registry. Exception: " + e); - cpuErrorCode |= CPU_REG_OPEN_ERROR; - } - - // If any of the following values are successfully retrieved and they don't - // match the condition for that value then it is safe to update. Hence why the - // following checks are somewhat convoluted. The possible values for the - // variable set by each check is as follows: - // - // | Match | No Match | Error | - // variable | true | false | null | - - let cpuVendorIDMatch = false; - try { - let cpuVendorID = wrk.readStringValue("VendorIdentifier"); - if (cpuVendorID.toLowerCase() == "genuineintel") { - cpuVendorIDMatch = true; - } - } catch (e) { - Cu.reportError("AUSHelper - error getting CPU vendor indentifier. Exception: " + e); - cpuVendorIDMatch = null; - cpuErrorCode |= CPU_VENDOR_ID_ERROR; - } - - let cpuIDMatch = false; - try { - let cpuID = wrk.readStringValue("Identifier"); - if (cpuID.toLowerCase().indexOf("family 6 model 61 stepping 4") != -1) { - cpuIDMatch = true; - } - } catch (e) { - Cu.reportError("AUSHelper - error getting CPU indentifier. Exception: " + e); - cpuIDMatch = null; - cpuErrorCode |= CPU_ID_ERROR; - } - - let microCodeVersions = [0xe, 0x11, 0x12, 0x13, 0x16, 0x18, 0x19]; - let cpuRevMatch = null; - try { - let keyNames = ["Update Revision", "Update Signature"]; - for (let i = 0; i < keyNames.length; ++i) { - try { - let regVal = wrk.readBinaryValue(keyNames[i]); - if (regVal.length == 8) { - let hexVal = []; - // We are only inyterested in the upper 4 bytes and the little endian - // value for it. - for (let j = 4; j < 8; j++) { - let c = regVal.charCodeAt(j).toString(16); - if (c.length == 1) { - c = "0" + c; - } - hexVal.unshift(c); - } - cpuRevMatch = false; - if (microCodeVersions.indexOf(parseInt(hexVal.join(''))) != -1) { - cpuRevMatch = true; - } - break; - } - } catch (e) { - if (i == keyNames.length - 1) { - // The registry key name's value was not successfully queried. - cpuRevMatch = null; - cpuErrorCode |= CPU_REV_ERROR; - } - } - } - wrk.close(); - } catch (ex) { - Cu.reportError("AUSHelper - error getting CPU revision. Exception: " + ex); - cpuRevMatch = null; - cpuErrorCode |= CPU_REV_ERROR; - } - - let cpuResult = CPU_UNKNOWN_BUG1296630; - let cpuValue = "(unkBug1296630v1)"; - // The following uses strict equality checks since the values can be true, - // false, or null. - if (cpuVendorIDMatch === false || cpuIDMatch === false || cpuRevMatch === false) { - // Since one of the values is false then the system won't be affected by - // bug 1296630 according to the conditions set out in bug 1311515. - cpuValue = "(noBug1296630v1)"; - cpuResult = CPU_NO_BUG1296630; - } else if (cpuVendorIDMatch === null || cpuIDMatch === null || cpuRevMatch === null) { - // Since one of the values is null we can't say for sure if the system will - // be affected by bug 1296630. - cpuValue = "(errBug1296630v1)"; - cpuResult = CPU_ERR_BUG1296630; - } else if (cpuVendorIDMatch === true && cpuIDMatch === true && cpuRevMatch === true) { - // Since all of the values are true we can say that the system will be - // affected by bug 1296630. - cpuValue = "(yesBug1296630v1)"; - cpuResult = CPU_YES_BUG1296630; - } - - Services.telemetry.getHistogramById(AUSHELPER_CPU_RESULT_CODE_HISTOGRAM_ID).add(cpuResult); - Services.telemetry.getHistogramById(AUSHELPER_CPU_ERROR_CODE_HISTOGRAM_ID).add(cpuErrorCode); - - const regWebsensePath = "Websense\\Agent"; - let websenseErrorCode = WEBSENSE_SUCCESS; - let websenseVersion = ""; - try { - let regModes = [wrk.ACCESS_READ, wrk.ACCESS_READ | wrk.WOW64_64]; - for (let i = 0; i < regModes.length; ++i) { - wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, "SOFTWARE", regModes[i]); - try { - if (wrk.hasChild(regWebsensePath)) { - let childKey = wrk.openChild(regWebsensePath, wrk.ACCESS_READ); - websenseVersion = childKey.readStringValue("InstallVersion"); - Services.telemetry.scalarSet(AUSHELPER_WEBSENSE_REG_VERSION_SCALAR_NAME, websenseVersion); - } - wrk.close(); - } catch (e) { - Cu.reportError("AUSHelper - unable to read registry. Exception: " + e); - websenseErrorCode |= WEBSENSE_REG_READ_ERROR; - } - } - } catch (ex) { - Cu.reportError("AUSHelper - unable to open registry. Exception: " + ex); - websenseErrorCode |= WEBSENSE_REG_OPEN_ERROR; - } - - Services.telemetry.getHistogramById(AUSHELPER_WEBSENSE_REG_EXISTS_HISTOGRAM_ID).add(!!websenseVersion); - let websenseValue = "(" + (websenseVersion ? "websense-" + websenseVersion : "nowebsense") + ")"; - - let branch = Services.prefs.getDefaultBranch(""); - let curValue = branch.getCharPref(APP_UPDATE_URL_PREF); - if (curValue.indexOf(REPLACE_KEY + "/") > -1) { - let newValue = curValue.replace(REPLACE_KEY + "/", REPLACE_KEY + cpuValue + websenseValue + "/"); - branch.setCharPref(APP_UPDATE_URL_PREF, newValue); - } else { - websenseErrorCode |= WEBSENSE_ALREADY_MODIFIED; - } - Services.telemetry.getHistogramById(AUSHELPER_WEBSENSE_ERROR_CODE_HISTOGRAM_ID).add(websenseErrorCode); -} -function shutdown() {} -function install() {} -function uninstall() {} diff --git a/browser/extensions/aushelper/install.rdf.in b/browser/extensions/aushelper/install.rdf.in deleted file mode 100644 index 78e841d88..000000000 --- a/browser/extensions/aushelper/install.rdf.in +++ /dev/null @@ -1,32 +0,0 @@ -<?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/. --> - -#filter substitution - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>aushelper@mozilla.org</em:id> - <em:version>2.0</em:version> - <em:type>2</em:type> - <em:bootstrap>true</em:bootstrap> - <em:multiprocessCompatible>true</em:multiprocessCompatible> - - <!-- Target Application this extension can install into, - with minimum and maximum supported versions. --> - <em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>@MOZ_APP_VERSION@</em:minVersion> - <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion> - </Description> - </em:targetApplication> - - <!-- Front End MetaData --> - <em:name>Application Update Service Helper</em:name> - <em:description>Sets value(s) in the update url based on custom checks.</em:description> - </Description> -</RDF> diff --git a/browser/extensions/e10srollout/bootstrap.js b/browser/extensions/e10srollout/bootstrap.js deleted file mode 100644 index 0da7ac225..000000000 --- a/browser/extensions/e10srollout/bootstrap.js +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/UpdateUtils.jsm"); -Cu.import("resource://gre/modules/AppConstants.jsm"); - - // The amount of people to be part of e10s -const TEST_THRESHOLD = { - "beta" : 0.5, // 50% - "release" : 1.0, // 100% - "esr" : 1.0, // 100% -}; - -const ADDON_ROLLOUT_POLICY = { - "beta" : "51alladdons", // Any WebExtension or addon except with mpc = false - "release" : "51set1", - "esr" : "esrA", // WebExtensions and Addons with mpc=true -}; - -if (AppConstants.RELEASE_OR_BETA) { - // Bug 1348576 - e10s is never enabled for non-official release builds - // This is hacky, but the problem it solves is the following: - // the e10s rollout is controlled by the channel name, which - // is the only way to distinguish between Beta and Release. - // However, non-official release builds (like the ones done by distros - // to ship Firefox on their package managers) do not set a value - // for the release channel, which gets them to the default value - // of.. (drumroll) "default". - // But we can't just always configure the same settings for the - // "default" channel because that's also the name that a locally - // built Firefox gets, and e10s is managed in a different way - // there (directly by prefs, on Nightly and Aurora). - TEST_THRESHOLD.default = TEST_THRESHOLD.release; - ADDON_ROLLOUT_POLICY.default = ADDON_ROLLOUT_POLICY.release; -} - - -const PREF_COHORT_SAMPLE = "e10s.rollout.cohortSample"; -const PREF_COHORT_NAME = "e10s.rollout.cohort"; -const PREF_E10S_OPTED_IN = "browser.tabs.remote.autostart"; -const PREF_E10S_FORCE_ENABLED = "browser.tabs.remote.force-enable"; -const PREF_E10S_FORCE_DISABLED = "browser.tabs.remote.force-disable"; -const PREF_TOGGLE_E10S = "browser.tabs.remote.autostart.2"; -const PREF_E10S_ADDON_POLICY = "extensions.e10s.rollout.policy"; -const PREF_E10S_ADDON_BLOCKLIST = "extensions.e10s.rollout.blocklist"; -const PREF_E10S_HAS_NONEXEMPT_ADDON = "extensions.e10s.rollout.hasAddon"; - -function startup() { - // In theory we only need to run this once (on install()), but - // it's better to also run it on every startup. If the user has - // made manual changes to the prefs, this will keep the data - // reported more accurate. - // It's also fine (and preferred) to just do it here on startup - // (instead of observing prefs), because e10s takes a restart - // to take effect, so we keep the data based on how it was when - // the session started. - defineCohort(); -} - -function install() { - defineCohort(); -} - -let cohortDefinedOnThisSession = false; - -function defineCohort() { - // Avoid running twice when it was called by install() first - if (cohortDefinedOnThisSession) { - return; - } - cohortDefinedOnThisSession = true; - - let updateChannel = UpdateUtils.getUpdateChannel(false); - if (!(updateChannel in TEST_THRESHOLD)) { - setCohort("unsupportedChannel"); - return; - } - - let addonPolicy = "unknown"; - if (updateChannel in ADDON_ROLLOUT_POLICY) { - addonPolicy = ADDON_ROLLOUT_POLICY[updateChannel]; - Preferences.set(PREF_E10S_ADDON_POLICY, addonPolicy); - // This is also the proper place to set the blocklist pref - // in case it is necessary. - - Preferences.set(PREF_E10S_ADDON_BLOCKLIST, - // bug 1185672 - Tab Mix Plus - "{dc572301-7619-498c-a57d-39143191b318};" + - // bug 1332692 - LastPass - "support@lastpass.com;"); - } else { - Preferences.reset(PREF_E10S_ADDON_POLICY); - } - - let userOptedOut = optedOut(); - let userOptedIn = optedIn(); - let disqualified = (Services.appinfo.multiprocessBlockPolicy != 0); - let testGroup = (getUserSample() < TEST_THRESHOLD[updateChannel]); - let hasNonExemptAddon = Preferences.get(PREF_E10S_HAS_NONEXEMPT_ADDON, false); - let temporaryDisqualification = getTemporaryDisqualification(); - - let cohortPrefix = ""; - if (disqualified) { - cohortPrefix = "disqualified-"; - } else if (hasNonExemptAddon) { - cohortPrefix = `addons-set${addonPolicy}-`; - } - - if (userOptedOut) { - setCohort("optedOut"); - } else if (userOptedIn) { - setCohort("optedIn"); - } else if (temporaryDisqualification != "") { - // Users who are disqualified by the backend (from multiprocessBlockPolicy) - // can be put into either the test or control groups, because e10s will - // still be denied by the backend, which is useful so that the E10S_STATUS - // telemetry probe can be correctly set. - - // For these volatile disqualification reasons, however, we must not try - // to activate e10s because the backend doesn't know about it. E10S_STATUS - // here will be accumulated as "2 - Disabled", which is fine too. - setCohort(`temp-disqualified-${temporaryDisqualification}`); - Preferences.reset(PREF_TOGGLE_E10S); - } else if (testGroup) { - setCohort(`${cohortPrefix}test`); - Preferences.set(PREF_TOGGLE_E10S, true); - } else { - setCohort(`${cohortPrefix}control`); - Preferences.reset(PREF_TOGGLE_E10S); - } -} - -function shutdown(data, reason) { -} - -function uninstall() { -} - -function getUserSample() { - let prefValue = Preferences.get(PREF_COHORT_SAMPLE, undefined); - let value = 0.0; - - if (typeof(prefValue) == "string") { - value = parseFloat(prefValue, 10); - return value; - } - - if (typeof(prefValue) == "number") { - // convert old integer value - value = prefValue / 100; - } else { - value = Math.random(); - } - - Preferences.set(PREF_COHORT_SAMPLE, value.toString().substr(0, 8)); - return value; -} - -function setCohort(cohortName) { - Preferences.set(PREF_COHORT_NAME, cohortName); - try { - if (Ci.nsICrashReporter) { - Services.appinfo.QueryInterface(Ci.nsICrashReporter).annotateCrashReport("E10SCohort", cohortName); - } - } catch (e) {} -} - -function optedIn() { - return Preferences.get(PREF_E10S_OPTED_IN, false) || - Preferences.get(PREF_E10S_FORCE_ENABLED, false); -} - -function optedOut() { - // Users can also opt-out by toggling back the pref to false. - // If they reset the pref instead they might be re-enabled if - // they are still part of the threshold. - return Preferences.get(PREF_E10S_FORCE_DISABLED, false) || - (Preferences.isSet(PREF_TOGGLE_E10S) && - Preferences.get(PREF_TOGGLE_E10S) == false); -} - -/* If this function returns a non-empty string, it - * means that this particular user should be temporarily - * disqualified due to some particular reason. - * If a user shouldn't be disqualified, then an empty - * string must be returned. - */ -function getTemporaryDisqualification() { - return ""; -} diff --git a/browser/extensions/e10srollout/install.rdf.in b/browser/extensions/e10srollout/install.rdf.in deleted file mode 100644 index 19ff58471..000000000 --- a/browser/extensions/e10srollout/install.rdf.in +++ /dev/null @@ -1,32 +0,0 @@ -<?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/. --> - -#filter substitution - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>e10srollout@mozilla.org</em:id> - <em:version>1.10</em:version> - <em:type>2</em:type> - <em:bootstrap>true</em:bootstrap> - <em:multiprocessCompatible>true</em:multiprocessCompatible> - - <!-- Target Application this theme can install into, - with minimum and maximum supported versions. --> - <em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>@MOZ_APP_VERSION@</em:minVersion> - <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion> - </Description> - </em:targetApplication> - - <!-- Front End MetaData --> - <em:name>Multi-process staged rollout</em:name> - <em:description>Staged rollout of Firefox multi-process feature.</em:description> - </Description> -</RDF> diff --git a/browser/extensions/e10srollout/moz.build b/browser/extensions/e10srollout/moz.build deleted file mode 100644 index 9b5a16d5a..000000000 --- a/browser/extensions/e10srollout/moz.build +++ /dev/null @@ -1,16 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION'] - -FINAL_TARGET_FILES.features['e10srollout@mozilla.org'] += [ - 'bootstrap.js' -] - -FINAL_TARGET_PP_FILES.features['e10srollout@mozilla.org'] += [ - 'install.rdf.in' -] diff --git a/browser/extensions/flyweb/bootstrap.js b/browser/extensions/flyweb/bootstrap.js deleted file mode 100644 index 089226519..000000000 --- a/browser/extensions/flyweb/bootstrap.js +++ /dev/null @@ -1,297 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", - "resource:///modules/CustomizableUI.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Console", - "resource://gre/modules/Console.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Services", - "resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Integration", - "resource://gre/modules/Integration.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PermissionUI", - "resource:///modules/PermissionUI.jsm"); - -XPCOMUtils.defineLazyGetter(this, "gFlyWebBundle", function() { - const tns = { - "flyweb-button.label": "FlyWeb", - "flyweb-button.tooltiptext": "Discover nearby FlyWeb services", - "flyweb-items-empty": "There are no FlyWeb services currently nearby" - }; - return { - GetStringFromName(name) { - return tns[name]; - } - }; -}); - -const FLYWEB_ENABLED_PREF = "dom.flyweb.enabled"; - -function install(aData, aReason) {} - -function uninstall(aData, aReason) {} - -function startup(aData, aReason) { - // Observe pref changes and enable/disable as necessary. - Services.prefs.addObserver(FLYWEB_ENABLED_PREF, prefObserver, false); - - // Only initialize if pref is enabled. - let enabled = Services.prefs.getBoolPref(FLYWEB_ENABLED_PREF); - if (enabled) { - FlyWebView.init(); - } -} - -function shutdown(aData, aReason) { - Services.prefs.removeObserver(FLYWEB_ENABLED_PREF, prefObserver); - - let enabled = Services.prefs.getBoolPref(FLYWEB_ENABLED_PREF); - if (enabled) { - FlyWebView.uninit(); - } -} - -// use enabled pref as a way for tests (e.g. test_contextmenu.html) to disable -// the addon when running. -function prefObserver(aSubject, aTopic, aData) { - let enabled = Services.prefs.getBoolPref(FLYWEB_ENABLED_PREF); - if (enabled) { - FlyWebView.init(); - } else { - FlyWebView.uninit(); - } -} - -let gDiscoveryManagerInstance; - -class DiscoveryManager { - constructor(aWindow) { - this._discoveryManager = new aWindow.FlyWebDiscoveryManager(); - } - - destroy() { - if (this._id) { - this.stop(); - } - - this._discoveryManager = null; - } - - start(callback) { - if (!this._id) { - this._id = this._discoveryManager.startDiscovery(this); - } - - this._callback = callback; - } - - stop() { - this._discoveryManager.stopDiscovery(this._id); - - this._id = null; - } - - pairWith(serviceId, callback) { - this._discoveryManager.pairWithService(serviceId, { - pairingSucceeded(service) { - callback(service); - }, - - pairingFailed(error) { - console.error("FlyWeb failed to pair with service " + serviceId, error); - } - }); - } - - onDiscoveredServicesChanged(services) { - if (!this._id || !this._callback) { - return; - } - - this._callback(services); - } -} - -const FlyWebPermissionPromptIntegration = (base) => ({ - __proto__: base, - createPermissionPrompt(type, request) { - if (type != "flyweb-publish-server") { - return super.createPermissionPrompt(...arguments); - } - - return { - __proto__: PermissionUI.PermissionPromptForRequestPrototype, - get request() { - return request; - }, - get permissionKey() { - return "flyweb-publish-server"; - }, - get popupOptions() { - return { - learnMoreURL: "https://flyweb.github.io", - popupIconURL: "chrome://flyweb/skin/icon-64.png", - }; - }, - get notificationID() { - return "flyweb-publish-server"; - }, - get anchorID() { - const kAnchorID = "flyweb-publish-server-notification-icon"; - let chromeDoc = this.browser.ownerDocument; - let anchor = chromeDoc.getElementById(kAnchorID); - if (!anchor) { - let notificationPopupBox = - chromeDoc.getElementById("notification-popup-box"); - let notificationIcon = chromeDoc.createElement("image"); - notificationIcon.id = kAnchorID; - notificationIcon.setAttribute("src", - "chrome://flyweb/skin/icon-64.png"); - notificationIcon.classList.add("notification-anchor-icon"); - notificationIcon.setAttribute("role", "button"); - notificationIcon.setAttribute("aria-label", - "View the publish-server request"); - notificationIcon.style.filter = - "url('chrome://browser/skin/filters.svg#fill')"; - notificationIcon.style.fill = "currentcolor"; - notificationIcon.style.opacity = "0.4"; - notificationPopupBox.appendChild(notificationIcon); - } - - return kAnchorID; - }, - get message() { - return "Would you like to let this site start a server accessible " + - "to nearby devices and people?"; - }, - get promptActions() { - return [{ - label: "Allow Server", - accessKey: "A", - action: Ci.nsIPermissionManager.ALLOW_ACTION, - expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, - }, { - label: "Block Server", - accessKey: "B", - action: Ci.nsIPermissionManager.DENY_ACTION, - expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, - }]; - }, - }; - }, -}); - -let FlyWebView = { - init() { - // Create widget and add it to the menu panel. - CustomizableUI.createWidget({ - id: "flyweb-button", - type: "view", - viewId: "flyweb-panel", - label: gFlyWebBundle.GetStringFromName("flyweb-button.label"), - tooltiptext: gFlyWebBundle.GetStringFromName("flyweb-button.tooltiptext"), - - onBeforeCreated(aDocument) { - let panel = aDocument.createElement("panelview"); - panel.id = "flyweb-panel"; - panel.setAttribute("class", "PanelUI-subView"); - panel.setAttribute("flex", "1"); - - let label = aDocument.createElement("label"); - label.setAttribute("class", "panel-subview-header"); - label.setAttribute("value", gFlyWebBundle.GetStringFromName("flyweb-button.label")); - - let empty = aDocument.createElement("description"); - empty.id = "flyweb-items-empty"; - empty.setAttribute("mousethrough", "always"); - empty.textContent = gFlyWebBundle.GetStringFromName("flyweb-items-empty"); - - let items = aDocument.createElement("vbox"); - items.id = "flyweb-items"; - items.setAttribute("class", "panel-subview-body"); - - panel.appendChild(label); - panel.appendChild(empty); - panel.appendChild(items); - - panel.addEventListener("command", this); - - aDocument.getElementById("PanelUI-multiView").appendChild(panel); - - this._sheetURI = Services.io.newURI("chrome://flyweb/skin/flyweb.css", null, null); - aDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIDOMWindowUtils).loadSheet(this._sheetURI, 1); - }, - - onDestroyed(aDocument) { - aDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIDOMWindowUtils).removeSheet(this._sheetURI, 1); - }, - - onViewShowing(aEvent) { - let doc = aEvent.target.ownerDocument; - - let items = doc.getElementById("flyweb-items"); - let empty = doc.getElementById("flyweb-items-empty"); - - if (!gDiscoveryManagerInstance) { - gDiscoveryManagerInstance = new DiscoveryManager(doc.defaultView); - } - - gDiscoveryManagerInstance.start((services) => { - while (items.firstChild) { - items.firstChild.remove(); - } - - let fragment = doc.createDocumentFragment(); - - for (let service of services) { - let button = doc.createElement("toolbarbutton"); - button.setAttribute("class", "subviewbutton cui-withicon"); - button.setAttribute("label", service.displayName); - button.setAttribute("data-service-id", service.serviceId); - fragment.appendChild(button); - } - - items.appendChild(fragment); - - empty.hidden = services.length > 0; - }); - }, - - onViewHiding(aEvent) { - gDiscoveryManagerInstance.stop(); - }, - - handleEvent(aEvent) { - if (aEvent.type === "command") { - let serviceId = aEvent.target.getAttribute("data-service-id"); - gDiscoveryManagerInstance.pairWith(serviceId, (service) => { - aEvent.view.openUILinkIn(service.uiUrl, "tab"); - }); - } - } - }); - - Integration.contentPermission - .register(FlyWebPermissionPromptIntegration); - }, - - uninit() { - CustomizableUI.destroyWidget("flyweb-button"); - - if (gDiscoveryManagerInstance) { - gDiscoveryManagerInstance.destroy(); - gDiscoveryManagerInstance = null; - } - - Integration.contentPermission - .unregister(FlyWebPermissionPromptIntegration); - } -}; diff --git a/browser/extensions/flyweb/install.rdf.in b/browser/extensions/flyweb/install.rdf.in deleted file mode 100644 index 17f746f9b..000000000 --- a/browser/extensions/flyweb/install.rdf.in +++ /dev/null @@ -1,32 +0,0 @@ -<?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/. --> - -#filter substitution - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>flyweb@mozilla.org</em:id> - <em:version>1.0.0</em:version> - <em:type>2</em:type> - <em:bootstrap>true</em:bootstrap> - <em:multiprocessCompatible>true</em:multiprocessCompatible> - - <!-- Target Application this theme can install into, - with minimum and maximum supported versions. --> - <em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>@MOZ_APP_VERSION@</em:minVersion> - <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion> - </Description> - </em:targetApplication> - - <!-- Front End MetaData --> - <em:name>FlyWeb</em:name> - <em:description>Discover nearby services in the browser</em:description> - </Description> -</RDF> diff --git a/browser/extensions/flyweb/jar.mn b/browser/extensions/flyweb/jar.mn deleted file mode 100644 index 8eed2135b..000000000 --- a/browser/extensions/flyweb/jar.mn +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -[features/flyweb@mozilla.org] chrome.jar: -% skin flyweb classic/1.0 %skin/linux/ -% skin flyweb classic/1.0 %skin/osx/ os=Darwin -% skin flyweb classic/1.0 %skin/windows/ os=WINNT -% skin flyweb-shared classic/1.0 %skin/shared/ - skin/ (skin/*) diff --git a/browser/extensions/flyweb/moz.build b/browser/extensions/flyweb/moz.build deleted file mode 100644 index 7f71bfb55..000000000 --- a/browser/extensions/flyweb/moz.build +++ /dev/null @@ -1,18 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION'] - -FINAL_TARGET_FILES.features['flyweb@mozilla.org'] += [ - 'bootstrap.js' -] - -FINAL_TARGET_PP_FILES.features['flyweb@mozilla.org'] += [ - 'install.rdf.in' -] - -JAR_MANIFESTS += ['jar.mn'] diff --git a/browser/extensions/flyweb/skin/flyweb-icon.svg b/browser/extensions/flyweb/skin/flyweb-icon.svg deleted file mode 100644 index 1b247e645..000000000 --- a/browser/extensions/flyweb/skin/flyweb-icon.svg +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" - width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve"> -<circle fill="#797C80" cx="32" cy="52" r="6"/> -<g> - <path fill="#797C80" d="M6.894,15.255c-2.254,1.547-4.386,3.304-6.361,5.279L0.18,20.887l3.536,3.536l0.354-0.354 - c1.621-1.62,3.363-3.072,5.196-4.369C8.126,18.464,7.296,16.943,6.894,15.255z"/> - <path fill="#797C80" d="M63.465,20.532C55.061,12.128,43.887,7.5,32,7.5c-2.265,0-4.504,0.17-6.703,0.501 - c0.822,1.44,1.3,3.1,1.312,4.87C28.382,12.631,30.181,12.5,32,12.5c10.55,0,20.468,4.108,27.928,11.567l0.354,0.354l3.537-3.535 - L63.465,20.532z"/> -</g> -<g> - <path fill="#797C80" d="M16.613,10.94c1.103,0,2,0.897,2,2s-0.897,2-2,2s-2-0.897-2-2S15.51,10.94,16.613,10.94 M16.613,6.94 - c-3.313,0-6,2.687-6,6s2.687,6,6,6s6-2.687,6-6S19.926,6.94,16.613,6.94L16.613,6.94z"/> -</g> -<g> - <path fill="#797C80" d="M46.492,37.502c-1.853-1.852-4.002-3.292-6.334-4.305c0.031,0.324,0.05,0.652,0.05,0.984 - c0,1.477-0.33,2.874-0.906,4.137c1.329,0.712,2.561,1.623,3.657,2.719l0.354,0.354l3.533-3.535L46.492,37.502z"/> - <path fill="#797C80" d="M20.262,35.207c-0.972,0.683-1.9,1.439-2.758,2.297l-0.354,0.354l3.536,3.537l0.354-0.354 - c0.35-0.35,0.715-0.679,1.091-0.99C21.118,38.66,20.446,37.007,20.262,35.207z"/> -</g> -<g> - <path fill="#797C80" d="M30.209,32.182c1.102,0,1.999,0.897,1.999,2s-0.896,2-1.999,2c-1.103,0-2-0.897-2-2 - S29.106,32.182,30.209,32.182 M30.209,28.182c-3.313,0-6,2.686-6,6c0,3.312,2.687,6,6,6c3.313,0,5.999-2.688,5.999-6 - C36.208,30.867,33.522,28.182,30.209,28.182L30.209,28.182z"/> -</g> -<g> - <path fill="#797C80" d="M32.207,23.716c0-1.497,0.34-2.912,0.932-4.188C32.76,19.515,32.381,19.5,32,19.5 - c-8.681,0-16.843,3.381-22.981,9.52l-0.354,0.354l3.535,3.535l0.354-0.354C17.748,27.36,24.654,24.5,32,24.5 - c0.083,0,0.165,0.005,0.247,0.006C32.227,24.245,32.207,23.982,32.207,23.716z"/> - <path fill="#797C80" d="M54.98,29.018c-0.987-0.987-2.033-1.896-3.119-2.738c-0.447,1.68-1.313,3.188-2.491,4.399 - c0.717,0.586,1.409,1.21,2.073,1.874l0.354,0.354l3.537-3.535L54.98,29.018z"/> -</g> -<g> - <path fill="#797C80" d="M42.207,21.716c1.103,0,2,0.897,2,2s-0.897,2-2,2s-2-0.897-2-2S41.104,21.716,42.207,21.716 M42.207,17.716 - c-3.313,0-6,2.687-6,6s2.687,6,6,6s6-2.687,6-6S45.521,17.716,42.207,17.716L42.207,17.716z"/> -</g> -</svg> diff --git a/browser/extensions/flyweb/skin/linux/flyweb.css b/browser/extensions/flyweb/skin/linux/flyweb.css deleted file mode 100644 index c549248da..000000000 --- a/browser/extensions/flyweb/skin/linux/flyweb.css +++ /dev/null @@ -1,5 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -@import url("chrome://flyweb-shared/skin/flyweb.css"); diff --git a/browser/extensions/flyweb/skin/linux/icon-16.png b/browser/extensions/flyweb/skin/linux/icon-16.png Binary files differdeleted file mode 100644 index 3a6c2e43a..000000000 --- a/browser/extensions/flyweb/skin/linux/icon-16.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/linux/icon-32-anchored.png b/browser/extensions/flyweb/skin/linux/icon-32-anchored.png Binary files differdeleted file mode 100644 index b05590dda..000000000 --- a/browser/extensions/flyweb/skin/linux/icon-32-anchored.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/linux/icon-32.png b/browser/extensions/flyweb/skin/linux/icon-32.png Binary files differdeleted file mode 100644 index a04ec20b9..000000000 --- a/browser/extensions/flyweb/skin/linux/icon-32.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/linux/icon-64-anchored.png b/browser/extensions/flyweb/skin/linux/icon-64-anchored.png Binary files differdeleted file mode 100644 index b617b9208..000000000 --- a/browser/extensions/flyweb/skin/linux/icon-64-anchored.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/linux/icon-64.png b/browser/extensions/flyweb/skin/linux/icon-64.png Binary files differdeleted file mode 100644 index be8ece467..000000000 --- a/browser/extensions/flyweb/skin/linux/icon-64.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/osx/flyweb.css b/browser/extensions/flyweb/skin/osx/flyweb.css deleted file mode 100644 index c549248da..000000000 --- a/browser/extensions/flyweb/skin/osx/flyweb.css +++ /dev/null @@ -1,5 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -@import url("chrome://flyweb-shared/skin/flyweb.css"); diff --git a/browser/extensions/flyweb/skin/osx/icon-16.png b/browser/extensions/flyweb/skin/osx/icon-16.png Binary files differdeleted file mode 100644 index 7c87435a4..000000000 --- a/browser/extensions/flyweb/skin/osx/icon-16.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/osx/icon-32-anchored.png b/browser/extensions/flyweb/skin/osx/icon-32-anchored.png Binary files differdeleted file mode 100644 index b05590dda..000000000 --- a/browser/extensions/flyweb/skin/osx/icon-32-anchored.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/osx/icon-32.png b/browser/extensions/flyweb/skin/osx/icon-32.png Binary files differdeleted file mode 100644 index 5b0140ffa..000000000 --- a/browser/extensions/flyweb/skin/osx/icon-32.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/osx/icon-64-anchored.png b/browser/extensions/flyweb/skin/osx/icon-64-anchored.png Binary files differdeleted file mode 100644 index b617b9208..000000000 --- a/browser/extensions/flyweb/skin/osx/icon-64-anchored.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/osx/icon-64.png b/browser/extensions/flyweb/skin/osx/icon-64.png Binary files differdeleted file mode 100644 index eb67c29ec..000000000 --- a/browser/extensions/flyweb/skin/osx/icon-64.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/shared/flyweb.css b/browser/extensions/flyweb/skin/shared/flyweb.css deleted file mode 100644 index acc8a743d..000000000 --- a/browser/extensions/flyweb/skin/shared/flyweb.css +++ /dev/null @@ -1,54 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#flyweb-panel { - width: 20em; -} - -#flyweb-items-empty { - box-sizing: border-box; - color: GrayText; - padding: 10px 20px; - text-align: center; -} - -#flyweb-button { - list-style-image: url("chrome://flyweb/skin/icon-16.png"); -} - -#flyweb-button[cui-areatype="menu-panel"], -toolbarpaletteitem[place="palette"] > #flyweb-button { - list-style-image: url("chrome://flyweb/skin/icon-32.png"); -} - -#flyweb-button[cui-areatype="menu-panel"][panel-multiview-anchor="true"] { - list-style-image: url("chrome://flyweb/skin/icon-32-anchored.png"); -} - -#flyweb-items > toolbarbutton { - list-style-image: url("chrome://flyweb/skin/icon-16.png"); -} - -@media (min-resolution: 2dppx) { - #flyweb-button { - list-style-image: url("chrome://flyweb/skin/icon-32.png"); - } - - #flyweb-button[cui-areatype="menu-panel"], - toolbarpaletteitem[place="palette"] > #flyweb-button { - list-style-image: url("chrome://flyweb/skin/icon-64.png"); - } - - #flyweb-button[cui-areatype="menu-panel"][panel-multiview-anchor="true"] { - list-style-image: url("chrome://flyweb/skin/icon-64-anchored.png"); - } - - #flyweb-items > toolbarbutton { - list-style-image: url("chrome://flyweb/skin/icon-32.png"); - } - - #flyweb-items > toolbarbutton > .toolbarbutton-icon { - width: 16px; - } -} diff --git a/browser/extensions/flyweb/skin/windows/icon-16.png b/browser/extensions/flyweb/skin/windows/icon-16.png Binary files differdeleted file mode 100644 index 3a6c2e43a..000000000 --- a/browser/extensions/flyweb/skin/windows/icon-16.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/windows/icon-32-anchored.png b/browser/extensions/flyweb/skin/windows/icon-32-anchored.png Binary files differdeleted file mode 100644 index b05590dda..000000000 --- a/browser/extensions/flyweb/skin/windows/icon-32-anchored.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/windows/icon-32.png b/browser/extensions/flyweb/skin/windows/icon-32.png Binary files differdeleted file mode 100644 index a04ec20b9..000000000 --- a/browser/extensions/flyweb/skin/windows/icon-32.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/windows/icon-64-anchored.png b/browser/extensions/flyweb/skin/windows/icon-64-anchored.png Binary files differdeleted file mode 100644 index b617b9208..000000000 --- a/browser/extensions/flyweb/skin/windows/icon-64-anchored.png +++ /dev/null diff --git a/browser/extensions/flyweb/skin/windows/icon-64.png b/browser/extensions/flyweb/skin/windows/icon-64.png Binary files differdeleted file mode 100644 index be8ece467..000000000 --- a/browser/extensions/flyweb/skin/windows/icon-64.png +++ /dev/null diff --git a/browser/extensions/formautofill/.eslintrc.js b/browser/extensions/formautofill/.eslintrc.js deleted file mode 100644 index ec89029e5..000000000 --- a/browser/extensions/formautofill/.eslintrc.js +++ /dev/null @@ -1,474 +0,0 @@ -"use strict"; - -module.exports = { // eslint-disable-line no-undef - "extends": "../../.eslintrc.js", - - "globals": { - "Components": true, - "dump": true, - "TextDecoder": false, - "TextEncoder": false, - }, - - "rules": { - // Rules from the mozilla plugin - "mozilla/balanced-listeners": "error", - "mozilla/no-aArgs": "warn", - "mozilla/no-cpows-in-tests": "warn", - "mozilla/var-only-at-top-level": "warn", - - "valid-jsdoc": ["error", { - "prefer": { - "return": "returns", - }, - "preferType": { - "Boolean": "boolean", - "Number": "number", - "String": "string", - "bool": "boolean", - }, - "requireParamDescription": false, - "requireReturn": false, - "requireReturnDescription": false, - }], - - // Braces only needed for multi-line arrow function blocks - // "arrow-body-style": ["error", "as-needed"], - - // Require spacing around => - "arrow-spacing": "error", - - // Always require spacing around a single line block - "block-spacing": "warn", - - // Forbid spaces inside the square brackets of array literals. - "array-bracket-spacing": ["error", "never"], - - // Forbid spaces inside the curly brackets of object literals. - "object-curly-spacing": ["error", "never"], - - // No space padding in parentheses - "space-in-parens": ["error", "never"], - - // Enforce one true brace style (opening brace on the same line) and avoid - // start and end braces on the same line. - "brace-style": ["error", "1tbs", {"allowSingleLine": true}], - - // No space before always a space after a comma - "comma-spacing": ["error", {"before": false, "after": true}], - - // Commas at the end of the line not the start - "comma-style": "error", - - // Don't require spaces around computed properties - "computed-property-spacing": ["warn", "never"], - - // Functions are not required to consistently return something or nothing - "consistent-return": "off", - - // Require braces around blocks that start a new line - "curly": ["error", "all"], - - // Always require a trailing EOL - "eol-last": "error", - - // Require function* name() - "generator-star-spacing": ["error", {"before": false, "after": true}], - - // Two space indent - "indent": ["error", 2, {"SwitchCase": 1}], - - // Space after colon not before in property declarations - "key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "minimum"}], - - // Require spaces before and after finally, catch, etc. - "keyword-spacing": "error", - - // Unix linebreaks - "linebreak-style": ["error", "unix"], - - // Always require parenthesis for new calls - "new-parens": "error", - - // Use [] instead of Array() - "no-array-constructor": "error", - - // No duplicate arguments in function declarations - "no-dupe-args": "error", - - // No duplicate keys in object declarations - "no-dupe-keys": "error", - - // No duplicate cases in switch statements - "no-duplicate-case": "error", - - // If an if block ends with a return no need for an else block - // "no-else-return": "error", - - // Disallow empty statements. This will report an error for: - // try { something(); } catch (e) {} - // but will not report it for: - // try { something(); } catch (e) { /* Silencing the error because ...*/ } - // which is a valid use case. - "no-empty": "error", - - // No empty character classes in regex - "no-empty-character-class": "error", - - // Disallow empty destructuring - "no-empty-pattern": "error", - - // No assiging to exception variable - "no-ex-assign": "error", - - // No using !! where casting to boolean is already happening - "no-extra-boolean-cast": "warn", - - // No double semicolon - "no-extra-semi": "error", - - // No overwriting defined functions - "no-func-assign": "error", - - // No invalid regular expresions - "no-invalid-regexp": "error", - - // No odd whitespace characters - "no-irregular-whitespace": "error", - - // No single if block inside an else block - "no-lonely-if": "warn", - - // No mixing spaces and tabs in indent - "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], - - // Disallow use of multiple spaces (sometimes used to align const values, - // array or object items, etc.). It's hard to maintain and doesn't add that - // much benefit. - "no-multi-spaces": "warn", - - // No reassigning native JS objects - "no-native-reassign": "error", - - // No (!foo in bar) - "no-negated-in-lhs": "error", - - // Nested ternary statements are confusing - "no-nested-ternary": "error", - - // Use {} instead of new Object() - "no-new-object": "error", - - // No Math() or JSON() - "no-obj-calls": "error", - - // No octal literals - "no-octal": "error", - - // No redeclaring variables - "no-redeclare": "error", - - // No unnecessary comparisons - "no-self-compare": "error", - - // No spaces between function name and parentheses - "no-spaced-func": "warn", - - // No trailing whitespace - "no-trailing-spaces": "error", - - // Error on newline where a semicolon is needed - "no-unexpected-multiline": "error", - - // No unreachable statements - "no-unreachable": "error", - - // No expressions where a statement is expected - "no-unused-expressions": "error", - - // No declaring variables that are never used - "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}], - - // No using variables before defined - "no-use-before-define": "error", - - // No using with - "no-with": "error", - - // Always require semicolon at end of statement - "semi": ["error", "always"], - - // Require space before blocks - "space-before-blocks": "error", - - // Never use spaces before function parentheses - "space-before-function-paren": ["error", {"anonymous": "never", "named": "never"}], - - // Require spaces around operators, except for a|"off". - "space-infix-ops": ["error", {"int32Hint": true}], - - // ++ and -- should not need spacing - "space-unary-ops": ["warn", {"nonwords": false}], - - // No comparisons to NaN - "use-isnan": "error", - - // Only check typeof against valid results - "valid-typeof": "error", - - // Disallow using variables outside the blocks they are defined (especially - // since only let and const are used, see "no-var"). - "block-scoped-var": "error", - - // Allow trailing commas for easy list extension. Having them does not - // impair readability, but also not required either. - "comma-dangle": ["error", "always-multiline"], - - // Warn about cyclomatic complexity in functions. - "complexity": "warn", - - // Don't warn for inconsistent naming when capturing this (not so important - // with auto-binding fat arrow functions). - // "consistent-this": ["error", "self"], - - // Don't require a default case in switch statements. Avoid being forced to - // add a bogus default when you know all possible cases are handled. - "default-case": "off", - - // Enforce dots on the next line with property name. - "dot-location": ["error", "property"], - - // Encourage the use of dot notation whenever possible. - "dot-notation": "error", - - // Allow using == instead of ===, in the interest of landing something since - // the devtools codebase is split on convention here. - "eqeqeq": "off", - - // Don't require function expressions to have a name. - // This makes the code more verbose and hard to read. Our engine already - // does a fantastic job assigning a name to the function, which includes - // the enclosing function name, and worst case you have a line number that - // you can just look up. - "func-names": "off", - - // Allow use of function declarations and expressions. - "func-style": "off", - - // Don't enforce the maximum depth that blocks can be nested. The complexity - // rule is a better rule to check this. - "max-depth": "off", - - // Maximum length of a line. - // Disabled because we exceed this in too many places. - "max-len": ["off", 80], - - // Maximum depth callbacks can be nested. - "max-nested-callbacks": ["error", 4], - - // Don't limit the number of parameters that can be used in a function. - "max-params": "off", - - // Don't limit the maximum number of statement allowed in a function. We - // already have the complexity rule that's a better measurement. - "max-statements": "off", - - // Don't require a capital letter for constructors, only check if all new - // operators are followed by a capital letter. Don't warn when capitalized - // functions are used without the new operator. - "new-cap": ["off", {"capIsNew": false}], - - // Allow use of bitwise operators. - "no-bitwise": "off", - - // Disallow use of arguments.caller or arguments.callee. - "no-caller": "error", - - // Disallow the catch clause parameter name being the same as a variable in - // the outer scope, to avoid confusion. - "no-catch-shadow": "off", - - // Disallow assignment in conditional expressions. - "no-cond-assign": "error", - - // Disallow using the console API. - "no-console": "error", - - // Allow using constant expressions in conditions like while (true) - "no-constant-condition": "off", - - // Allow use of the continue statement. - "no-continue": "off", - - // Disallow control characters in regular expressions. - "no-control-regex": "error", - - // Disallow use of debugger. - "no-debugger": "error", - - // Disallow deletion of variables (deleting properties is fine). - "no-delete-var": "error", - - // Allow division operators explicitly at beginning of regular expression. - "no-div-regex": "off", - - // Disallow use of eval(). We have other APIs to evaluate code in content. - "no-eval": "error", - - // Disallow adding to native types - "no-extend-native": "error", - - // Disallow unnecessary function binding. - "no-extra-bind": "error", - - // Allow unnecessary parentheses, as they may make the code more readable. - "no-extra-parens": "off", - - // Disallow fallthrough of case statements, except if there is a comment. - "no-fallthrough": "error", - - // Allow the use of leading or trailing decimal points in numeric literals. - "no-floating-decimal": "off", - - // Allow comments inline after code. - "no-inline-comments": "off", - - // Disallow use of labels for anything other then loops and switches. - "no-labels": ["error", {"allowLoop": true}], - - // Disallow use of multiline strings (use template strings instead). - "no-multi-str": "warn", - - // Disallow multiple empty lines. - "no-multiple-empty-lines": ["warn", {"max": 2}], - - // Allow reassignment of function parameters. - "no-param-reassign": "off", - - // Allow string concatenation with __dirname and __filename (not a node env). - "no-path-concat": "off", - - // Allow use of unary operators, ++ and --. - "no-plusplus": "off", - - // Allow using process.env (not a node environment). - "no-process-env": "off", - - // Allow using process.exit (not a node environment). - "no-process-exit": "off", - - // Disallow usage of __proto__ property. - "no-proto": "error", - - // Disallow multiple spaces in a regular expression literal. - "no-regex-spaces": "error", - - // Allow reserved words being used as object literal keys. - "no-reserved-keys": "off", - - // Don't restrict usage of specified node modules (not a node environment). - "no-restricted-modules": "off", - - // Disallow use of assignment in return statement. It is preferable for a - // single line of code to have only one easily predictable effect. - "no-return-assign": "error", - - // Don't warn about declaration of variables already declared in the outer scope. - "no-shadow": "off", - - // Disallow shadowing of names such as arguments. - "no-shadow-restricted-names": "error", - - // Allow use of synchronous methods (not a node environment). - "no-sync": "off", - - // Allow the use of ternary operators. - "no-ternary": "off", - - // Disallow throwing literals (eg. throw "error" instead of - // throw new Error("error")). - "no-throw-literal": "error", - - // Disallow use of undeclared variables unless mentioned in a /* global */ - // block. Note that globals from head.js are automatically imported in tests - // by the import-headjs-globals rule form the mozilla eslint plugin. - "no-undef": "error", - - // Allow dangling underscores in identifiers (for privates). - "no-underscore-dangle": "off", - - // Allow use of undefined variable. - "no-undefined": "off", - - // Disallow the use of Boolean literals in conditional expressions. - "no-unneeded-ternary": "error", - - // We use var-only-at-top-level instead of no-var as we allow top level - // vars. - "no-var": "off", - - // Allow using TODO/FIXME comments. - "no-warning-comments": "off", - - // Don't require method and property shorthand syntax for object literals. - // We use this in the code a lot, but not consistently, and this seems more - // like something to check at code review time. - "object-shorthand": "off", - - // Allow more than one variable declaration per function. - "one-var": "off", - - // Disallow padding within blocks. - "padded-blocks": ["warn", "never"], - - // Don't require quotes around object literal property names. - "quote-props": "off", - - // Double quotes should be used. - "quotes": ["warn", "double", {"avoidEscape": true, "allowTemplateLiterals": true}], - - // Require use of the second argument for parseInt(). - "radix": "error", - - // Enforce spacing after semicolons. - "semi-spacing": ["error", {"before": false, "after": true}], - - // Don't require to sort variables within the same declaration block. - // Anyway, one-var is disabled. - "sort-vars": "off", - - // Require a space immediately following the // in a line comment. - "spaced-comment": ["error", "always"], - - // Require "use strict" to be defined globally in the script. - "strict": ["error", "global"], - - // Allow vars to be declared anywhere in the scope. - "vars-on-top": "off", - - // Don't require immediate function invocation to be wrapped in parentheses. - "wrap-iife": "off", - - // Don't require regex literals to be wrapped in parentheses (which - // supposedly prevent them from being mistaken for division operators). - "wrap-regex": "off", - - // Disallow Yoda conditions (where literal value comes first). - "yoda": "error", - - // disallow use of eval()-like methods - "no-implied-eval": "error", - - // Disallow function or variable declarations in nested blocks - "no-inner-declarations": "error", - - // Disallow usage of __iterator__ property - "no-iterator": "error", - - // Disallow labels that share a name with a variable - "no-label-var": "error", - - // Disallow creating new instances of String, Number, and Boolean - "no-new-wrappers": "error", - }, -}; diff --git a/browser/extensions/formautofill/bootstrap.js b/browser/extensions/formautofill/bootstrap.js deleted file mode 100644 index 0b3f355bd..000000000 --- a/browser/extensions/formautofill/bootstrap.js +++ /dev/null @@ -1,12 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -/* exported startup, shutdown, install, uninstall */ - -function startup() {} -function shutdown() {} -function install() {} -function uninstall() {} diff --git a/browser/extensions/formautofill/content/FormAutofillContent.jsm b/browser/extensions/formautofill/content/FormAutofillContent.jsm deleted file mode 100644 index bde397580..000000000 --- a/browser/extensions/formautofill/content/FormAutofillContent.jsm +++ /dev/null @@ -1,134 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Implements a service used by DOM content to request Form Autofill. - */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -/** - * Handles profile autofill for a DOM Form element. - * @param {HTMLFormElement} form Form that need to be auto filled - */ -function FormAutofillHandler(form) { - this.form = form; - this.fieldDetails = []; -} - -FormAutofillHandler.prototype = { - /** - * DOM Form element to which this object is attached. - */ - form: null, - - /** - * Array of collected data about relevant form fields. Each item is an object - * storing the identifying details of the field and a reference to the - * originally associated element from the form. - * - * The "section", "addressType", "contactType", and "fieldName" values are - * used to identify the exact field when the serializable data is received - * from the backend. There cannot be multiple fields which have - * the same exact combination of these values. - * - * A direct reference to the associated element cannot be sent to the user - * interface because processing may be done in the parent process. - */ - fieldDetails: null, - - /** - * Returns information from the form about fields that can be autofilled, and - * populates the fieldDetails array on this object accordingly. - * - * @returns {Array<Object>} Serializable data structure that can be sent to the user - * interface, or null if the operation failed because the constraints - * on the allowed fields were not honored. - */ - collectFormFields() { - let autofillData = []; - - for (let element of this.form.elements) { - // Query the interface and exclude elements that cannot be autocompleted. - if (!(element instanceof Ci.nsIDOMHTMLInputElement)) { - continue; - } - - // Exclude elements to which no autocomplete field has been assigned. - let info = element.getAutocompleteInfo(); - if (!info.fieldName || ["on", "off"].includes(info.fieldName)) { - continue; - } - - // Store the association between the field metadata and the element. - if (this.fieldDetails.some(f => f.section == info.section && - f.addressType == info.addressType && - f.contactType == info.contactType && - f.fieldName == info.fieldName)) { - // A field with the same identifier already exists. - return null; - } - - let inputFormat = { - section: info.section, - addressType: info.addressType, - contactType: info.contactType, - fieldName: info.fieldName, - }; - // Clone the inputFormat for caching the fields and elements together - let formatWithElement = Object.assign({}, inputFormat); - - inputFormat.index = autofillData.length; - autofillData.push(inputFormat); - - formatWithElement.element = element; - this.fieldDetails.push(formatWithElement); - } - - return autofillData; - }, - - /** - * Processes form fields that can be autofilled, and populates them with the - * data provided by backend. - * - * @param {Array<Object>} autofillResult - * Data returned by the user interface. - * [{ - * section: Value originally provided to the user interface. - * addressType: Value originally provided to the user interface. - * contactType: Value originally provided to the user interface. - * fieldName: Value originally provided to the user interface. - * value: String with which the field should be updated. - * index: Index to match the input in fieldDetails - * }], - * } - */ - autofillFormFields(autofillResult) { - for (let field of autofillResult) { - // Get the field details, if it was processed by the user interface. - let fieldDetail = this.fieldDetails[field.index]; - - // Avoid the invalid value set - if (!fieldDetail || !field.value) { - continue; - } - - let info = fieldDetail.element.getAutocompleteInfo(); - if (field.section != info.section || - field.addressType != info.addressType || - field.contactType != info.contactType || - field.fieldName != info.fieldName) { - Cu.reportError("Autocomplete tokens mismatched"); - continue; - } - - fieldDetail.element.setUserInput(field.value); - } - }, -}; - -this.EXPORTED_SYMBOLS = ["FormAutofillHandler"]; diff --git a/browser/extensions/formautofill/content/FormAutofillParent.jsm b/browser/extensions/formautofill/content/FormAutofillParent.jsm deleted file mode 100644 index bdfe0f478..000000000 --- a/browser/extensions/formautofill/content/FormAutofillParent.jsm +++ /dev/null @@ -1,173 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Implements a service used to access storage and communicate with content. - * - * A "fields" array is used to communicate with FormAutofillContent. Each item - * represents a single input field in the content page as well as its - * @autocomplete properties. The schema is as below. Please refer to - * FormAutofillContent.jsm for more details. - * - * [ - * { - * section, - * addressType, - * contactType, - * fieldName, - * value, - * index - * }, - * { - * // ... - * } - * ] - */ - -/* exported FormAutofillParent */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "OS", - "resource://gre/modules/osfile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ProfileStorage", - "resource://formautofill/ProfileStorage.jsm"); - -const PROFILE_JSON_FILE_NAME = "autofill-profiles.json"; - -let FormAutofillParent = { - _profileStore: null, - - /** - * Initializes ProfileStorage and registers the message handler. - */ - init: function() { - let storePath = - OS.Path.join(OS.Constants.Path.profileDir, PROFILE_JSON_FILE_NAME); - - this._profileStore = new ProfileStorage(storePath); - this._profileStore.initialize(); - - let mm = Cc["@mozilla.org/globalmessagemanager;1"] - .getService(Ci.nsIMessageListenerManager); - mm.addMessageListener("FormAutofill:PopulateFieldValues", this); - }, - - /** - * Handles the message coming from FormAutofillContent. - * - * @param {string} message.name The name of the message. - * @param {object} message.data The data of the message. - * @param {nsIFrameMessageManager} message.target Caller's message manager. - */ - receiveMessage: function({name, data, target}) { - switch (name) { - case "FormAutofill:PopulateFieldValues": - this._populateFieldValues(data, target); - break; - } - }, - - /** - * Returns the instance of ProfileStorage. To avoid syncing issues, anyone - * who needs to access the profile should request the instance by this instead - * of creating a new one. - * - * @returns {ProfileStorage} - */ - getProfileStore: function() { - return this._profileStore; - }, - - /** - * Uninitializes FormAutofillParent. This is for testing only. - * - * @private - */ - _uninit: function() { - if (this._profileStore) { - this._profileStore._saveImmediately(); - this._profileStore = null; - } - - let mm = Cc["@mozilla.org/globalmessagemanager;1"] - .getService(Ci.nsIMessageListenerManager); - mm.removeMessageListener("FormAutofill:PopulateFieldValues", this); - }, - - /** - * Populates the field values and notifies content to fill in. Exception will - * be thrown if there's no matching profile. - * - * @private - * @param {string} data.guid - * Indicates which profile to populate - * @param {Fields} data.fields - * The "fields" array collected from content. - * @param {nsIFrameMessageManager} target - * Content's message manager. - */ - _populateFieldValues({guid, fields}, target) { - this._profileStore.notifyUsed(guid); - this._fillInFields(this._profileStore.get(guid), fields); - target.sendAsyncMessage("FormAutofill:fillForm", {fields}); - }, - - /** - * Transforms a word with hyphen into camel case. - * (e.g. transforms "address-type" into "addressType".) - * - * @private - * @param {string} str The original string with hyphen. - * @returns {string} The camel-cased output string. - */ - _camelCase(str) { - return str.toLowerCase().replace(/-([a-z])/g, s => s[1].toUpperCase()); - }, - - /** - * Get the corresponding value from the specified profile according to a valid - * @autocomplete field name. - * - * Note that the field name doesn't need to match the property name defined in - * Profile object. This method can transform the raw data to fulfill it. (e.g. - * inputting "country-name" as "fieldName" will get a full name transformed - * from the country code that is recorded in "country" field.) - * - * @private - * @param {Profile} profile The specified profile. - * @param {string} fieldName A valid @autocomplete field name. - * @returns {string} The corresponding value. Returns "undefined" if there's - * no matching field. - */ - _getDataByFieldName(profile, fieldName) { - let key = this._camelCase(fieldName); - - // TODO: Transform the raw profile data to fulfill "fieldName" here. - - return profile[key]; - }, - - /** - * Fills in the "fields" array by the specified profile. - * - * @private - * @param {Profile} profile The specified profile to fill in. - * @param {Fields} fields The "fields" array collected from content. - */ - _fillInFields(profile, fields) { - for (let field of fields) { - let value = this._getDataByFieldName(profile, field.fieldName); - if (value !== undefined) { - field.value = value; - } - } - }, -}; - -this.EXPORTED_SYMBOLS = ["FormAutofillParent"]; diff --git a/browser/extensions/formautofill/content/ProfileStorage.jsm b/browser/extensions/formautofill/content/ProfileStorage.jsm deleted file mode 100644 index 843177d4e..000000000 --- a/browser/extensions/formautofill/content/ProfileStorage.jsm +++ /dev/null @@ -1,251 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Implements an interface of the storage of Form Autofill. - * - * The data is stored in JSON format, without indentation, using UTF-8 encoding. - * With indentation applied, the file would look like this: - * - * { - * version: 1, - * profiles: [ - * { - * guid, // 12 character... - * - * // profile - * organization, // Company - * streetAddress, // (Multiline) - * addressLevel2, // City/Town - * addressLevel1, // Province (Standardized code if possible) - * postalCode, - * country, // ISO 3166 - * tel, - * email, - * - * // metadata - * timeCreated, // in ms - * timeLastUsed, // in ms - * timeLastModified, // in ms - * timesUsed - * }, - * { - * // ... - * } - * ] - * } - */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "JSONFile", - "resource://gre/modules/JSONFile.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -const SCHEMA_VERSION = 1; - -// Name-related fields will be handled in follow-up bugs due to the complexity. -const VALID_FIELDS = [ - "organization", - "streetAddress", - "addressLevel2", - "addressLevel1", - "postalCode", - "country", - "tel", - "email", -]; - -function ProfileStorage(path) { - this._path = path; -} - -ProfileStorage.prototype = { - /** - * Loads the profile data from file to memory. - * - * @returns {Promise} - * @resolves When the operation finished successfully. - * @rejects JavaScript exception. - */ - initialize() { - this._store = new JSONFile({ - path: this._path, - dataPostProcessor: this._dataPostProcessor.bind(this), - }); - return this._store.load(); - }, - - /** - * Adds a new profile. - * - * @param {Profile} profile - * The new profile for saving. - */ - add(profile) { - this._store.ensureDataReady(); - - let profileToSave = this._normalizeProfile(profile); - - profileToSave.guid = gUUIDGenerator.generateUUID().toString() - .replace(/[{}-]/g, "").substring(0, 12); - - // Metadata - let now = Date.now(); - profileToSave.timeCreated = now; - profileToSave.timeLastModified = now; - profileToSave.timeLastUsed = 0; - profileToSave.timesUsed = 0; - - this._store.data.profiles.push(profileToSave); - - this._store.saveSoon(); - }, - - /** - * Update the specified profile. - * - * @param {string} guid - * Indicates which profile to update. - * @param {Profile} profile - * The new profile used to overwrite the old one. - */ - update(guid, profile) { - this._store.ensureDataReady(); - - let profileFound = this._findByGUID(guid); - if (!profileFound) { - throw new Error("No matching profile."); - } - - let profileToUpdate = this._normalizeProfile(profile); - for (let field of VALID_FIELDS) { - if (profileToUpdate[field] !== undefined) { - profileFound[field] = profileToUpdate[field]; - } else { - delete profileFound[field]; - } - } - - profileFound.timeLastModified = Date.now(); - - this._store.saveSoon(); - }, - - /** - * Notifies the stroage of the use of the specified profile, so we can update - * the metadata accordingly. - * - * @param {string} guid - * Indicates which profile to be notified. - */ - notifyUsed(guid) { - this._store.ensureDataReady(); - - let profileFound = this._findByGUID(guid); - if (!profileFound) { - throw new Error("No matching profile."); - } - - profileFound.timesUsed++; - profileFound.timeLastUsed = Date.now(); - - this._store.saveSoon(); - }, - - /** - * Removes the specified profile. No error occurs if the profile isn't found. - * - * @param {string} guid - * Indicates which profile to remove. - */ - remove(guid) { - this._store.ensureDataReady(); - - this._store.data.profiles = - this._store.data.profiles.filter(profile => profile.guid != guid); - this._store.saveSoon(); - }, - - /** - * Returns the profile with the specified GUID. - * - * @param {string} guid - * Indicates which profile to retrieve. - * @returns {Profile} - * A clone of the profile. - */ - get(guid) { - this._store.ensureDataReady(); - - let profileFound = this._findByGUID(guid); - if (!profileFound) { - throw new Error("No matching profile."); - } - - // Profile is cloned to avoid accidental modifications from outside. - return this._clone(profileFound); - }, - - /** - * Returns all profiles. - * - * @returns {Array.<Profile>} - * An array containing clones of all profiles. - */ - getAll() { - this._store.ensureDataReady(); - - // Profiles are cloned to avoid accidental modifications from outside. - return this._store.data.profiles.map(this._clone); - }, - - _clone(profile) { - return Object.assign({}, profile); - }, - - _findByGUID(guid) { - return this._store.data.profiles.find(profile => profile.guid == guid); - }, - - _normalizeProfile(profile) { - let result = {}; - for (let key in profile) { - if (!VALID_FIELDS.includes(key)) { - throw new Error(`"${key}" is not a valid field.`); - } - if (typeof profile[key] !== "string" && - typeof profile[key] !== "number") { - throw new Error(`"${key}" contains invalid data type.`); - } - - result[key] = profile[key]; - } - return result; - }, - - _dataPostProcessor(data) { - data.version = SCHEMA_VERSION; - if (!data.profiles) { - data.profiles = []; - } - return data; - }, - - // For test only. - _saveImmediately() { - return this._store._save(); - }, -}; - -this.EXPORTED_SYMBOLS = ["ProfileStorage"]; diff --git a/browser/extensions/formautofill/install.rdf.in b/browser/extensions/formautofill/install.rdf.in deleted file mode 100644 index 5e34051ba..000000000 --- a/browser/extensions/formautofill/install.rdf.in +++ /dev/null @@ -1,32 +0,0 @@ -<?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/. --> - -#filter substitution - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>formautofill@mozilla.org</em:id> - <em:version>1.0</em:version> - <em:type>2</em:type> - <em:bootstrap>true</em:bootstrap> - <em:multiprocessCompatible>true</em:multiprocessCompatible> - - <!-- Target Application this extension can install into, - with minimum and maximum supported versions. --> - <em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>@MOZ_APP_VERSION@</em:minVersion> - <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion> - </Description> - </em:targetApplication> - - <!-- Front End MetaData --> - <em:name>Form Autofill</em:name> - <em:description>Autofill forms with saved profiles</em:description> - </Description> -</RDF> diff --git a/browser/extensions/formautofill/moz.build b/browser/extensions/formautofill/moz.build deleted file mode 100644 index abcc659ee..000000000 --- a/browser/extensions/formautofill/moz.build +++ /dev/null @@ -1,18 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION'] - -FINAL_TARGET_FILES.features['formautofill@mozilla.org'] += [ - 'bootstrap.js' -] - -FINAL_TARGET_PP_FILES.features['formautofill@mozilla.org'] += [ - 'install.rdf.in' -] - -JAR_MANIFESTS += ['jar.mn'] diff --git a/browser/extensions/moz.build b/browser/extensions/moz.build index 4f95704e6..69d6af6d6 100644 --- a/browser/extensions/moz.build +++ b/browser/extensions/moz.build @@ -5,16 +5,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DIRS += [ -# 'aushelper', -# 'e10srollout', 'pdfjs', -# 'pocket', -# 'webcompat', ] -# Only include the following system add-ons if building Aurora or Nightly -if 'a' in CONFIG['GRE_MILESTONE']: - DIRS += [ - 'flyweb', - 'formautofill', - ] diff --git a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm index 3b9f9de26..5e337bbc5 100644 --- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm +++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm @@ -29,7 +29,8 @@ const MOZ_CENTRAL = JSON.parse('true'); const PDFJS_EVENT_ID = 'pdf.js.message'; const PDF_CONTENT_TYPE = 'application/pdf'; const PREF_PREFIX = 'pdfjs'; -const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html'; +const PDF_VIEWER_ORIGIN = "resource://pdf.js"; +const PDF_VIEWER_WEB_PAGE = "resource://pdf.js/web/viewer.html"; const MAX_NUMBER_OF_PREFS = 50; const MAX_STRING_PREF_LENGTH = 128; @@ -110,11 +111,15 @@ function log(aMsg) { dump(msg + '\n'); } -function getDOMWindow(aChannel) { +function getDOMWindow(aChannel, aPrincipal) { var requestor = aChannel.notificationCallbacks ? aChannel.notificationCallbacks : aChannel.loadGroup.notificationCallbacks; var win = requestor.getInterface(Components.interfaces.nsIDOMWindow); + // Ensure the window wasn't navigated to something that is not PDF.js. + if (!win.document.nodePrincipal.equals(aPrincipal)) { + return null; + } return win; } @@ -632,7 +637,7 @@ var RangedChromeActions = (function RangedChromeActionsClosure() { loaded: loaded, total: total, chunk: self.dataListener.readData() - }, '*'); + }, PDF_VIEWER_ORIGIN); }; this.dataListener.oncomplete = function () { self.dataListener = null; @@ -646,7 +651,7 @@ var RangedChromeActions = (function RangedChromeActionsClosure() { pdfUrl: this.pdfUrl, length: this.contentLength, data: data - }, '*'); + }, PDF_VIEWER_ORIGIN); return true; }; @@ -668,13 +673,13 @@ var RangedChromeActions = (function RangedChromeActionsClosure() { pdfjsLoadAction: 'range', begin: args.begin, chunk: args.chunk - }, '*'); + }, PDF_VIEWER_ORIGIN); }, onProgress: function RangedChromeActions_onProgress(evt) { domWindow.postMessage({ pdfjsLoadAction: 'rangeProgress', loaded: evt.loaded, - }, '*'); + }, PDF_VIEWER_ORIGIN); } }); }; @@ -723,7 +728,7 @@ var StandardChromeActions = (function StandardChromeActionsClosure() { pdfjsLoadAction: 'progress', loaded: loaded, total: total - }, '*'); + }, PDF_VIEWER_ORIGIN); }; this.dataListener.oncomplete = @@ -732,7 +737,7 @@ var StandardChromeActions = (function StandardChromeActionsClosure() { pdfjsLoadAction: 'complete', data: data, errorCode: errorCode - }, '*'); + }, PDF_VIEWER_ORIGIN); self.dataListener = null; self.originalRequest = null; @@ -977,10 +982,14 @@ PdfStreamConverter.prototype = { listener.onDataAvailable(aRequest, aContext, inputStream, offset, count); }, - onStopRequest: function(request, context, statusCode) { - // We get the DOM window here instead of before the request since it - // may have changed during a redirect. - var domWindow = getDOMWindow(channel); + onStopRequest(request, context, statusCode) { + var domWindow = getDOMWindow(channel, resourcePrincipal); + if (!Components.isSuccessCode(statusCode) || !domWindow) { + // The request may have been aborted and the document may have been + // replaced with something that is not PDF.js, abort attaching. + listener.onStopRequest(aRequest, context, statusCode); + return; + } var actions; if (rangeRequest || streamRequest) { actions = new RangedChromeActions( @@ -991,7 +1000,7 @@ PdfStreamConverter.prototype = { domWindow, contentDispositionFilename, aRequest, dataListener); } var requestListener = new RequestListener(actions); - domWindow.addEventListener(PDFJS_EVENT_ID, function(event) { + domWindow.document.addEventListener(PDFJS_EVENT_ID, function(event) { requestListener.receive(event); }, false, true); if (actions.supportsIntegratedFind()) { diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index 4c35bd401..6ce519940 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -41653,6 +41653,22 @@ var isStream = corePrimitives.isStream; var PostScriptLexer = corePsParser.PostScriptLexer; var PostScriptParser = corePsParser.PostScriptParser; + function toNumberArray(arr) { + if (!Array.isArray(arr)) { + return null; + } + var length = arr.length; + for (var i = 0; i < length; i++) { + if (typeof arr[i] !== 'number') { + var result = new Array(length); + for (var j = 0; j < length; j++) { + result[j] = +arr[j]; + } + return result; + } + } + return arr; + } var PDFFunction = function PDFFunctionClosure() { var CONSTRUCT_SAMPLED = 0; var CONSTRUCT_INTERPOLATED = 2; @@ -41752,8 +41768,8 @@ } return out; } - var domain = dict.getArray('Domain'); - var range = dict.getArray('Range'); + var domain = toNumberArray(dict.getArray('Domain')); + var range = toNumberArray(dict.getArray('Range')); if (!domain || !range) { error('No domain or range'); } @@ -41761,7 +41777,7 @@ var outputSize = range.length / 2; domain = toMultiArray(domain); range = toMultiArray(range); - var size = dict.get('Size'); + var size = toNumberArray(dict.get('Size')); var bps = dict.get('BitsPerSample'); var order = dict.get('Order') || 1; if (order !== 1) { @@ -41769,16 +41785,16 @@ // As in poppler, ignoring order, linear interpolation may work as good info('No support for cubic spline interpolation: ' + order); } - var encode = dict.getArray('Encode'); + var encode = toNumberArray(dict.getArray('Encode')); if (!encode) { encode = []; for (var i = 0; i < inputSize; ++i) { - encode.push(0); - encode.push(size[i] - 1); + encode.push([0, size[i] - 1]); } + } else { + encode = toMultiArray(encode); } - encode = toMultiArray(encode); - var decode = dict.getArray('Decode'); + var decode = toNumberArray(dict.getArray('Decode')); if (!decode) { decode = range; } else { @@ -41873,12 +41889,9 @@ }; }, constructInterpolated: function PDFFunction_constructInterpolated(str, dict) { - var c0 = dict.getArray('C0') || [0]; - var c1 = dict.getArray('C1') || [1]; + var c0 = toNumberArray(dict.getArray('C0')) || [0]; + var c1 = toNumberArray(dict.getArray('C1')) || [1]; var n = dict.get('N'); - if (!isArray(c0) || !isArray(c1)) { - error('Illegal dictionary for interpolated function'); - } var length = c0.length; var diff = []; for (var i = 0; i < length; ++i) { @@ -41904,7 +41917,7 @@ }; }, constructStiched: function PDFFunction_constructStiched(fn, dict, xref) { - var domain = dict.getArray('Domain'); + var domain = toNumberArray(dict.getArray('Domain')); if (!domain) { error('No domain'); } @@ -41915,10 +41928,10 @@ var fnRefs = dict.get('Functions'); var fns = []; for (var i = 0, ii = fnRefs.length; i < ii; ++i) { - fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i]))); + fns.push(PDFFunction.parse(xref, xref.fetchIfRef(fnRefs[i]))); } - var bounds = dict.getArray('Bounds'); - var encode = dict.getArray('Encode'); + var bounds = toNumberArray(dict.getArray('Bounds')); + var encode = toNumberArray(dict.getArray('Encode')); return [ CONSTRUCT_STICHED, domain, @@ -41931,12 +41944,8 @@ var domain = IR[1]; var bounds = IR[2]; var encode = IR[3]; - var fnsIR = IR[4]; - var fns = []; + var fns = IR[4]; var tmpBuf = new Float32Array(1); - for (var i = 0, ii = fnsIR.length; i < ii; i++) { - fns.push(PDFFunction.fromIR(fnsIR[i])); - } return function constructStichedFromIRResult(src, srcOffset, dest, destOffset) { var clip = function constructStichedFromIRClip(v, min, max) { if (v > max) { @@ -41973,8 +41982,8 @@ }; }, constructPostScript: function PDFFunction_constructPostScript(fn, dict, xref) { - var domain = dict.getArray('Domain'); - var range = dict.getArray('Range'); + var domain = toNumberArray(dict.getArray('Domain')); + var range = toNumberArray(dict.getArray('Range')); if (!domain) { error('No domain.'); } @@ -42933,8 +42942,8 @@ case 'AlternateCS': var numComps = IR[1]; var alt = IR[2]; - var tintFnIR = IR[3]; - return new AlternateCS(numComps, ColorSpace.fromIR(alt), PDFFunction.fromIR(tintFnIR)); + var tintFn = IR[3]; + return new AlternateCS(numComps, ColorSpace.fromIR(alt), tintFn); case 'LabCS': whitePoint = IR[1]; blackPoint = IR[2]; @@ -43072,12 +43081,12 @@ numComps = name.length; } alt = ColorSpace.parseToIR(cs[2], xref, res); - var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3])); + var tintFn = PDFFunction.parse(xref, xref.fetchIfRef(cs[3])); return [ 'AlternateCS', numComps, alt, - tintFnIR + tintFn ]; case 'Lab': params = xref.fetchIfRef(cs[1]); @@ -52488,4 +52497,4 @@ })); }.call(pdfjsLibs)); exports.WorkerMessageHandler = pdfjsLibs.pdfjsCoreWorker.WorkerMessageHandler; -}));
\ No newline at end of file +})); diff --git a/browser/extensions/pocket/bootstrap.js b/browser/extensions/pocket/bootstrap.js deleted file mode 100644 index c470eb8d3..000000000 --- a/browser/extensions/pocket/bootstrap.js +++ /dev/null @@ -1,511 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://services-common/utils.js"); -Cu.import("resource://gre/modules/Preferences.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Services", - "resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", - "resource:///modules/RecentWindow.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", - "resource:///modules/CustomizableUI.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", - "resource://gre/modules/AddonManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", - "resource://gre/modules/ReaderMode.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Pocket", - "chrome://pocket/content/Pocket.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AboutPocket", - "chrome://pocket/content/AboutPocket.jsm"); -XPCOMUtils.defineLazyGetter(this, "gPocketBundle", function() { - return Services.strings.createBundle("chrome://pocket/locale/pocket.properties"); -}); -XPCOMUtils.defineLazyGetter(this, "gPocketStyleURI", function() { - return Services.io.newURI("chrome://pocket/skin/pocket.css", null, null); -}); - -// Due to bug 1051238 frame scripts are cached forever, so we can't update them -// as a restartless add-on. The Math.random() is the work around for this. -const PROCESS_SCRIPT = "chrome://pocket/content/pocket-content-process.js?" + Math.random(); - -const PREF_BRANCH = "extensions.pocket."; -const PREFS = { - enabled: true, // bug 1229937, figure out ui tour support - api: "api.getpocket.com", - site: "getpocket.com", - oAuthConsumerKey: "40249-e88c401e1b1f2242d9e441c4" -}; - -function setDefaultPrefs() { - let branch = Services.prefs.getDefaultBranch(PREF_BRANCH); - for (let [key, val] of Object.entries(PREFS)) { - // If someone beat us to setting a default, don't overwrite it. This can - // happen if distribution.ini sets the default first. - if (branch.getPrefType(key) != branch.PREF_INVALID) - continue; - switch (typeof val) { - case "boolean": - branch.setBoolPref(key, val); - break; - case "number": - branch.setIntPref(key, val); - break; - case "string": - branch.setCharPref(key, val); - break; - } - } -} - -function createElementWithAttrs(document, type, attrs) { - let element = document.createElement(type); - Object.keys(attrs).forEach(function (attr) { - element.setAttribute(attr, attrs[attr]); - }) - return element; -} - -function CreatePocketWidget(reason) { - let id = "pocket-button" - let widget = CustomizableUI.getWidget(id); - // The widget is only null if we've created then destroyed the widget. - // Once we've actually called createWidget the provider will be set to - // PROVIDER_API. - if (widget && widget.provider == CustomizableUI.PROVIDER_API) - return; - // if upgrading from builtin version and the button was placed in ui, - // seenWidget will not be null - let seenWidget = CustomizableUI.getPlacementOfWidget("pocket-button", false, true); - let pocketButton = { - id: "pocket-button", - defaultArea: CustomizableUI.AREA_NAVBAR, - introducedInVersion: "pref", - type: "view", - tabSpecific: true, - viewId: "PanelUI-pocketView", - label: gPocketBundle.GetStringFromName("pocket-button.label"), - tooltiptext: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"), - // Use forwarding functions here to avoid loading Pocket.jsm on startup: - onViewShowing: function() { - return Pocket.onPanelViewShowing.apply(this, arguments); - }, - onViewHiding: function() { - return Pocket.onPanelViewHiding.apply(this, arguments); - }, - onBeforeCreated: function(doc) { - // Bug 1223127,CUI should make this easier to do. - if (doc.getElementById("PanelUI-pocketView")) - return; - let view = doc.createElement("panelview"); - view.id = "PanelUI-pocketView"; - let panel = doc.createElement("vbox"); - panel.setAttribute("class", "panel-subview-body"); - view.appendChild(panel); - doc.getElementById("PanelUI-multiView").appendChild(view); - } - }; - - CustomizableUI.createWidget(pocketButton); - CustomizableUI.addListener(pocketButton); - // placed is null if location is palette - let placed = CustomizableUI.getPlacementOfWidget("pocket-button"); - - // a first time install will always have placed the button somewhere, and will - // not have a placement prior to creating the widget. Thus, !seenWidget && - // placed. - if (reason == ADDON_ENABLE && !seenWidget && placed) { - // initially place the button after the bookmarks button if it is in the UI - let widgets = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR); - let bmbtn = widgets.indexOf("bookmarks-menu-button"); - if (bmbtn > -1) { - CustomizableUI.moveWidgetWithinArea("pocket-button", bmbtn + 1); - } - } - - // Uninstall the Pocket social provider if it exists, but only if we haven't - // already uninstalled it in this manner. That way the user can reinstall - // it if they prefer it without its being uninstalled every time they start - // the browser. - let SocialService; - try { - // For Firefox 51+ - SocialService = Cu.import("resource:///modules/SocialService.jsm", {}).SocialService; - } catch (e) { - SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService; - } - - let origin = "https://getpocket.com"; - SocialService.getProvider(origin, provider => { - if (provider) { - let pref = "social.backup.getpocket-com"; - if (!Services.prefs.prefHasUserValue(pref)) { - let str = Cc["@mozilla.org/supports-string;1"]. - createInstance(Ci.nsISupportsString); - str.data = JSON.stringify(provider.manifest); - Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str); - SocialService.uninstallProvider(origin, () => {}); - } - } - }); - -} - -// PocketContextMenu -// When the context menu is opened check if we need to build and enable pocket UI. -var PocketContextMenu = { - init: function() { - Services.obs.addObserver(this, "on-build-contextmenu", false); - }, - shutdown: function() { - Services.obs.removeObserver(this, "on-build-contextmenu"); - // loop through windows and remove context menus - // iterate through all windows and add pocket to them - for (let win of CustomizableUI.windows) { - let document = win.document; - for (let id of ["context-pocket", "context-savelinktopocket"]) { - let element = document.getElementById(id); - if (element) - element.remove(); - } - } - }, - observe: function(aSubject, aTopic, aData) { - let subject = aSubject.wrappedJSObject; - let document = subject.menu.ownerDocument; - let pocketEnabled = CustomizableUI.getPlacementOfWidget("pocket-button"); - - let showSaveCurrentPageToPocket = !(subject.onTextInput || subject.onLink || - subject.isContentSelected || subject.onImage || - subject.onCanvas || subject.onVideo || subject.onAudio); - let targetUrl = subject.onLink ? subject.linkUrl : subject.pageUrl; - let targetURI = Services.io.newURI(targetUrl, null, null); - let canPocket = pocketEnabled && (targetURI.schemeIs("http") || targetURI.schemeIs("https") || - (targetURI.schemeIs("about") && ReaderMode.getOriginalUrl(targetUrl))); - - let showSaveLinkToPocket = canPocket && !showSaveCurrentPageToPocket && subject.onLink; - - // create menu entries if necessary - let menu = document.getElementById("context-pocket"); - if (!menu) { - menu = createElementWithAttrs(document, "menuitem", { - "id": "context-pocket", - "label": gPocketBundle.GetStringFromName("saveToPocketCmd.label"), - "accesskey": gPocketBundle.GetStringFromName("saveToPocketCmd.accesskey"), - "oncommand": "Pocket.savePage(gContextMenu.browser, gContextMenu.browser.currentURI.spec, gContextMenu.browser.contentTitle);" - }); - let sibling = document.getElementById("context-savepage"); - if (sibling.nextSibling) { - sibling.parentNode.insertBefore(menu, sibling.nextSibling); - } else { - sibling.parentNode.appendChild(menu); - } - } - menu.hidden = !(canPocket && showSaveCurrentPageToPocket); - - menu = document.getElementById("context-savelinktopocket"); - if (!menu) { - menu = createElementWithAttrs(document, "menuitem", { - "id": "context-savelinktopocket", - "label": gPocketBundle.GetStringFromName("saveLinkToPocketCmd.label"), - "accesskey": gPocketBundle.GetStringFromName("saveLinkToPocketCmd.accesskey"), - "oncommand": "Pocket.savePage(gContextMenu.browser, gContextMenu.linkURL);" - }); - let sibling = document.getElementById("context-savelink"); - if (sibling.nextSibling) { - sibling.parentNode.insertBefore(menu, sibling.nextSibling); - } else { - sibling.parentNode.appendChild(menu); - } - } - menu.hidden = !showSaveLinkToPocket; - } -} - -// PocketReader -// Listen for reader mode setup and add our button to the reader toolbar -var PocketReader = { - _hidden: true, - get hidden() { - return this._hidden; - }, - set hidden(hide) { - hide = !!hide; - if (hide === this._hidden) - return; - this._hidden = hide; - this.update(); - }, - startup: function() { - // Setup the listeners, update will be called when the widget is added, - // no need to do that now. - let mm = Services.mm; - mm.addMessageListener("Reader:OnSetup", this); - mm.addMessageListener("Reader:Clicked-pocket-button", this); - }, - shutdown: function() { - let mm = Services.mm; - mm.removeMessageListener("Reader:OnSetup", this); - mm.removeMessageListener("Reader:Clicked-pocket-button", this); - this.hidden = true; - }, - update: function() { - if (this.hidden) { - Services.mm.broadcastAsyncMessage("Reader:RemoveButton", { id: "pocket-button" }); - } else { - Services.mm.broadcastAsyncMessage("Reader:AddButton", - { id: "pocket-button", - title: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"), - image: "chrome://pocket/content/panels/img/pocket.svg#pocket-mark" }); - } - }, - receiveMessage: function(message) { - switch (message.name) { - case "Reader:OnSetup": { - // Tell the reader about our button. - if (this.hidden) - break; - message.target.messageManager. - sendAsyncMessage("Reader:AddButton", { id: "pocket-button", - title: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"), - image: "chrome://pocket/content/panels/img/pocket.svg#pocket-mark"}); - break; - } - case "Reader:Clicked-pocket-button": { - let doc = message.target.ownerDocument; - let pocketWidget = doc.getElementById("pocket-button"); - let placement = CustomizableUI.getPlacementOfWidget("pocket-button"); - if (placement) { - if (placement.area == CustomizableUI.AREA_PANEL) { - doc.defaultView.PanelUI.show().then(function() { - // The DOM node might not exist yet if the panel wasn't opened before. - pocketWidget = doc.getElementById("pocket-button"); - pocketWidget.doCommand(); - }); - } else { - pocketWidget.doCommand(); - } - } - break; - } - } - } -} - - -function pktUIGetter(prop, window) { - return { - get: function() { - // delete any getters for properties loaded from main.js so we only load main.js once - delete window.pktUI; - delete window.pktApi; - delete window.pktUIMessaging; - Services.scriptloader.loadSubScript("chrome://pocket/content/main.js", window); - return window[prop]; - }, - configurable: true, - enumerable: true - }; -} - -var PocketOverlay = { - startup: function(reason) { - let styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"] - .getService(Ci.nsIStyleSheetService); - this._sheetType = styleSheetService.AUTHOR_SHEET; - this._cachedSheet = styleSheetService.preloadSheet(gPocketStyleURI, - this._sheetType); - Services.ppmm.loadProcessScript(PROCESS_SCRIPT, true); - PocketReader.startup(); - CustomizableUI.addListener(this); - CreatePocketWidget(reason); - PocketContextMenu.init(); - - for (let win of CustomizableUI.windows) { - this.onWindowOpened(win); - } - }, - shutdown: function(reason) { - let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"] - .getService(Ci.nsIMessageBroadcaster); - ppmm.broadcastAsyncMessage("PocketShuttingDown"); - // Although the ppmm loads the scripts into the chrome process as well, - // we need to manually unregister here anyway to ensure these aren't part - // of the chrome process and avoid errors. - AboutPocket.aboutSaved.unregister(); - AboutPocket.aboutSignup.unregister(); - - CustomizableUI.removeListener(this); - for (let window of CustomizableUI.windows) { - for (let id of ["panelMenu_pocket", "menu_pocket", "BMB_pocket", - "panelMenu_pocketSeparator", "menu_pocketSeparator", - "BMB_pocketSeparator"]) { - let element = window.document.getElementById(id); - if (element) - element.remove(); - } - this.removeStyles(window); - // remove script getters/objects - delete window.Pocket; - delete window.pktApi; - delete window.pktUI; - delete window.pktUIMessaging; - } - CustomizableUI.destroyWidget("pocket-button"); - PocketContextMenu.shutdown(); - PocketReader.shutdown(); - }, - onWindowOpened: function(window) { - if (window.hasOwnProperty("pktUI")) - return; - this.setWindowScripts(window); - this.addStyles(window); - this.updateWindow(window); - }, - setWindowScripts: function(window) { - XPCOMUtils.defineLazyModuleGetter(window, "Pocket", - "chrome://pocket/content/Pocket.jsm"); - // Can't use XPCOMUtils for these because the scripts try to define the variables - // on window, and so the defineProperty inside defineLazyGetter fails. - Object.defineProperty(window, "pktApi", pktUIGetter("pktApi", window)); - Object.defineProperty(window, "pktUI", pktUIGetter("pktUI", window)); - Object.defineProperty(window, "pktUIMessaging", pktUIGetter("pktUIMessaging", window)); - }, - // called for each window as it is opened - updateWindow: function(window) { - // insert our three menu items - let document = window.document; - let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button"); - - // add to bookmarksMenu - let sib = document.getElementById("menu_bookmarkThisPage"); - if (sib && !document.getElementById("menu_pocket")) { - let menu = createElementWithAttrs(document, "menuitem", { - "id": "menu_pocket", - "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"), - "class": "menuitem-iconic", // OSX only - "oncommand": "openUILink(Pocket.listURL, event);", - "hidden": hidden - }); - let sep = createElementWithAttrs(document, "menuseparator", { - "id": "menu_pocketSeparator", - "hidden": hidden - }); - sib.parentNode.insertBefore(menu, sib); - sib.parentNode.insertBefore(sep, sib); - } - - // add to bookmarks-menu-button - sib = document.getElementById("BMB_bookmarksToolbar"); - if (sib && !document.getElementById("BMB_pocket")) { - let menu = createElementWithAttrs(document, "menuitem", { - "id": "BMB_pocket", - "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"), - "class": "menuitem-iconic bookmark-item subviewbutton", - "oncommand": "openUILink(Pocket.listURL, event);", - "hidden": hidden - }); - let sep = createElementWithAttrs(document, "menuseparator", { - "id": "BMB_pocketSeparator", - "hidden": hidden - }); - sib.parentNode.insertBefore(menu, sib); - sib.parentNode.insertBefore(sep, sib); - } - - // add to PanelUI-bookmarks - sib = document.getElementById("panelMenuBookmarkThisPage"); - if (sib && !document.getElementById("panelMenu_pocket")) { - let menu = createElementWithAttrs(document, "toolbarbutton", { - "id": "panelMenu_pocket", - "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"), - "class": "subviewbutton cui-withicon", - "oncommand": "openUILink(Pocket.listURL, event);", - "hidden": hidden - }); - let sep = createElementWithAttrs(document, "toolbarseparator", { - "id": "panelMenu_pocketSeparator", - "hidden": hidden - }); - // nextSibling is no-id toolbarseparator - // insert separator first then button - sib = sib.nextSibling; - sib.parentNode.insertBefore(sep, sib); - sib.parentNode.insertBefore(menu, sib); - } - }, - onWidgetAfterDOMChange: function(aWidgetNode) { - if (aWidgetNode.id != "pocket-button") { - return; - } - let doc = aWidgetNode.ownerDocument; - let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button"); - for (let prefix of ["panelMenu_", "menu_", "BMB_"]) { - let element = doc.getElementById(prefix + "pocket"); - if (element) { - element.hidden = hidden; - doc.getElementById(prefix + "pocketSeparator").hidden = hidden; - } - } - // enable or disable reader button - PocketReader.hidden = hidden; - }, - - addStyles: function(win) { - let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); - utils.addSheet(this._cachedSheet, this._sheetType); - }, - - removeStyles: function(win) { - let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); - utils.removeSheet(gPocketStyleURI, this._sheetType); - } - -} - -// use enabled pref as a way for tests (e.g. test_contextmenu.html) to disable -// the addon when running. -function prefObserver(aSubject, aTopic, aData) { - let enabled = Services.prefs.getBoolPref("extensions.pocket.enabled"); - if (enabled) - PocketOverlay.startup(ADDON_ENABLE); - else - PocketOverlay.shutdown(ADDON_DISABLE); -} - -function startup(data, reason) { - AddonManager.getAddonByID("isreaditlater@ideashower.com", addon => { - if (addon && addon.isActive) - return; - setDefaultPrefs(); - // migrate enabled pref - if (Services.prefs.prefHasUserValue("browser.pocket.enabled")) { - Services.prefs.setBoolPref("extensions.pocket.enabled", Services.prefs.getBoolPref("browser.pocket.enabled")); - Services.prefs.clearUserPref("browser.pocket.enabled"); - } - // watch pref change and enable/disable if necessary - Services.prefs.addObserver("extensions.pocket.enabled", prefObserver, false); - if (!Services.prefs.getBoolPref("extensions.pocket.enabled")) - return; - PocketOverlay.startup(reason); - }); -} - -function shutdown(data, reason) { - // For speed sake, we should only do a shutdown if we're being disabled. - // On an app shutdown, just let it fade away... - if (reason != APP_SHUTDOWN) { - Services.prefs.removeObserver("extensions.pocket.enabled", prefObserver); - PocketOverlay.shutdown(reason); - } -} - -function install() { -} - -function uninstall() { -} diff --git a/browser/extensions/pocket/content/AboutPocket.jsm b/browser/extensions/pocket/content/AboutPocket.jsm deleted file mode 100644 index c7f57aa87..000000000 --- a/browser/extensions/pocket/content/AboutPocket.jsm +++ /dev/null @@ -1,93 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const { interfaces: Ci, results: Cr, manager: Cm, utils: Cu } = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error". -const PREF_LOG_LEVEL = "loop.debug.loglevel"; - -XPCOMUtils.defineLazyGetter(this, "log", () => { - let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI; - let consoleOptions = { - maxLogLevelPref: PREF_LOG_LEVEL, - prefix: "Loop" - }; - return new ConsoleAPI(consoleOptions); -}); - - -function AboutPage(chromeURL, aboutHost, classID, description, uriFlags) { - this.chromeURL = chromeURL; - this.aboutHost = aboutHost; - this.classID = Components.ID(classID); - this.description = description; - this.uriFlags = uriFlags; -} - -AboutPage.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]), - getURIFlags: function(aURI) { // eslint-disable-line no-unused-vars - return this.uriFlags; - }, - - newChannel: function(aURI, aLoadInfo) { - let newURI = Services.io.newURI(this.chromeURL, null, null); - let channel = Services.io.newChannelFromURIWithLoadInfo(newURI, - aLoadInfo); - channel.originalURI = aURI; - - if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) { - let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(aURI); - channel.owner = principal; - } - return channel; - }, - - createInstance: function(outer, iid) { - if (outer !== null) { - throw Cr.NS_ERROR_NO_AGGREGATION; - } - return this.QueryInterface(iid); - }, - - register: function() { - Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory( - this.classID, this.description, - "@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this); - }, - - unregister: function() { - Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory( - this.classID, this); - } -}; - -/* exported AboutPocket */ -var AboutPocket = {}; - -XPCOMUtils.defineLazyGetter(AboutPocket, "aboutSaved", () => - new AboutPage("chrome://pocket/content/panels/saved.html", - "pocket-saved", - "{3e759f54-37af-7843-9824-f71b5993ceed}", - "About Pocket Saved", - Ci.nsIAboutModule.ALLOW_SCRIPT | - Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | - Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT) -); - -XPCOMUtils.defineLazyGetter(AboutPocket, "aboutSignup", () => - new AboutPage("chrome://pocket/content/panels/signup.html", - "pocket-signup", - "{8548329d-00c4-234e-8f17-75026db3b56e}", - "About Pocket Signup", - Ci.nsIAboutModule.ALLOW_SCRIPT | - Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | - Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT) -); - -this.EXPORTED_SYMBOLS = ["AboutPocket"]; diff --git a/browser/extensions/pocket/content/Pocket.jsm b/browser/extensions/pocket/content/Pocket.jsm deleted file mode 100644 index 54f9cdf11..000000000 --- a/browser/extensions/pocket/content/Pocket.jsm +++ /dev/null @@ -1,93 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -this.EXPORTED_SYMBOLS = ["Pocket"]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", - "resource:///modules/CustomizableUI.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", - "resource://gre/modules/ReaderMode.jsm"); - -var Pocket = { - get site() { return Services.prefs.getCharPref("extensions.pocket.site"); }, - get listURL() { return "https://" + Pocket.site + "/?src=ff_ext"; }, - - /** - * Functions related to the Pocket panel UI. - */ - onPanelViewShowing(event) { - let document = event.target.ownerDocument; - let window = document.defaultView; - let iframe = window.pktUI.getPanelFrame(); - - let urlToSave = Pocket._urlToSave; - let titleToSave = Pocket._titleToSave; - Pocket._urlToSave = null; - Pocket._titleToSave = null; - // ViewShowing fires immediately before it creates the contents, - // in lieu of an AfterViewShowing event, just spin the event loop. - window.setTimeout(function() { - if (urlToSave) { - window.pktUI.tryToSaveUrl(urlToSave, titleToSave); - } else { - window.pktUI.tryToSaveCurrentPage(); - } - - // pocketPanelDidHide in main.js set iframe to about:blank when it was - // hidden, make sure we're loading the save panel. - if (iframe.contentDocument && - iframe.contentDocument.readyState == "complete" && - iframe.contentDocument.documentURI != "about:blank") { - window.pktUI.pocketPanelDidShow(); - } else { - // iframe didn't load yet. This seems to always be the case when in - // the toolbar panel, but never the case for a subview. - // XXX this only being fired when it's a _capturing_ listener! - iframe.addEventListener("load", Pocket.onFrameLoaded, true); - } - }, 0); - }, - - onFrameLoaded(event) { - let document = event.currentTarget.ownerDocument; - let window = document.defaultView; - let iframe = window.pktUI.getPanelFrame(); - - iframe.removeEventListener("load", Pocket.onFrameLoaded, true); - window.pktUI.pocketPanelDidShow(); - }, - - onPanelViewHiding(event) { - let window = event.target.ownerGlobal; - window.pktUI.pocketPanelDidHide(event); - }, - - _urlToSave: null, - _titleToSave: null, - savePage(browser, url, title) { - let document = browser.ownerDocument; - let pocketWidget = document.getElementById("pocket-button"); - let placement = CustomizableUI.getPlacementOfWidget("pocket-button"); - if (!placement) - return; - - this._urlToSave = url; - this._titleToSave = title; - if (placement.area == CustomizableUI.AREA_PANEL) { - let win = document.defaultView; - win.PanelUI.show().then(function() { - pocketWidget = document.getElementById("pocket-button"); - pocketWidget.doCommand(); - }); - } else { - pocketWidget.doCommand(); - } - }, -}; diff --git a/browser/extensions/pocket/content/main.js b/browser/extensions/pocket/content/main.js deleted file mode 100644 index 3c1c5785e..000000000 --- a/browser/extensions/pocket/content/main.js +++ /dev/null @@ -1,737 +0,0 @@ -/* - * LICENSE - * - * POCKET MARKS - * - * Notwithstanding the permitted uses of the Software (as defined below) pursuant to the license set forth below, "Pocket," "Read It Later" and the Pocket icon and logos (collectively, the “Pocket Marks”) are registered and common law trademarks of Read It Later, Inc. This means that, while you have considerable freedom to redistribute and modify the Software, there are tight restrictions on your ability to use the Pocket Marks. This license does not grant you any rights to use the Pocket Marks except as they are embodied in the Software. - * - * --- - * - * SOFTWARE - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* - * Pocket UI module - * - * Handles interactions with Pocket buttons, panels and menus. - * - */ - -// TODO : Get the toolbar icons from Firefox's build (Nikki needs to give us a red saved icon) -// TODO : [needs clarificaiton from Fx] Firefox's plan was to hide Pocket from context menus until the user logs in. Now that it's an extension I'm wondering if we still need to do this. -// TODO : [needs clarificaiton from Fx] Reader mode (might be a something they need to do since it's in html, need to investigate their code) -// TODO : [needs clarificaiton from Fx] Move prefs within pktApi.s to sqlite or a local file so it's not editable (and is safer) -// TODO : [nice to have] - Immediately save, buffer the actions in a local queue and send (so it works offline, works like our native extensions) - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", - "resource://gre/modules/ReaderMode.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "pktApi", - "chrome://pocket/content/pktApi.jsm"); - -var pktUI = (function() { - - // -- Initialization (on startup and new windows) -- // - var _currentPanelDidShow; - var _currentPanelDidHide; - - // Init panel id at 0. The first actual panel id will have the number 1 so - // in case at some point any panel has the id 0 we know there is something - // wrong - var _panelId = 0; - - var overflowMenuWidth = 230; - var overflowMenuHeight = 475; - var savePanelWidth = 350; - var savePanelHeights = {collapsed: 153, expanded: 272}; - - // -- Event Handling -- // - - /** - * Event handler when Pocket toolbar button is pressed - */ - - function pocketPanelDidShow(event) { - if (_currentPanelDidShow) { - _currentPanelDidShow(event); - } - - } - - function pocketPanelDidHide(event) { - if (_currentPanelDidHide) { - _currentPanelDidHide(event); - } - - // clear the panel - getPanelFrame().setAttribute('src', 'about:blank'); - } - - - // -- Communication to API -- // - - /** - * Either save or attempt to log the user in - */ - function tryToSaveCurrentPage() { - tryToSaveUrl(getCurrentUrl(), getCurrentTitle()); - } - - function tryToSaveUrl(url, title) { - - // If the user is logged in, go ahead and save the current page - if (pktApi.isUserLoggedIn()) { - saveAndShowConfirmation(url, title); - return; - } - - // If the user is not logged in, show the logged-out state to prompt them to authenticate - showSignUp(); - } - - - // -- Panel UI -- // - - /** - * Show the sign-up panel - */ - function showSignUp() { - // AB test: Direct logged-out users to tab vs panel - if (pktApi.getSignupPanelTabTestVariant() == 'v2') - { - let site = Services.prefs.getCharPref("extensions.pocket.site"); - openTabWithUrl('https://' + site + '/firefox_learnmore?s=ffi&t=autoredirect&tv=page_learnmore&src=ff_ext', true); - - // force the panel closed before it opens - getPanel().hidePopup(); - - return; - } - - // Control: Show panel as normal - getFirefoxAccountSignedInUser(function(userdata) - { - var fxasignedin = (typeof userdata == 'object' && userdata !== null) ? '1' : '0'; - var startheight = 490; - var inOverflowMenu = isInOverflowMenu(); - var controlvariant = pktApi.getSignupPanelTabTestVariant() == 'control'; - - if (inOverflowMenu) - { - startheight = overflowMenuHeight; - } - else - { - startheight = 460; - if (fxasignedin == '1') - { - startheight = 406; - } - } - if (!controlvariant) { - startheight = 427; - } - var variant; - if (inOverflowMenu) - { - variant = 'overflow'; - } - else - { - variant = 'storyboard_lm'; - } - - showPanel("about:pocket-signup?pockethost=" - + Services.prefs.getCharPref("extensions.pocket.site") - + "&fxasignedin=" - + fxasignedin - + "&variant=" - + variant - + '&controlvariant=' - + controlvariant - + '&inoverflowmenu=' - + inOverflowMenu - + "&locale=" - + getUILocale(), { - onShow: function() { - }, - onHide: panelDidHide, - width: inOverflowMenu ? overflowMenuWidth : 300, - height: startheight - }); - }); - } - - /** - * Show the logged-out state / sign-up panel - */ - function saveAndShowConfirmation(url, title) { - - // Validate input parameter - if (typeof url !== 'undefined' && url.startsWith("about:reader?url=")) { - url = ReaderMode.getOriginalUrl(url); - } - - var isValidURL = (typeof url !== 'undefined' && (url.startsWith("http") || url.startsWith('https'))); - - var inOverflowMenu = isInOverflowMenu(); - var startheight = pktApi.isPremiumUser() && isValidURL ? savePanelHeights.expanded : savePanelHeights.collapsed; - if (inOverflowMenu) { - startheight = overflowMenuHeight; - } - - var panelId = showPanel("about:pocket-saved?pockethost=" + Services.prefs.getCharPref("extensions.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? '1' : '0') + '&inoverflowmenu='+inOverflowMenu + "&locale=" + getUILocale(), { - onShow: function() { - var saveLinkMessageId = 'saveLink'; - - // Send error message for invalid url - if (!isValidURL) { - // TODO: Pass key for localized error in error object - let error = { - message: 'Only links can be saved', - localizedKey: "onlylinkssaved" - }; - pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, error); - return; - } - - // Check online state - if (!navigator.onLine) { - // TODO: Pass key for localized error in error object - let error = { - message: 'You must be connected to the Internet in order to save to Pocket. Please connect to the Internet and try again.' - }; - pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, error); - return; - } - - // Add url - var options = { - success: function(data, request) { - var item = data.item; - var successResponse = { - status: "success", - item: item - }; - pktUIMessaging.sendMessageToPanel(panelId, saveLinkMessageId, successResponse); - }, - error: function(error, request) { - // If user is not authorized show singup page - if (request.status === 401) { - showSignUp(); - return; - } - - // If there is no error message in the error use a - // complete catch-all - var errorMessage = error.message || "There was an error when trying to save to Pocket."; - var panelError = { message: errorMessage} - - // Send error message to panel - pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, panelError); - } - } - - // Add title if given - if (typeof title !== "undefined") { - options.title = title; - } - - // Send the link - pktApi.addLink(url, options); - }, - onHide: panelDidHide, - width: inOverflowMenu ? overflowMenuWidth : savePanelWidth, - height: startheight - }); - } - - /** - * Open a generic panel - */ - function showPanel(url, options) { - - // Add new panel id - _panelId += 1; - url += ("&panelId=" + _panelId); - - // We don't have to hide and show the panel again if it's already shown - // as if the user tries to click again on the toolbar button the overlay - // will close instead of the button will be clicked - var iframe = getPanelFrame(); - - // Register event handlers - registerEventMessages(); - - // Load the iframe - iframe.setAttribute('src', url); - - // Uncomment to leave panel open -- for debugging - // panel.setAttribute('noautohide', true); - // panel.setAttribute('consumeoutsideclicks', false); - // - - // For some reason setting onpopupshown and onpopuphidden on the panel directly didn't work, so - // do it this hacky way for now - _currentPanelDidShow = options.onShow; - _currentPanelDidHide = options.onHide; - - resizePanel({ - width: options.width, - height: options.height - }); - return _panelId; - } - - /** - * Resize the panel - * options = { - * width: , - * height: , - * animate [default false] - * } - */ - function resizePanel(options) { - var iframe = getPanelFrame(); - var subview = getSubview(); - - if (subview) { - // Use the subview's size - iframe.style.width = "100%"; - iframe.style.height = subview.parentNode.clientHeight + "px"; - } else { - // Set an explicit size, panel will adapt. - iframe.style.width = options.width + "px"; - iframe.style.height = options.height + "px"; - } - } - - /** - * Called when the signup and saved panel was hidden - */ - function panelDidHide() { - // clear the onShow and onHide values - _currentPanelDidShow = null; - _currentPanelDidHide = null; - } - - /** - * Register all of the messages needed for the panels - */ - function registerEventMessages() { - var iframe = getPanelFrame(); - - // Only register the messages once - var didInitAttributeKey = 'did_init'; - var didInitMessageListener = iframe.getAttribute(didInitAttributeKey); - if (typeof didInitMessageListener !== "undefined" && didInitMessageListener == 1) { - return; - } - iframe.setAttribute(didInitAttributeKey, 1); - - // When the panel is displayed it generated an event called - // "show": we will listen for that event and when it happens, - // send our own "show" event to the panel's script, so the - // script can prepare the panel for display. - var _showMessageId = "show"; - pktUIMessaging.addMessageListener(iframe, _showMessageId, function(panelId, data) { - // Let panel know that it is ready - pktUIMessaging.sendMessageToPanel(panelId, _showMessageId); - }); - - // Open a new tab with a given url and activate if - var _openTabWithUrlMessageId = "openTabWithUrl"; - pktUIMessaging.addMessageListener(iframe, _openTabWithUrlMessageId, function(panelId, data, contentPrincipal) { - try { - urlSecurityCheck(data.url, contentPrincipal, Services.scriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL); - } catch (ex) { - return; - } - - // Check if the tab should become active after opening - var activate = true; - if (typeof data.activate !== "undefined") { - activate = data.activate; - } - - var url = data.url; - openTabWithUrl(url, activate); - pktUIMessaging.sendResponseMessageToPanel(panelId, _openTabWithUrlMessageId, url); - }); - - // Close the panel - var _closeMessageId = "close"; - pktUIMessaging.addMessageListener(iframe, _closeMessageId, function(panelId, data) { - getPanel().hidePopup(); - }); - - // Send the current url to the panel - var _getCurrentURLMessageId = "getCurrentURL"; - pktUIMessaging.addMessageListener(iframe, _getCurrentURLMessageId, function(panelId, data) { - pktUIMessaging.sendResponseMessageToPanel(panelId, _getCurrentURLMessageId, getCurrentUrl()); - }); - - var _resizePanelMessageId = "resizePanel"; - pktUIMessaging.addMessageListener(iframe, _resizePanelMessageId, function(panelId, data) { - resizePanel(data); - }); - - // Callback post initialization to tell background script that panel is "ready" for communication. - pktUIMessaging.addMessageListener(iframe, "listenerReady", function(panelId, data) { - - }); - - pktUIMessaging.addMessageListener(iframe, "collapseSavePanel", function(panelId, data) { - if (!pktApi.isPremiumUser() && !isInOverflowMenu()) - resizePanel({width:savePanelWidth, height:savePanelHeights.collapsed}); - }); - - pktUIMessaging.addMessageListener(iframe, "expandSavePanel", function(panelId, data) { - if (!isInOverflowMenu()) - resizePanel({width:savePanelWidth, height:savePanelHeights.expanded}); - }); - - // Ask for recently accessed/used tags for auto complete - var _getTagsMessageId = "getTags"; - pktUIMessaging.addMessageListener(iframe, _getTagsMessageId, function(panelId, data) { - pktApi.getTags(function(tags, usedTags) { - pktUIMessaging.sendResponseMessageToPanel(panelId, _getTagsMessageId, { - tags: tags, - usedTags: usedTags - }); - }); - }); - - // Ask for suggested tags based on passed url - var _getSuggestedTagsMessageId = "getSuggestedTags"; - pktUIMessaging.addMessageListener(iframe, _getSuggestedTagsMessageId, function(panelId, data) { - pktApi.getSuggestedTagsForURL(data.url, { - success: function(data, response) { - var suggestedTags = data.suggested_tags; - var successResponse = { - status: "success", - value: { - suggestedTags: suggestedTags - } - } - pktUIMessaging.sendResponseMessageToPanel(panelId, _getSuggestedTagsMessageId, successResponse); - }, - error: function(error, response) { - pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _getSuggestedTagsMessageId, error); - } - }) - }); - - // Pass url and array list of tags, add to existing save item accordingly - var _addTagsMessageId = "addTags"; - pktUIMessaging.addMessageListener(iframe, _addTagsMessageId, function(panelId, data) { - pktApi.addTagsToURL(data.url, data.tags, { - success: function(data, response) { - var successResponse = {status: "success"}; - pktUIMessaging.sendResponseMessageToPanel(panelId, _addTagsMessageId, successResponse); - }, - error: function(error, response) { - pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _addTagsMessageId, error); - } - }); - }); - - // Based on clicking "remove page" CTA, and passed unique item id, remove the item - var _deleteItemMessageId = "deleteItem"; - pktUIMessaging.addMessageListener(iframe, _deleteItemMessageId, function(panelId, data) { - pktApi.deleteItem(data.itemId, { - success: function(data, response) { - var successResponse = {status: "success"}; - pktUIMessaging.sendResponseMessageToPanel(panelId, _deleteItemMessageId, successResponse); - }, - error: function(error, response) { - pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _deleteItemMessageId, error); - } - }) - }); - - var _initL10NMessageId = "initL10N"; - pktUIMessaging.addMessageListener(iframe, _initL10NMessageId, function(panelId, data) { - var strings = {}; - var bundle = Services.strings.createBundle("chrome://pocket/locale/pocket.properties"); - var e = bundle.getSimpleEnumeration(); - while (e.hasMoreElements()) { - var str = e.getNext().QueryInterface(Components.interfaces.nsIPropertyElement); - if (str.key in data) { - strings[str.key] = bundle.formatStringFromName(str.key, data[str.key], data[str.key].length); - } else { - strings[str.key] = str.value; - } - } - pktUIMessaging.sendResponseMessageToPanel(panelId, _initL10NMessageId, { strings: strings }); - }); - - } - - // -- Browser Navigation -- // - - /** - * Open a new tab with a given url and notify the iframe panel that it was opened - */ - - function openTabWithUrl(url) { - let recentWindow = Services.wm.getMostRecentWindow("navigator:browser"); - if (!recentWindow) { - Cu.reportError("Pocket: No open browser windows to openTabWithUrl"); - return; - } - - // If the user is in permanent private browsing than this is not an issue, - // since the current window will always share the same cookie jar as the other - // windows. - if (!PrivateBrowsingUtils.isWindowPrivate(recentWindow) || - PrivateBrowsingUtils.permanentPrivateBrowsing) { - recentWindow.openUILinkIn(url, "tab"); - return; - } - - let windows = Services.wm.getEnumerator("navigator:browser"); - while (windows.hasMoreElements()) { - let win = windows.getNext(); - if (!PrivateBrowsingUtils.isWindowPrivate(win)) { - win.openUILinkIn(url, "tab"); - return; - } - } - - // If there were no non-private windows opened already. - recentWindow.openUILinkIn(url, "window"); - } - - - // -- Helper Functions -- // - - function getCurrentUrl() { - return getBrowser().currentURI.spec; - } - - function getCurrentTitle() { - return getBrowser().contentTitle; - } - - function getPanel() { - var frame = getPanelFrame(); - var panel = frame; - while (panel && panel.localName != "panel") { - panel = panel.parentNode; - } - return panel; - } - - function getPanelFrame() { - var frame = document.getElementById('pocket-panel-iframe'); - if (!frame) { - var frameParent = document.getElementById("PanelUI-pocketView").firstChild; - frame = document.createElement("iframe"); - frame.id = 'pocket-panel-iframe'; - frame.setAttribute("type", "content"); - frameParent.appendChild(frame); - } - return frame; - } - - function getSubview() { - var view = document.getElementById("PanelUI-pocketView"); - if (view && view.getAttribute("current") == "true") - return view; - return null; - } - - function isInOverflowMenu() { - var subview = getSubview(); - return !!subview; - } - - function getFirefoxAccountSignedInUser(callback) { - fxAccounts.getSignedInUser().then(userData => { - callback(userData); - }).then(null, error => { - callback(); - }); - } - - function getUILocale() { - var locale = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIXULChromeRegistry). - getSelectedLocale("browser"); - return locale; - } - - /** - * Public functions - */ - return { - getPanelFrame: getPanelFrame, - - openTabWithUrl: openTabWithUrl, - - pocketPanelDidShow: pocketPanelDidShow, - pocketPanelDidHide: pocketPanelDidHide, - - tryToSaveUrl: tryToSaveUrl, - tryToSaveCurrentPage: tryToSaveCurrentPage - }; -}()); - -// -- Communication to Background -- // -// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages -var pktUIMessaging = (function() { - - /** - * Prefix message id for message listening - */ - function prefixedMessageId(messageId) { - return 'PKT_' + messageId; - } - - /** - * Register a listener and callback for a specific messageId - */ - function addMessageListener(iframe, messageId, callback) { - iframe.addEventListener(prefixedMessageId(messageId), function(e) { - var nodePrincipal = e.target.nodePrincipal; - // ignore to ensure we do not pick up other events in the browser - if (!nodePrincipal || !nodePrincipal.URI || !nodePrincipal.URI.spec.startsWith("about:pocket")) { - return; - } - - // Pass in information to callback - var payload = JSON.parse(e.target.getAttribute("payload"))[0]; - var panelId = payload.panelId; - var data = payload.data; - callback(panelId, data, nodePrincipal); - - // Cleanup the element - e.target.parentNode.removeChild(e.target); - - }, false, true); - } - - /** - * Send a message to the panel's iframe - */ - function sendMessageToPanel(panelId, messageId, payload) { - - if (!isPanelIdValid(panelId)) { return; } - - var panelFrame = pktUI.getPanelFrame(); - if (!isPocketPanelFrameValid(panelFrame)) { return; } - - var doc = panelFrame.contentWindow.document; - var documentElement = doc.documentElement; - - // Send message to panel - var panelMessageId = prefixedMessageId(panelId + '_' + messageId); - - var AnswerEvt = doc.createElement("PKTMessage"); - AnswerEvt.setAttribute("payload", JSON.stringify([payload])); - documentElement.appendChild(AnswerEvt); - - var event = doc.createEvent("HTMLEvents"); - event.initEvent(panelMessageId, true, false); - AnswerEvt.dispatchEvent(event); - } - - function sendResponseMessageToPanel(panelId, messageId, payload) { - var responseMessageId = messageId + "Response"; - sendMessageToPanel(panelId, responseMessageId, payload); - } - - /** - * Helper function to package an error object and send it to the panel - * iframe as a message response - */ - function sendErrorMessageToPanel(panelId, messageId, error) { - var errorResponse = {status: "error", error: error}; - sendMessageToPanel(panelId, messageId, errorResponse); - } - - function sendErrorResponseMessageToPanel(panelId, messageId, error) { - var errorResponse = {status: "error", error: error}; - sendResponseMessageToPanel(panelId, messageId, errorResponse); - } - - /** - * Validation - */ - - function isPanelIdValid(panelId) { - // First check if panelId has a valid value > 0. We set the panelId to - // 0 to start. But if for some reason the message is attempted to be - // sent before the panel has a panelId, then it's going to send out - // a message with panelId 0, which is never going to be heard. If this - // happens, it means some race condition occurred where the panel was - // trying to communicate before it should. - if (panelId === 0) { - console.warn("Tried to send message to panel with id 0.") - return false; - } - - return true - } - - function isPocketPanelFrameValid(panelFrame) { - // Check if panel is available if not throw a warning and bailout. - // We likely try to send to a panel that is not visible anymore - if (typeof panelFrame === "undefined") { - console.warn("Pocket panel frame is undefined"); - return false; - } - - var contentWindow = panelFrame.contentWindow; - if (typeof contentWindow == "undefined") { - console.warn("Pocket panel frame content window is undefined"); - return false; - } - - var doc = contentWindow.document; - if (typeof doc === "undefined") { - console.warn("Pocket panel frame content window document is undefined"); - return false; - } - - var documentElement = doc.documentElement; - if (typeof documentElement === "undefined") { - console.warn("Pocket panel frame content window document document element is undefined"); - return false; - } - - return true; - } - - /** - * Public - */ - return { - addMessageListener: addMessageListener, - sendMessageToPanel: sendMessageToPanel, - sendResponseMessageToPanel: sendResponseMessageToPanel, - sendErrorMessageToPanel: sendErrorMessageToPanel, - sendErrorResponseMessageToPanel: sendErrorResponseMessageToPanel - } -}()); diff --git a/browser/extensions/pocket/content/panels/css/firasans.css b/browser/extensions/pocket/content/panels/css/firasans.css deleted file mode 100644 index 5915345d6..000000000 --- a/browser/extensions/pocket/content/panels/css/firasans.css +++ /dev/null @@ -1,6 +0,0 @@ -@font-face { - font-family: 'FiraSans'; - src: url('../fonts/FiraSans-Regular.woff') format('woff'); - font-weight: normal; - font-style: normal; -}
\ No newline at end of file diff --git a/browser/extensions/pocket/content/panels/css/normalize.css b/browser/extensions/pocket/content/panels/css/normalize.css deleted file mode 100644 index b7b4b746e..000000000 --- a/browser/extensions/pocket/content/panels/css/normalize.css +++ /dev/null @@ -1,424 +0,0 @@ -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ - -/** - * 1. Set default font family to sans-serif. - * 2. Prevent iOS text size adjust after orientation change, without disabling - * user zoom. - */ - -html { - font-family: sans-serif; /* 1 */ -} - -/** - * Remove default margin. - */ - -body { - margin: 0; -} - -/* HTML5 display definitions - ========================================================================== */ - -/** - * Correct `block` display not defined for any HTML5 element in IE 8/9. - * Correct `block` display not defined for `details` or `summary` in IE 10/11 - * and Firefox. - * Correct `block` display not defined for `main` in IE 11. - */ - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} - -/** - * 1. Correct `inline-block` display not defined in IE 8/9. - * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. - */ - -audio, -canvas, -progress, -video { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ -} - -/** - * Prevent modern browsers from displaying `audio` without controls. - * Remove excess height in iOS 5 devices. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Address `[hidden]` styling not present in IE 8/9/10. - * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. - */ - -[hidden], -template { - display: none; -} - -/* Links - ========================================================================== */ - -/** - * Remove the gray background color from active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * Improve readability when focused and also mouse hovered in all browsers. - */ - -a:active, -a:hover { - outline: 0; -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Address styling not present in IE 8/9/10/11, Safari, and Chrome. - */ - -abbr[title] { - border-bottom: 1px dotted; -} - -/** - * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. - */ - -b, -strong { - font-weight: bold; -} - -/** - * Address styling not present in Safari and Chrome. - */ - -dfn { - font-style: italic; -} - -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari, and Chrome. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/** - * Address styling not present in IE 8/9. - */ - -mark { - background: #ff0; - color: #000; -} - -/** - * Address inconsistent and variable font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` affecting `line-height` in all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove border when inside `a` element in IE 8/9/10. - */ - -img { - border: 0; -} - -/** - * Correct overflow not hidden in IE 9/10/11. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Grouping content - ========================================================================== */ - -/** - * Address margin not present in IE 8/9 and Safari. - */ - -figure { - margin: 1em 40px; -} - -/** - * Address differences between Firefox and other browsers. - */ - -hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} - -/** - * Contain overflow in all browsers. - */ - -pre { - overflow: auto; -} - -/** - * Address odd `em`-unit font size rendering in all browsers. - */ - -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} - -/* Forms - ========================================================================== */ - -/** - * Known limitation: by default, Chrome and Safari on OS X allow very limited - * styling of `select`, unless a `border` property is set. - */ - -/** - * 1. Correct color not being inherited. - * Known issue: affects color of disabled elements. - * 2. Correct font properties not being inherited. - * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. - */ - -button, -input, -optgroup, -select, -textarea { - color: inherit; /* 1 */ - font: inherit; /* 2 */ - margin: 0; /* 3 */ -} - -/** - * Address `overflow` set to `hidden` in IE 8/9/10/11. - */ - -button { - overflow: visible; -} - -/** - * Address inconsistent `text-transform` inheritance for `button` and `select`. - * All other form control elements do not inherit `text-transform` values. - * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. - * Correct `select` style inheritance in Firefox. - */ - -button, -select { - text-transform: none; -} - -/** - * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` - * and `video` controls. - * 2. Correct inability to style clickable `input` types in iOS. - * 3. Improve usability and consistency of cursor style between image-type - * `input` and others. - */ - -button, -html input[type="button"], /* 1 */ -input[type="reset"], -input[type="submit"] { - cursor: pointer; /* 3 */ -} - -/** - * Re-set default cursor for disabled elements. - */ - -button[disabled], -html input[disabled] { - cursor: default; -} - -/** - * Remove inner padding and border in Firefox 4+. - */ - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} - -/** - * Address Firefox 4+ setting `line-height` on `input` using `!important` in - * the UA stylesheet. - */ - -input { - line-height: normal; -} - -/** - * It's recommended that you don't attempt to style these elements. - * Firefox's implementation doesn't respect box-sizing, padding, or width. - * - * 1. Address box sizing set to `content-box` in IE 8/9/10. - * 2. Remove excess padding in IE 8/9/10. - */ - -input[type="checkbox"], -input[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * 1. Address `appearance` set to `searchfield` in Safari and Chrome. - * 2. Address `box-sizing` set to `border-box` in Safari and Chrome - * (include `-moz` to future-proof). - */ - -input[type="search"] { - box-sizing: content-box; -} - -/** - * Define consistent border, margin, and padding. - */ - -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -/** - * 1. Correct `color` not being inherited in IE 8/9/10/11. - * 2. Remove padding so people aren't caught out if they zero out fieldsets. - */ - -legend { - border: 0; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Remove default vertical scrollbar in IE 8/9/10/11. - */ - -textarea { - overflow: auto; -} - -/** - * Don't inherit the `font-weight` (applied by a rule above). - * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. - */ - -optgroup { - font-weight: bold; -} - -/* Tables - ========================================================================== */ - -/** - * Remove most spacing between table cells. - */ - -table { - border-collapse: collapse; - border-spacing: 0; -} - -td, -th { - padding: 0; -} - -/* Normalization for FF panel defauts - ========================================================================== */ -html { - outline: none; - padding: 0; -} - -a { - color: #0095dd; - margin: 0; - outline: none; - padding: 0; - text-decoration: none; -} - -a:hover, -a:active { - color: #008acb; - text-decoration: underline; -} - -a:active { - color: #006b9d; -} diff --git a/browser/extensions/pocket/content/panels/css/saved.css b/browser/extensions/pocket/content/panels/css/saved.css deleted file mode 100644 index d3f88d04c..000000000 --- a/browser/extensions/pocket/content/panels/css/saved.css +++ /dev/null @@ -1,825 +0,0 @@ -/* saved.css - * - * Description: - * With base elements out of the way, this sets all custom styling for the page saved dialog. - * - * Contents: - * Global - * Loading spinner - * Core detail - * Tag entry - * Recent/suggested tags - * Premium upsell - * Token input/autocomplete - * Overflow mode - * Language overrides - */ - -/*=Global ---------------------------------------------------------------------------------------- */ -.pkt_ext_containersaved { - background-color: #fbfbfb; - border-radius: 4px; - display: block; - font-size: 16px; - font-family: "FiraSans", "Helvetica Neue", Helvetica, Arial, sans-serif; - padding: 0; - position: relative; - text-align: center; -} -.pkt_ext_cf:after { - content: " "; - display:table; - clear:both; -} -.pkt_ext_containersaved .pkt_ext_tag_detail, -.pkt_ext_containersaved .pkt_ext_recenttag_detail, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail { - margin: 0 auto; - padding: 0.25em 1em; - position: relative; - width: auto; -} - -/*=Loading spinner ---------------------------------------------------------------------------------------- */ -@keyframes pkt_ext_spin { - to { - transform: rotate(1turn); - } -} -.pkt_ext_containersaved { - font-size: 16px; -} -.pkt_ext_containersaved .pkt_ext_loadingspinner { - position: relative; - display: inline-block; - height: 2.5em; - left: 50%; - margin: 2em 0 0 -1.25em; - font-size: 10px; - text-indent: 999em; - position: absolute; - top: 4em; - overflow: hidden; - width: 2.5em; - animation: pkt_ext_spin 0.7s infinite steps(8); -} -.pkt_ext_containersaved .pkt_ext_loadingspinner:before, -.pkt_ext_containersaved .pkt_ext_loadingspinner:after, -.pkt_ext_containersaved .pkt_ext_loadingspinner > div:before, -.pkt_ext_containersaved .pkt_ext_loadingspinner > div:after { - content: ''; - position: absolute; - top: 0; - left: 1.125em; - width: 0.25em; - height: 0.75em; - border-radius: .2em; - background: #eee; - box-shadow: 0 1.75em #eee; - transform-origin: 50% 1.25em; -} -.pkt_ext_containersaved .pkt_ext_loadingspinner:before { - background: #555; -} -.pkt_ext_containersaved .pkt_ext_loadingspinner:after { - transform: rotate(-45deg); - background: #777; -} -.pkt_ext_containersaved .pkt_ext_loadingspinner > div:before { - transform: rotate(-90deg); - background: #999; -} -.pkt_ext_containersaved .pkt_ext_loadingspinner > div:after { - transform: rotate(-135deg); - background: #bbb; -} - -/*=Core detail ---------------------------------------------------------------------------------------- */ -.pkt_ext_containersaved .pkt_ext_initload { - left: 0; - position: absolute; - top: 0; - width: 100%; -} -.pkt_ext_containersaved .pkt_ext_detail { - max-height: 0; - opacity: 0; - position: relative; - z-index: 10; -} -.pkt_ext_container_detailactive .pkt_ext_initload { - opacity: 0; -} -.pkt_ext_container_detailactive .pkt_ext_initload .pkt_ext_loadingspinner, -.pkt_ext_container_finalstate .pkt_ext_initload .pkt_ext_loadingspinner { - animation: none; -} -.pkt_ext_container_detailactive .pkt_ext_detail { - max-height: 20em; - opacity: 1; -} -.pkt_ext_container_finalstate .pkt_ext_edit_msg, -.pkt_ext_container_finalstate .pkt_ext_tag_detail, -.pkt_ext_container_finalstate .pkt_ext_suggestedtag_detail, -.pkt_ext_container_finalstate .pkt_ext_item_actions { - opacity: 0; - transition: opacity 0.2s ease-out; -} -.pkt_ext_container_finalerrorstate .pkt_ext_edit_msg, -.pkt_ext_container_finalerrorstate .pkt_ext_tag_detail, -.pkt_ext_container_finalerrorstate .pkt_ext_suggestedtag_detail, -.pkt_ext_container_finalerrorstate .pkt_ext_item_actions { - display: none; - transition: none; -} -.pkt_ext_containersaved h2 { - background: transparent; - border: none; - color: #333; - display: block; - float: none; - font-size: 18px; - font-weight: normal; - letter-spacing: normal; - line-height: 1; - margin: 19px 0 4px; - padding: 0; - position: relative; - text-align: left; - text-transform: none; -} -@keyframes fade_in_out { - 0% { - opacity: 1; - } - 50% { - opacity: 0; - } - 100% { - opacity: 1; - } -} -.pkt_ext_container_finalstate h2 { - animation: fade_in_out 0.4s ease-out; -} -.pkt_ext_container_finalerrorstate h2 { - animation: none; - color: #d74345; -} -.pkt_ext_containersaved .pkt_ext_errordetail { - display: none; - font-size: 12px; - font-weight: normal; - left: 6.4em; - max-width: 21em; - opacity: 0; - position: absolute; - top: 2.7em; - text-align: left; - visibility: hidden; -} -.pkt_ext_container_finalerrorstate .pkt_ext_errordetail { - display: block; - opacity: 1; - visibility: visible; -} -.pkt_ext_containersaved .pkt_ext_logo { - background: url(../img/pocketlogosolo@1x.png) center center no-repeat; - display: block; - float: left; - height: 40px; - padding: 1.25em 1em; - position: relative; - width: 44px; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersaved .pkt_ext_logo { - background-image: url(../img/pocketlogosolo@2x.png); - background-size: 44px 40px; - } -} -.pkt_ext_container_finalerrorstate .pkt_ext_logo { - background-image: url(../img/pocketerror@1x.png); - height: 44px; - width: 44px; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_container_finalerrorstate .pkt_ext_logo { - background-image: url(../img/pocketerror@2x.png); - background-size: 44px 44px; - } -} -.pkt_ext_containersaved .pkt_ext_topdetail { - float: left; -} -.pkt_ext_containersaved .pkt_ext_edit_msg { - box-sizing: border-box; - display: none; - font-size: 0.75em; - left: auto; - padding: 0 1.4em; - position: absolute; - text-align: left; - top: 8.7em; - width: 100%; -} -.pkt_ext_containersaved .pkt_ext_edit_msg_error { - color: #d74345; -} -.pkt_ext_containersaved .pkt_ext_edit_msg_active { - display: block; -} -.pkt_ext_containersaved .pkt_ext_item_actions { - background: transparent; - float: none; - height: auto; - margin-bottom: 1em; - margin-top: 0; - width: auto; -} -.pkt_ext_containersaved .pkt_ext_item_actions_disabled { - opacity: 0.5; -} -.pkt_ext_container_finalstate .pkt_ext_item_actions_disabled { - opacity: 0; -} -.pkt_ext_containersaved .pkt_ext_item_actions ul { - background: none; - display: block; - float: none; - font-size: 16px; - height: auto; - margin: 0; - padding: 0; - width: 100%; -} -.pkt_ext_containersaved .pkt_ext_item_actions li { - box-sizing: border-box; - background: none; - border: 0; - float: left; - list-style: none; - line-height: 0.8; - height: auto; - padding-right: 0.4em; - width: auto; -} -.pkt_ext_containersaved .pkt_ext_item_actions li:before { - content: none; -} -.pkt_ext_containersaved .pkt_ext_item_actions .pkt_ext_actions_separator { - border-left: 2px solid #777; - height: 0.75em; - margin-top: 0.3em; - padding: 0; - width: 10px; -} -.pkt_ext_containersaved .pkt_ext_item_actions a { - background: transparent; - color: #0095dd; - display: block; - font-feature-settings: normal; - font-size: 12px; - font-weight: normal; - letter-spacing: normal; - line-height: inherit; - height: auto; - margin: 0; - padding: 0.5em; - float: left; - text-align: left; - text-decoration: none; - text-transform: none; -} -.pkt_ext_containersaved .pkt_ext_item_actions a:hover { - color: #008acb; - text-decoration: underline; -} -.pkt_ext_containersaved .pkt_ext_item_actions a:before, -.pkt_ext_containersaved .pkt_ext_item_actions a:after { - background: transparent; - display: none; -} -.pkt_ext_containersaved .pkt_ext_item_actions_disabled a { - cursor: default; -} -.pkt_ext_containersaved .pkt_ext_item_actions .pkt_ext_openpocket { - float: right; - padding-right: 0.7em; - text-align: right; -} -.pkt_ext_containersaved .pkt_ext_item_actions .pkt_ext_removeitem { - padding-left: 0; -} -.pkt_ext_containersaved .pkt_ext_close { - background: url(../img/tag_close@1x.png) center center no-repeat; - color: #333; - display: block; - font-size: 0.8em; - height: 10px; - right: 0.5em; - overflow: hidden; - position: absolute; - text-align: center; - text-indent: -9999px; - top: -1em; - width: 10px; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersaved .pkt_ext_close { - background-image: url(../img/tag_close@2x.png); - background-size: 8px 8px; - } -} -.pkt_ext_containersaved .pkt_ext_close:hover { - color: #000; - text-decoration: none; -} - -/*=Tag entry ---------------------------------------------------------------------------------------- */ -.pkt_ext_containersaved .pkt_ext_tag_detail { - border: 1px solid #c1c1c1; - border-radius: 2px; - font-size: 16px; - clear: both; - margin: 1.25em 1em; - padding: 0; - display: flex; -} -.pkt_ext_containersaved .pkt_ext_tag_error { - border: none; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper { - box-sizing: border-box; - flex: 1; - background-color: #fff; - border-right: 1px solid #c3c3c3; - color: #333; - display: block; - float: none; - font-size: 0.875em; - list-style: none; - margin: 0; - overflow: hidden; - padding: 0.25em 0.5em; - width: 14em; - padding-left: 0.5em; - padding-right: 0.5em; -} -.pkt_ext_containersaved .pkt_ext_tag_error .pkt_ext_tag_input_wrapper { - border: 1px solid #d74345; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper .token-input-list { - display: block; - left: 0; - height: 1.7em; - overflow: hidden; - position: relative; - width: 60em; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper .token-input-list, -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper li { - font-size: 14px; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper li { - height: auto; - width: auto; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper li:before { - content: none; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper input { - border: 0; - box-shadow: none; - background-color: #fff; - color: #333; - font-size: 14px; - float: left; - line-height: normal; - height: auto; - min-height: 0; - min-width: 5em; - padding: 3px 2px 1px; - text-transform: none; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper input::placeholder { - color: #a9a9a9; - letter-spacing: normal; - text-transform: none; -} -.pkt_ext_containersaved .input_disabled { - cursor: default; - opacity: 0.5; -} -.pkt_ext_containersaved .pkt_ext_btn { - box-sizing: border-box; - color: #333; - float: none; - font-size: 0.875em; - font-size: 14px; - letter-spacing: normal; - height: 2.2em; - min-width: 4em; - padding: 0.5em 0; - text-decoration: none; - text-transform: none; - width: auto; -} -.pkt_ext_containersaved .pkt_ext_btn:hover { - background-color: #ebebeb; -} -.pkt_ext_containersaved .pkt_ext_btn:active { - background-color: #dadada; -} -.pkt_ext_containersaved .pkt_ext_btn_disabled, -.pkt_ext_containersaved .pkt_ext_btn_disabled:hover, -.pkt_ext_containersaved .pkt_ext_btn_disabled:active { - background-color: transparent; - cursor: default; - opacity: 0.4; -} -.pkt_ext_containersaved .pkt_ext_tag_error .pkt_ext_btn { - border: 1px solid #c3c3c3; - border-width: 1px 1px 1px 0; - height: 2.35em; -} -.pkt_ext_containersaved .autocomplete-suggestions { - margin-top: 2.2em; -} - -/*=Recent/suggested tags ---------------------------------------------------------------------------------------- */ -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown { - border-top: 1px solid #c1c1c1; - bottom: 0; - box-sizing: border-box; - background: #ebebeb; - clear: both; - left: 0; - opacity: 0; - min-height: 110px; - position: fixed; - visibility: hidden; - width: 100%; -} -.pkt_ext_container_detailactive .pkt_ext_suggestedtag_detail, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown { - opacity: 1; - visibility: visible; -} -.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown { - padding: 4px 0; -} -.pkt_ext_container_finalstate .pkt_ext_suggestedtag_detail { - opacity: 0; - visibility: hidden; -} -.pkt_ext_containersaved -.pkt_ext_containersaved .pkt_ext_recenttag_detail h4, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail h4 { - color: #333; - font-size: 0.8125em; - font-size: 13px; - font-weight: normal; - font-style: normal; - letter-spacing: normal; - margin: 0.5em 0; - text-align: left; - text-transform: none; -} -.pkt_ext_containersaved .pkt_ext_recenttag_detail .pkt_ext_loadingspinner, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail .pkt_ext_loadingspinner { - display: none; - position: absolute; -} -.pkt_ext_containersaved .pkt_ext_recenttag_detail_loading .pkt_ext_loadingspinner, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail_loading .pkt_ext_loadingspinner { - display: block; - font-size: 6px; - left: 48%; -} -.pkt_ext_containersaved .pkt_ext_recenttag_detail ul, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail ul { - display: block; - margin: 0; - height: 2em; - overflow: hidden; - padding: 2px 0 0 0; -} -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail ul { - height: auto; - margin: 0; - max-height: 4em; - padding-top: 6px; -} -.pkt_ext_containersaved .pkt_ext_recenttag_detail li, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail li { - background: none; - float: left; - height: inherit; - line-height: 1.5; - list-style: none; - margin-bottom: 0.5em; - width: inherit; -} -.pkt_ext_containersaved .pkt_ext_recenttag_detail li:before, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail li:before { - content: none; -} -.pkt_ext_containersaved .pkt_ext_recenttag_detail .recenttag_msg, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail .suggestedtag_msg { - color: #333; - font-size: 0.8125em; - line-height: 1.2; - left: auto; - position: absolute; - text-align: left; - top: 2em; -} -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail .suggestedtag_msg { - margin-right: 1.3em; -} -.pkt_ext_containersaved .token_tag { - border-radius: 4px; - background: #f7f7f7; - border: 1px solid #c3c3c3; - color: #333; - font-size: 0.875em; - font-size: 14px; - font-weight: normal; - letter-spacing: normal; - margin-right: 0.5em; - padding: 0.125em 0.625em; - text-decoration: none; - text-transform: none; -} -.pkt_ext_containersaved .token_tag:hover { - background-color: #008acb; - border-color: #008acb; - color: #fff; - text-decoration: none; -} -.pkt_ext_containersaved .token_tag:before, -.pkt_ext_containersaved .token_tag:after { - content: none; -} -.pkt_ext_containersaved .token_tag:hover span { - background-image: url(../img/tag_closeactive@1x.png); -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersaved .token_tag:hover span { - background-image: url(../img/tag_closeactive@2x.png); - background-size: 8px 8px; - } -} -.pkt_ext_containersaved .pkt_ext_recenttag_detail_disabled .token_tag, -.pkt_ext_containersaved .pkt_ext_recenttag_detail_disabled .token_tag:hover, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail_disabled .token_tag, -.pkt_ext_containersaved .pkt_ext_suggestedtag_detail_disabled .token_tag:hover { - background-color: #f7f7f7; - cursor: default; - opacity: 0.5; -} -.pkt_ext_containersaved .token_tag_inactive { - display: none; -} - -/*=Premium upsell ---------------------------------------------------------------------------------------- */ -.pkt_ext_detail .pkt_ext_premupsell { - background-color: #50bbb6; - display: block; - padding: 1.5em 0; - text-align: center; -} -.pkt_ext_premupsell h4 { - color: #fff; - font-size: 1em; - margin-bottom: 1em; -} -.pkt_ext_premupsell a { - color: #28605d; - border-bottom: 1px solid #47a7a3; - font-weight: normal; -} -.pkt_ext_premupsell a:hover { - color: #14302f; -} - -/*=Token input/autocomplete ---------------------------------------------------------------------------------------- */ -.token-input-dropdown-tag { - border-radius: 4px; - box-sizing: border-box; - background: #fff; - border: 1px solid #cdcdcd; - margin-top: 0.5em; - left: 0 !important; - overflow-y: auto; - top: 1.9em !important; - z-index: 9000; -} -.token-input-dropdown-tag ul { - height: inherit; - max-height: 115px; - margin: 0; - overflow: auto; - padding: 0.5em 0; -} -.token-input-dropdown-tag ul li { - background: none; - color: #333; - font-weight: normal; - font-size: 1em; - float: none; - height: inherit; - letter-spacing: normal; - list-style: none; - padding: 0.75em; - text-align: left; - text-transform: none; - width: inherit; -} -.token-input-dropdown-tag ul li:before { - content: none; -} -.token-input-dropdown ul li.token-input-selected-dropdown-item { - background-color: #008acb; - color: #fff; -} -.token-input-list { - list-style: none; - margin: 0; - padding: 0; -} -.token-input-list li { - text-align: left; - list-style: none; -} -.token-input-list li input { - border: 0; - background-color: white; -} -.pkt_ext_containersaved .token-input-token { - background: none; - border-radius: 4px; - border: 1px solid #c3c3c3; - overflow: hidden; - margin: 0; - padding: 0 8px; - background-color: #f7f7f7; - color: #000; - font-weight: normal; - cursor: default; - line-height: 1.5; - display: block; - width: auto; - margin: 0 0.2em; - float: left; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled { - position: relative; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled input { - opacity: 0.5; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled .token-input-list { - opacity: 0.5; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled .pkt_ext_tag_input_blocker { - height: 100%; - left: 0; - position: absolute; - top: 0; - width: 100%; - z-index: 5; -} -.pkt_ext_containersaved .token-input-token p { - display: inline-block; - font-size: 14px; - font-weight: normal; - line-height: inherit; - letter-spacing: normal; - padding: 0; - margin: 0; - text-transform: none; - vertical-align: top; - width: auto; -} -.pkt_ext_containersaved .token-input-token p:before { - content: none; - width: 0; -} -.pkt_ext_containersaved .token-input-token span { - background: url(../img/tag_close@1x.png) center center no-repeat; - cursor: pointer; - display: inline-block; - height: 8px; - margin: 0 0 0 8px; - overflow: hidden; - width: 8px; - text-indent: -99px; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersaved .token-input-token span { - background-image: url(../img/tag_close@2x.png); - background-size: 8px 8px; - } -} -.pkt_ext_containersaved .token-input-selected-token { - background-color: #008acb; - border-color: #008acb; - color: #fff; -} -.pkt_ext_containersaved .token-input-selected-token span { - background-image: url(../img/tag_closeactive@1x.png); -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersaved .token-input-selected-token span { - background-image: url(../img/tag_closeactive@2x.png); - background-size: 8px 8px; - } -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled .token-input-selected-token { - background-color: #f7f7f7; -} -.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled .token-input-selected-token span { - color: #bbb; -} - -/*=Overflow mode ---------------------------------------------------------------------------------------- */ -.pkt_ext_saved_overflow .pkt_ext_logo { - float: none; - margin: 0.5em auto 0; -} -.pkt_ext_saved_overflow .pkt_ext_initload { - top: -8px; -} -.pkt_ext_saved_overflow .pkt_ext_loadingspinner { - top: 10em; -} -.pkt_ext_saved_overflow .pkt_ext_topdetail { - float: none; - margin: 0 auto; - padding: 0 1em; -} -.pkt_ext_saved_overflow h2 { - margin-bottom: 0.5em; - margin-top: 0; - text-align: center; -} -.pkt_ext_saved_overflow .pkt_ext_item_actions ul { - display: inline-block; - width: auto; -} -.pkt_ext_saved_overflow .pkt_ext_item_actions li { - float: none; - padding-left: 1em; - padding-right: 1em; - text-align: center; -} -.pkt_ext_saved_overflow .pkt_ext_item_actions .pkt_ext_removeitem, -.pkt_ext_saved_overflow .pkt_ext_item_actions .pkt_ext_openpocket { - float: none; - text-align: center; - padding-left: 0; - padding-right: 0; -} -.pkt_ext_saved_overflow .pkt_ext_item_actions .pkt_ext_actions_separator { - display: none; -} -.pkt_ext_saved_overflow .pkt_ext_tag_detail { - margin-top: 0; -} -.pkt_ext_saved_overflow .pkt_ext_suggestedtag_detail, -.pkt_ext_saved_overflow .pkt_ext_suggestedtag_detailshown { - top: 14.75em; -} -.pkt_ext_saved_overflow .pkt_ext_edit_msg { - top: 16em; -} -.pkt_ext_container_finalerrorstate.pkt_ext_saved_overflow .pkt_ext_errordetail { - box-sizing: border-box; - left: 0; - padding-left: 1em; - padding-right: 1em; - text-align: center; - top: 8.3em; - width: 100%; -} - -/*=Language overrides ---------------------------------------------------------------------------------------- */ -.pkt_ext_saved_es .pkt_ext_btn { - min-width: 5em; -} -.pkt_ext_saved_de .pkt_ext_btn, -.pkt_ext_saved_ru .pkt_ext_btn { - min-width: 6em; -} diff --git a/browser/extensions/pocket/content/panels/css/signup.css b/browser/extensions/pocket/content/panels/css/signup.css deleted file mode 100644 index 5c428a29b..000000000 --- a/browser/extensions/pocket/content/panels/css/signup.css +++ /dev/null @@ -1,424 +0,0 @@ -/* signup.css - * - * Description: - * With base elements out of the way, this sets all custom styling for the extension. - * - * Contents: - * Global - * Core detail - * Core detail - storyboard - * Buttons - * Overflow mode - * Language overrides - */ - -/*=Global ---------------------------------------------------------------------------------------- */ -.pkt_ext_containersignup { - background-color: #ebebeb; - color: #333; - display: block; - font-size: 16px; - font-family: "FiraSans", "Helvetica Neue", Helvetica, Arial, sans-serif; - margin: 0; - padding: 0; - position: relative; - text-align: center; -} -.pkt_ext_containersignup_inactive { - animation: pkt_ext_hide 0.3s ease-out; - opacity: 0; - visibility: hidden; -} -.pkt_ext_cf:after { - content: " "; - display: table; - clear: both; -} -@keyframes pkt_ext_hide { - 0% { - opacity: 1; - visibility: visible; - } - 99% { - opacity: 0; - visibility: visible; - } - 100% { - opacity: 0; - visibility: hidden; - } -} - -/*=Core detail ---------------------------------------------------------------------------------------- */ -.pkt_ext_containersignup p { - font-size: 14px; - color: #333; - font-family: "FiraSans", "Helvetica Neue", Helvetica, Arial, sans-serif; - line-height: 1.3; - margin: 0 auto 1.5em; - max-width: 260px; -} -.pkt_ext_containersignup a { - color: #4c8fd0; -} -.pkt_ext_containersignup a:hover { - color: #3076b9; -} -.pkt_ext_containersignup .pkt_ext_introdetail { - background-color: #fbfbfb; - border: 1px solid #c1c1c1; - border-width: 0 0 1px; -} -.pkt_ext_containersignup .pkt_ext_logo { - background: url(../img/pocketlogo@1x.png) center bottom no-repeat; - display: block; - height: 32px; - margin: 0 auto 15px; - padding-top: 25px; - position: relative; - text-indent: -9999px; - width: 123px; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersignup .pkt_ext_logo { - background-image: url(../img/pocketlogo@2x.png); - background-size: 123px 32px; - } -} -.pkt_ext_containersignup .pkt_ext_introimg { - background: url(../img/pocketsignup_hero@1x.png) center center no-repeat; - display: block; - height: 125px; - margin: 0 auto; - position: relative; - text-indent: -9999px; - width: 255px; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersignup .pkt_ext_introimg { - background-image: url(../img/pocketsignup_hero@2x.png); - background-size: 255px 125px; - } -} -.pkt_ext_containersignup .pkt_ext_tagline { - margin-bottom: 0.5em; -} -.pkt_ext_containersignup .pkt_ext_learnmore { - font-size: 12px; -} -.pkt_ext_containersignup .pkt_ext_learnmoreinactive { - visibility: hidden; -} -.pkt_ext_signupdetail h4 { - font-size: 12px; - font-weight: normal; -} -.pkt_ext_signupdetail .btn-container { - position: relative; - margin-bottom: 0.8em; -} -.pkt_ext_containersignup .ff_signuphelp { - background: url(../img/signup_help@1x.png) center center no-repeat; - display: block; - height: 18px; - margin-top: -9px; - right: -15px; - position: absolute; - text-indent: -9999px; - width: 18px; - top: 50%; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersignup .ff_signuphelp { - background-image: url(../img/signup_help@2x.png); - background-size: 18px 18px; - } -} -.pkt_ext_containersignup .alreadyhave { - font-size: 12px; - max-width: 320px; - margin-top: 15px; -} -.pkt_ext_containersignup .tryitnowspace { - margin-top: 22px; -} -.pkt_ext_signupdetail p.pkt_ext_tos { - color: #777; - font-size: 10px; - line-height: 1.5; - margin-top: 17px; - padding-top: 0; - max-width: 190px; -} - -/*=Core detail - storyboard ---------------------------------------------------------------------------------------- */ -.pkt_ext_introstory { - align-items: center; - display: flex; - padding: 20px; -} -.pkt_ext_introstory:after { - clear: both; - content: ""; - display: table; -} -.pkt_ext_introstory p { - margin-bottom: 0; - text-align: left; -} -.pkt_ext_introstoryone { - padding: 20px 18px 15px 20px; -} -.pkt_ext_introstorytwo { - padding: 3px 0 0 20px; -} -.pkt_ext_introstorytwo .pkt_ext_tagline { - margin-bottom: 1.5em; -} -.pkt_ext_introstory_text { - flex: 1; -} -.pkt_ext_introstoryone_img, -.pkt_ext_introstorytwo_img { - display: block; - overflow: hidden; - position: relative; - text-indent: -999px; -} -.pkt_ext_introstoryone_img { - background: url(../img/pocketsignup_button@1x.png) center right no-repeat; - height: 82px; - padding: 0 0 0 0.7em; - width: 82px; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_introstoryone_img { - background-image: url(../img/pocketsignup_button@2x.png); - background-size: 82px 82px; - } -} -.pkt_ext_introstorytwo_img { - background: url(../img/pocketsignup_devices@1x.png) bottom right no-repeat; - height: 110px; - padding: 1em 0 0 0.7em; - width: 124px; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_introstorytwo_img { - background-image: url(../img/pocketsignup_devices@2x.png); - background-size: 124px 110px; - } -} -.pkt_ext_introstorydivider { - border-top: 1px solid #c1c1c1; - height: 1px; - margin: 0 auto; - width: 125px; -} - -/*=Buttons ---------------------------------------------------------------------------------------- */ -.pkt_ext_containersignup .btn { - background-color: #0096dd; - border: 1px solid #0095dd; - border-radius: 2px; - color: #fff; - display: inline-block; - font-family: "FiraSans", "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 16px; - font-weight: normal; - line-height: 1; - margin: 0; - padding: 11px 45px; - text-align: center; - text-decoration: none; - text-shadow: 0 -1px 0 rgba(142,4,17,0.5); - transition: background-color 0.1s linear; - width: auto; -} -.pkt_ext_containersignup .btn-secondary { - background-color: #fbfbfb; - border-color: #c1c1c1; - color: #444; - text-shadow: 0 1px 0 rgba(255,255,255,0.5); -} -.pkt_ext_containersignup .btn-small { - padding: 6px 20px; -} -.pkt_ext_containersignup .btn-mini { - font-size: 14px; - padding: 5px 15px 4px; -} -.pkt_ext_containersignup .btn:hover { - background-color: #008acb; - color: #fff; - text-decoration: none; -} -.pkt_ext_containersignup .btn-secondary:hover, -.pkt_ext_containersignup .btn-important:hover { - background-color: #f6f6f6; - color: #222; -} -.pkt_ext_containersignup .btn-disabled { - background-image: none; - color: #ccc; - color: rgba(255,255,255,0.6); - cursor: default; - opacity: 0.9; -} -.pkt_ext_containersignup .signup-btn-firefox, -.pkt_ext_containersignup .signup-btn-tryitnow, -.pkt_ext_containersignup .signup-btn-email, -.pkt_ext_containersignup .signupinterim-btn-login, -.pkt_ext_containersignup .signupinterim-btn-signup, -.pkt_ext_containersignup .forgot-btn-submit, -.pkt_ext_containersignup .forgotreset-btn-change { - min-width: 12.125em; - padding: 0.8em 1.1875em; - box-sizing: content-box; -} -.pkt_ext_containersignup .signup-btn-email { - position: relative; - z-index: 10; -} -.pkt_ext_containersignup .signup-btn-tryitnow, -.pkt_ext_containersignup .signup-btn-firefox { - min-width: 14.5em; - position: relative; - padding: 0; -} -.pkt_ext_containersignup .signup-btn-tryitnow{ - margin-top: 25px; -} -.pkt_ext_containersignup .signup-btn-firefox .logo { - background: url(../img/signup_firefoxlogo@1x.png) center center no-repeat; - height: 2.6em; - left: 10px; - margin: 0; - padding: 0; - width: 22px; - position: absolute; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_containersignup .signup-btn-firefox .logo { - background-image: url(../img/signup_firefoxlogo@2x.png); - background-size: 22px 22px; - } -} -.pkt_ext_containersignup .forgotreset-btn-change { - margin-bottom: 2em; -} -.pkt_ext_containersignup .signup-btn-tryitnow .text, -.pkt_ext_containersignup .signup-btn-firefox .text { - display: inline-block; - padding: 0.8em 1.625em; - position: relative; - text-shadow: none; - white-space: nowrap; -} -.pkt_ext_containersignup .signup-btn-tryitnow .text, -.pkt_ext_containersignup .signup-btn-firefox .text { - color: #fff; -} -.pkt_ext_containersignup .btn-disabled .text { - color: #ccc; - color: rgba(255,255,255,0.6); -} - -/*=Overflow mode ---------------------------------------------------------------------------------------- */ -.pkt_ext_signup_overflow .pkt_ext_tagline { - margin-bottom: 1em; - padding: 0 1em; -} -.pkt_ext_signup_overflow .pkt_ext_introimg { - background-size: 200px 98px; - height: 98px; - width: 200px; -} -.pkt_ext_signup_overflow .signup-btn-firefox, -.pkt_ext_containersignup .signup-btn-tryitnow, -.pkt_ext_signup_overflow .signup-btn-email { - font-size: 14px; - min-width: 12.6em; - padding-left: 0.75em; - padding-right: 0.75em; -} -.pkt_ext_signup_overflow .signup-btn-tryitnow .text, -.pkt_ext_signup_overflow .signup-btn-firefox .text { - padding-left: 0; - padding-right: 0; -} - -/*=Language overrides ---------------------------------------------------------------------------------------- */ -.pkt_ext_signup_de .pkt_ext_introstoryone_img { - margin-right: -5px; - padding-left: 0; -} -.pkt_ext_signup_de .pkt_ext_introstorytwo .pkt_ext_tagline, -.pkt_ext_signup_es .pkt_ext_introstorytwo .pkt_ext_tagline, -.pkt_ext_signup_ja .pkt_ext_introstorytwo .pkt_ext_tagline, -.pkt_ext_signup_ru .pkt_ext_introstorytwo .pkt_ext_tagline { - margin-bottom: 0.5em; -} -.pkt_ext_signup_de .signup-btn-firefox .text, -.pkt_ext_signup_de .signup-btn-tryitnow .text, -.pkt_ext_signup_de .signup-btn-email, -.pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-firefox .text, -.pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-email, -.pkt_ext_signup_ja .signup-btn-firefox .text, -.pkt_ext_signup_ja .signup-btn-tryitnow .text, -.pkt_ext_signup_ja .signup-btn-email, -.pkt_ext_signup_ru .signup-btn-firefox .text, -.pkt_ext_signup_ru .signup-btn-tryitnow .text, -.pkt_ext_signup_ru .signup-btn-email { - font-size: 15px; -} -.pkt_ext_signup_ja .signup-btn-firefox .text, -.pkt_ext_signup_ja .signup-btn-tryitnow .text, -.pkt_ext_signup_ru .signup-btn-firefox .text, -.pkt_ext_signup_ru .signup-btn-tryitnow .text { - left: 15px; -} -.pkt_ext_signup_de .signup-btn-firefox .logo, -.pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-firefox .logo, -.pkt_ext_signup_ja .signup-btn-firefox .logo, -.pkt_ext_signup_ru .signup-btn-firefox .logo { - height: 2.4em; -} -@media (min-resolution: 1.1dppx) { - .pkt_ext_signup_de .signup-btn-firefox .logo, - .pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-firefox .logo, - .pkt_ext_signup_ja .signup-btn-firefox .logo, - .pkt_ext_signup_ru .signup-btn-firefox .logo { - height: 2.5em; - } -} -.pkt_ext_signup_de .signup-btn-email, -.pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-email, -.pkt_ext_signup_ja .signup-btn-email, -.pkt_ext_signup_ru .signup-btn-email { - min-width: 13em; - padding: 0.8533em 1.2667em; -} -.pkt_ext_signup_de .pkt_ext_logo, -.pkt_ext_signup_es .pkt_ext_logo, -.pkt_ext_signup_ru .pkt_ext_logo { - padding-top: 15px; -} -.pkt_ext_signup_de .pkt_ext_introdetailhero .pkt_ext_tagline, -.pkt_ext_signup_es .pkt_ext_introdetailhero .pkt_ext_tagline, -.pkt_ext_signup_ja .pkt_ext_introdetailhero .pkt_ext_tagline, -.pkt_ext_signup_ru .pkt_ext_introdetailhero .pkt_ext_tagline { - font-size: 13px; -} -.pkt_ext_signup_overflow.pkt_ext_signup_de .signup-btn-firefox .logo, -.pkt_ext_signup_overflow.pkt_ext_signup_es .signup-btn-firefox .logo, -.pkt_ext_signup_overflow.pkt_ext_signup_ja .signup-btn-firefox .logo, -.pkt_ext_signup_overflow.pkt_ext_signup_ru .signup-btn-firefox .logo { - display: none; -} diff --git a/browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woff b/browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woff Binary files differdeleted file mode 100644 index f466cdda9..000000000 --- a/browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woff +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocket.svg b/browser/extensions/pocket/content/panels/img/pocket.svg deleted file mode 100644 index d93fd6a15..000000000 --- a/browser/extensions/pocket/content/panels/img/pocket.svg +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<!-- 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/. -->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
- <style>
- use:not(:target) {
- display: none;
- }
- use {
- fill: #808080;
- }
- use[id$="-added"] {
- fill: #ee4056;
- }
- </style>
- <defs>
- <path id="pocket-mark-shape" d="M21.901,4.204C21.642,3.484,20.956,3,20.196,3h-0.01h-1.721H3.814C3.067,3,2.385,3.474,2.119,4.179 C2.04,4.388,2,4.606,2,4.828v6.082l0.069,1.21c0.29,2.751,1.707,5.155,3.899,6.832c0.039,0.03,0.079,0.06,0.119,0.089l0.025,0.018 c1.175,0.866,2.491,1.452,3.91,1.741C10.677,20.932,11.347,21,12.013,21c0.615,0,1.232-0.057,1.839-0.171 c0.073-0.014,0.145-0.028,0.219-0.044c0.02-0.004,0.042-0.012,0.064-0.023c1.359-0.299,2.621-0.87,3.753-1.704l0.025-0.018 c0.04-0.029,0.08-0.059,0.119-0.089c2.192-1.677,3.609-4.08,3.898-6.832L22,10.91V4.828C22,4.618,21.975,4.409,21.901,4.204z M17.667,10.539l-4.704,4.547c-0.266,0.256-0.608,0.385-0.949,0.385c-0.342,0-0.684-0.129-0.949-0.385l-4.705-4.547 c-0.547-0.528-0.565-1.403-0.04-1.954c0.524-0.551,1.392-0.569,1.939-0.041l3.756,3.63l3.755-3.63 c0.547-0.528,1.415-0.51,1.939,0.04C18.231,9.136,18.213,10.011,17.667,10.539z"/>
- </defs>
- <use id="pocket-mark" xlink:href="#pocket-mark-shape"/>
- <use id="pocket-mark-added" xlink:href="#pocket-mark-shape"/>
-</svg>
diff --git a/browser/extensions/pocket/content/panels/img/pocketerror@1x.png b/browser/extensions/pocket/content/panels/img/pocketerror@1x.png Binary files differdeleted file mode 100644 index e2b4d04de..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketerror@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketerror@2x.png b/browser/extensions/pocket/content/panels/img/pocketerror@2x.png Binary files differdeleted file mode 100644 index d501503b0..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketerror@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketlogo@1x.png b/browser/extensions/pocket/content/panels/img/pocketlogo@1x.png Binary files differdeleted file mode 100644 index 62b3db310..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketlogo@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketlogo@2x.png b/browser/extensions/pocket/content/panels/img/pocketlogo@2x.png Binary files differdeleted file mode 100644 index b0e80bff3..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketlogo@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.png b/browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.png Binary files differdeleted file mode 100644 index 77dc16f8c..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.png b/browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.png Binary files differdeleted file mode 100644 index c467c5a29..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketmenuitem16.png b/browser/extensions/pocket/content/panels/img/pocketmenuitem16.png Binary files differdeleted file mode 100644 index b52db6abf..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketmenuitem16.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.png b/browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.png Binary files differdeleted file mode 100644 index 69aa55b03..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.png Binary files differdeleted file mode 100644 index 12326fae3..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.png Binary files differdeleted file mode 100644 index 5bdebc5e9..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.png Binary files differdeleted file mode 100644 index c4a7ad677..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.png Binary files differdeleted file mode 100644 index 157304c3e..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.png Binary files differdeleted file mode 100644 index 80c5bd486..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.png Binary files differdeleted file mode 100644 index 36d0add61..000000000 --- a/browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.png b/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.png Binary files differdeleted file mode 100644 index 52cbe052c..000000000 --- a/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.png b/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.png Binary files differdeleted file mode 100644 index cd218805e..000000000 --- a/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/signup_help@1x.png b/browser/extensions/pocket/content/panels/img/signup_help@1x.png Binary files differdeleted file mode 100644 index 5019025c0..000000000 --- a/browser/extensions/pocket/content/panels/img/signup_help@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/signup_help@2x.png b/browser/extensions/pocket/content/panels/img/signup_help@2x.png Binary files differdeleted file mode 100644 index 6714bb3bc..000000000 --- a/browser/extensions/pocket/content/panels/img/signup_help@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/signup_or@1x.png b/browser/extensions/pocket/content/panels/img/signup_or@1x.png Binary files differdeleted file mode 100644 index 318cea0f6..000000000 --- a/browser/extensions/pocket/content/panels/img/signup_or@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/signup_or@2x.png b/browser/extensions/pocket/content/panels/img/signup_or@2x.png Binary files differdeleted file mode 100644 index 837f1814a..000000000 --- a/browser/extensions/pocket/content/panels/img/signup_or@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/tag_close@1x.png b/browser/extensions/pocket/content/panels/img/tag_close@1x.png Binary files differdeleted file mode 100644 index 2dd02ba02..000000000 --- a/browser/extensions/pocket/content/panels/img/tag_close@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/tag_close@2x.png b/browser/extensions/pocket/content/panels/img/tag_close@2x.png Binary files differdeleted file mode 100644 index 8bd0eec57..000000000 --- a/browser/extensions/pocket/content/panels/img/tag_close@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/tag_closeactive@1x.png b/browser/extensions/pocket/content/panels/img/tag_closeactive@1x.png Binary files differdeleted file mode 100644 index ad4239232..000000000 --- a/browser/extensions/pocket/content/panels/img/tag_closeactive@1x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/img/tag_closeactive@2x.png b/browser/extensions/pocket/content/panels/img/tag_closeactive@2x.png Binary files differdeleted file mode 100644 index 80c35e3aa..000000000 --- a/browser/extensions/pocket/content/panels/img/tag_closeactive@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/content/panels/js/messages.js b/browser/extensions/pocket/content/panels/js/messages.js deleted file mode 100644 index ae08c3e73..000000000 --- a/browser/extensions/pocket/content/panels/js/messages.js +++ /dev/null @@ -1,78 +0,0 @@ -// Documentation of methods used here are at: -// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages - -var pktPanelMessaging = (function() { - - function panelIdFromURL(url) { - var panelId = url.match(/panelId=([\w|\d|\.]*)&?/); - if (panelId && panelId.length > 1) { - return panelId[1]; - } - - return 0; - } - - function prefixedMessageId(messageId) { - return 'PKT_' + messageId; - } - - function panelPrefixedMessageId(panelId, messageId) { - return prefixedMessageId(panelId + '_' + messageId); - } - - function addMessageListener(panelId, messageId, callback) { - document.addEventListener(panelPrefixedMessageId(panelId, messageId), function(e) { - - callback(JSON.parse(e.target.getAttribute("payload"))[0]); - - // TODO: Figure out why e.target.parentNode is null - // e.target.parentNode.removeChild(e.target); - - }, false); - - } - - function removeMessageListener(panelId, messageId, callback) { - document.removeEventListener(panelPrefixedMessageId(panelId, messageId), callback); - } - - function sendMessage(panelId, messageId, payload, callback) { - // Payload needs to be an object in format: - // { panelId: panelId, data: {} } - var messagePayload = { - panelId: panelId, - data: (payload || {}) - }; - - // Create a callback to listen for a response - if (callback) { - var messageResponseId = messageId + "Response"; - var responseListener = function(responsePayload) { - callback(responsePayload); - removeMessageListener(panelId, messageResponseId, responseListener); - } - - addMessageListener(panelId, messageResponseId, responseListener); - } - - // Send message - var element = document.createElement("PKTMessageFromPanelElement"); - element.setAttribute("payload", JSON.stringify([messagePayload])); - document.documentElement.appendChild(element); - - var evt = document.createEvent("Events"); - evt.initEvent(prefixedMessageId(messageId), true, false); - element.dispatchEvent(evt); - } - - - /** - * Public functions - */ - return { - panelIdFromURL: panelIdFromURL, - addMessageListener : addMessageListener, - removeMessageListener : removeMessageListener, - sendMessage: sendMessage - }; -}()); diff --git a/browser/extensions/pocket/content/panels/js/saved.js b/browser/extensions/pocket/content/panels/js/saved.js deleted file mode 100644 index 3abc8889a..000000000 --- a/browser/extensions/pocket/content/panels/js/saved.js +++ /dev/null @@ -1,608 +0,0 @@ -/* -PKT_SAVED_OVERLAY is the view itself and contains all of the methods to manipute the overlay and messaging. -It does not contain any logic for saving or communication with the extension or server. -*/ -var PKT_SAVED_OVERLAY = function (options) -{ - var myself = this; - this.inited = false; - this.active = false; - this.wrapper = null; - this.pockethost = "getpocket.com"; - this.savedItemId = 0; - this.savedUrl = ''; - this.premiumStatus = false; - this.preventCloseTimerCancel = false; - this.closeValid = true; - this.mouseInside = false; - this.autocloseTimer = null; - this.inoverflowmenu = false; - this.dictJSON = {}; - this.autocloseTiming = 3500; - this.autocloseTimingFinalState = 2000; - this.mouseInside = false; - this.userTags = []; - this.cxt_suggested_available = 0; - this.cxt_entered = 0; - this.cxt_suggested = 0; - this.cxt_removed = 0; - this.justaddedsuggested = false; - this.fillTagContainer = function(tags, container, tagclass) { - container.children().remove(); - for (var i = 0; i < tags.length; i++) { - var newtag = $('<li><a href="#" class="token_tag"></a></li>'); - newtag.find('a').text(tags[i]); - newtag.addClass(tagclass); - container.append(newtag); - this.cxt_suggested_available++; - } - }; - this.fillUserTags = function() { - thePKT_SAVED.sendMessage("getTags", {}, function(resp) - { - if (typeof resp == 'object' && typeof resp.tags == 'object') - { - myself.userTags = resp.tags; - } - }); - }; - this.fillSuggestedTags = function() - { - if (!$('.pkt_ext_suggestedtag_detail').length) - { - myself.suggestedTagsLoaded = true; - myself.startCloseTimer(); - return; - } - - thePKT_SAVED.sendMessage("getSuggestedTags", - { - url: myself.savedUrl - }, function(resp) - { - $('.pkt_ext_suggestedtag_detail').removeClass('pkt_ext_suggestedtag_detail_loading'); - if (resp.status == 'success') - { - var newtags = []; - for (var i = 0; i < resp.value.suggestedTags.length; i++) - { - newtags.push(resp.value.suggestedTags[i].tag); - } - myself.suggestedTagsLoaded = true; - if (!myself.mouseInside) { - myself.startCloseTimer(); - } - myself.fillTagContainer(newtags, $('.pkt_ext_suggestedtag_detail ul'), 'token_suggestedtag'); - } - else if (resp.status == 'error') { - var msg = $('<p class="suggestedtag_msg">'); - msg.text(resp.error.message); - $('.pkt_ext_suggestedtag_detail').append(msg); - this.suggestedTagsLoaded = true; - if (!myself.mouseInside) { - myself.startCloseTimer(); - } - } - }); - } - this.initAutoCloseEvents = function() { - this.wrapper.on('mouseenter', function() { - myself.mouseInside = true; - myself.stopCloseTimer(); - }); - this.wrapper.on('mouseleave', function() { - myself.mouseInside = false; - myself.startCloseTimer(); - }); - this.wrapper.on('click', function(e) { - myself.closeValid = false; - }); - }; - this.startCloseTimer = function(manualtime) - { - var settime = manualtime ? manualtime : myself.autocloseTiming; - if (typeof myself.autocloseTimer == 'number') - { - clearTimeout(myself.autocloseTimer); - } - myself.autocloseTimer = setTimeout(function() - { - if (myself.closeValid || myself.preventCloseTimerCancel) - { - myself.preventCloseTimerCancel = false; - myself.closePopup(); - } - }, settime); - }; - this.stopCloseTimer = function() - { - if (myself.preventCloseTimerCancel) - { - return; - } - clearTimeout(myself.autocloseTimer); - }; - this.closePopup = function() { - myself.stopCloseTimer(); - thePKT_SAVED.sendMessage("close"); - }; - this.checkValidTagSubmit = function() { - var inputlength = $.trim($('.pkt_ext_tag_input_wrapper').find('.token-input-input-token').children('input').val()).length; - if ($('.pkt_ext_containersaved').find('.token-input-token').length || (inputlength > 0 && inputlength < 26)) - { - $('.pkt_ext_containersaved').find('.pkt_ext_btn').removeClass('pkt_ext_btn_disabled'); - } - else - { - $('.pkt_ext_containersaved').find('.pkt_ext_btn').addClass('pkt_ext_btn_disabled'); - } - myself.updateSlidingTagList(); - }; - this.updateSlidingTagList = function() { - var inputleft = $('.token-input-input-token input').position().left; - var listleft = $('.token-input-list').position().left; - var listleftmanual = parseInt($('.token-input-list').css('left')); - var listleftnatural = listleft - listleftmanual; - var leftwidth = $('.pkt_ext_tag_input_wrapper').outerWidth(); - - if ((inputleft + listleft + 20) > leftwidth) - { - $('.token-input-list').css('left', Math.min(((inputleft + listleftnatural - leftwidth + 20)*-1), 0) + 'px'); - } - else - { - $('.token-input-list').css('left', '0'); - } - }; - this.checkPlaceholderStatus = function() { - if (this.wrapper.find('.pkt_ext_tag_input_wrapper').find('.token-input-token').length) - { - this.wrapper.find('.token-input-input-token input').attr('placeholder', ''); - } - else - { - this.wrapper.find('.token-input-input-token input').attr('placeholder', $('.pkt_ext_tag_input').attr('placeholder')).css('width', '200px'); - } - }; - this.initTagInput = function() { - var inputwrapper = $('.pkt_ext_tag_input_wrapper'); - inputwrapper.find('.pkt_ext_tag_input').tokenInput([], { - searchDelay: 200, - minChars: 1, - animateDropdown: false, - noResultsHideDropdown: true, - scrollKeyboard: true, - emptyInputLength: 200, - search_function: function(term, cb) { - var returnlist = []; - if (term.length) { - var limit = 15; - var r = new RegExp('^' + term); - for (var i = 0; i < myself.userTags.length; i++) { - if (r.test(myself.userTags[i]) && limit > 0) { - returnlist.push({name:myself.userTags[i]}); - limit--; - } - } - } - if (!$('.token-input-dropdown-tag').data('init')) { - $('.token-input-dropdown-tag').css('width', inputwrapper.outerWidth()).data('init'); - inputwrapper.append($('.token-input-dropdown-tag')); - } - cb(returnlist); - }, - textToData: function(text) { - if ($.trim(text).length > 25 || !$.trim(text).length) { - if (text.length > 25) { - myself.showTagsError(myself.dictJSON.maxtaglength); - changestamp = Date.now(); - setTimeout(function() { - $('.token-input-input-token input').val(text).focus(); - }, 10); - } - return null; - } - myself.hideTagsError(); - return {name:myself.sanitizeText(text.toLowerCase())}; - }, - onReady: function() { - $('.token-input-dropdown').addClass('token-input-dropdown-tag'); - inputwrapper.find('.token-input-input-token input').attr('placeholder', $('.tag-input').attr('placeholder')).css('width', '200px'); - if ($('.pkt_ext_suggestedtag_detail').length) { - myself.wrapper.find('.pkt_ext_suggestedtag_detail').on('click', '.token_tag', function(e) { - e.preventDefault(); - var tag = $(e.target); - if ($(this).parents('.pkt_ext_suggestedtag_detail_disabled').length) { - return; - } - myself.justaddedsuggested = true; - inputwrapper.find('.pkt_ext_tag_input').tokenInput('add', {id:inputwrapper.find('.token-input-token').length, name:tag.text()}); - tag.addClass('token-suggestedtag-inactive'); - $('.token-input-input-token input').focus(); - }); - } - $('.token-input-list').on('keydown', 'input', function(e) { - if (e.which == 37) { - myself.updateSlidingTagList(); - } - }).on('keypress', 'input', function(e) { - if (e.which == 13) { - if (typeof changestamp == 'undefined' || (Date.now() - changestamp > 250)) { - e.preventDefault(); - myself.wrapper.find('.pkt_ext_btn').trigger('click'); - } - } - }).on('keyup', 'input', function(e) { - myself.checkValidTagSubmit(); - }); - myself.checkPlaceholderStatus(); - }, - onAdd: function() { - myself.checkValidTagSubmit(); - changestamp = Date.now(); - myself.hideInactiveTags(); - myself.checkPlaceholderStatus(); - }, - onDelete: function() { - myself.checkValidTagSubmit(); - changestamp = Date.now(); - myself.showActiveTags(); - myself.checkPlaceholderStatus(); - }, - onShowDropdown: function() { - thePKT_SAVED.sendMessage("expandSavePanel"); - }, - onHideDropdown: function() { - thePKT_SAVED.sendMessage("collapseSavePanel"); - } - }); - $('body').on('keydown', function(e) { - var key = e.keyCode || e.which; - if (key == 8) { - var selected = $('.token-input-selected-token'); - if (selected.length) { - e.preventDefault(); - e.stopImmediatePropagation(); - inputwrapper.find('.pkt_ext_tag_input').tokenInput('remove', {name:selected.find('p').text()}); - } - } - else if ($(e.target).parent().hasClass('token-input-input-token')) { - e.stopImmediatePropagation(); - } - }); - }; - this.disableInput = function() { - this.wrapper.find('.pkt_ext_item_actions').addClass('pkt_ext_item_actions_disabled'); - this.wrapper.find('.pkt_ext_btn').addClass('pkt_ext_btn_disabled'); - this.wrapper.find('.pkt_ext_tag_input_wrapper').addClass('pkt_ext_tag_input_wrapper_disabled'); - if (this.wrapper.find('.pkt_ext_suggestedtag_detail').length) { - this.wrapper.find('.pkt_ext_suggestedtag_detail').addClass('pkt_ext_suggestedtag_detail_disabled'); - } - }; - this.enableInput = function() { - this.wrapper.find('.pkt_ext_item_actions').removeClass('pkt_ext_item_actions_disabled'); - this.checkValidTagSubmit(); - this.wrapper.find('.pkt_ext_tag_input_wrapper').removeClass('pkt_ext_tag_input_wrapper_disabled'); - if (this.wrapper.find('.pkt_ext_suggestedtag_detail').length) { - this.wrapper.find('.pkt_ext_suggestedtag_detail').removeClass('pkt_ext_suggestedtag_detail_disabled'); - } - }; - this.initAddTagInput = function() { - $('.pkt_ext_btn').click(function(e) { - e.preventDefault(); - if ($(this).hasClass('pkt_ext_btn_disabled') || $('.pkt_ext_edit_msg_active').filter('.pkt_ext_edit_msg_error').length) - { - return; - } - myself.disableInput(); - $('.pkt_ext_containersaved').find('.pkt_ext_detail h2').text(myself.dictJSON.processingtags); - var originaltags = []; - $('.token-input-token').each(function() - { - var text = $.trim($(this).find('p').text()); - if (text.length) - { - originaltags.push(text); - } - }); - - thePKT_SAVED.sendMessage("addTags", - { - url: myself.savedUrl, - tags: originaltags - }, function(resp) - { - if (resp.status == 'success') - { - myself.showStateFinalMsg(myself.dictJSON.tagssaved); - } - else if (resp.status == 'error') - { - $('.pkt_ext_edit_msg').addClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(resp.error.message); - } - }); - }); - }; - this.initRemovePageInput = function() { - $('.pkt_ext_removeitem').click(function(e) { - if ($(this).parents('.pkt_ext_item_actions_disabled').length) { - e.preventDefault(); - return; - } - if ($(this).hasClass('pkt_ext_removeitem')) { - e.preventDefault(); - myself.disableInput(); - $('.pkt_ext_containersaved').find('.pkt_ext_detail h2').text(myself.dictJSON.processingremove); - - thePKT_SAVED.sendMessage("deleteItem", - { - itemId: myself.savedItemId - }, function(resp) { - if (resp.status == 'success') { - myself.showStateFinalMsg(myself.dictJSON.pageremoved); - } - else if (resp.status == 'error') { - $('.pkt_ext_edit_msg').addClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(resp.error.message); - } - }); - } - }); - }; - this.initOpenListInput = function() { - $('.pkt_ext_openpocket').click(function(e) - { - e.preventDefault(); - thePKT_SAVED.sendMessage("openTabWithUrl", - { - url: $(this).attr('href'), - activate: true - }); - myself.closePopup(); - }); - }; - this.showTagsError = function(msg) { - $('.pkt_ext_edit_msg').addClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(msg); - $('.pkt_ext_tag_detail').addClass('pkt_ext_tag_error'); - }; - this.hideTagsError = function(msg) { - $('.pkt_ext_edit_msg').removeClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(''); - $('.pkt_ext_tag_detail').removeClass('pkt_ext_tag_error'); - }; - this.showActiveTags = function() { - if (!$('.pkt_ext_suggestedtag_detail').length) { - return; - } - var activetokenstext = '|'; - $('.token-input-token').each(function(index, element) { - activetokenstext += $(element).find('p').text() + '|'; - }); - - var inactivetags = $('.pkt_ext_suggestedtag_detail').find('.token_tag_inactive'); - inactivetags.each(function(index, element) { - if (activetokenstext.indexOf('|' + $(element).text() + '|') == -1) { - $(element).removeClass('token_tag_inactive'); - } - }); - }; - this.hideInactiveTags = function() { - if (!$('.pkt_ext_suggestedtag_detail').length) { - return; - } - var activetokenstext = '|'; - $('.token-input-token').each(function(index, element) { - activetokenstext += $(element).find('p').text() + '|'; - }); - var activesuggestedtags = $('.token_tag').not('.token_tag_inactive'); - activesuggestedtags.each(function(index, element) { - if (activetokenstext.indexOf('|' + $(element).text() + '|') > -1) { - $(element).addClass('token_tag_inactive'); - } - }); - }; - this.showStateSaved = function(initobj) { - this.wrapper.find('.pkt_ext_detail h2').text(this.dictJSON.pagesaved); - this.wrapper.find('.pkt_ext_btn').addClass('pkt_ext_btn_disabled'); - if (typeof initobj.item == 'object') - { - this.savedItemId = initobj.item.item_id; - this.savedUrl = initobj.item.given_url; - } - $('.pkt_ext_containersaved').addClass('pkt_ext_container_detailactive').removeClass('pkt_ext_container_finalstate'); - - myself.fillUserTags(); - if (myself.suggestedTagsLoaded) { - myself.startCloseTimer(); - } - else { - myself.fillSuggestedTags(); - } - }; - this.sanitizeText = function(s) { - var sanitizeMap = { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''' - }; - if (typeof s !== 'string') - { - return ''; - } - return String(s).replace(/[&<>"']/g, function (str) { - return sanitizeMap[str]; - }); - }; - this.showStateFinalMsg = function(msg) { - this.wrapper.find('.pkt_ext_tag_detail').one('webkitTransitionEnd transitionend msTransitionEnd oTransitionEnd', function(e) - { - $(this).off('webkitTransitionEnd transitionend msTransitionEnd oTransitionEnd'); - myself.preventCloseTimerCancel = true; - myself.startCloseTimer(myself.autocloseTimingFinalState); - myself.wrapper.find('.pkt_ext_detail h2').text(msg); - }); - this.wrapper.addClass('pkt_ext_container_finalstate'); - }; - this.showStateError = function(headline, detail) { - this.wrapper.find('.pkt_ext_detail h2').text(headline); - this.wrapper.find('.pkt_ext_detail h3').text(detail); - this.wrapper.addClass('pkt_ext_container_detailactive pkt_ext_container_finalstate pkt_ext_container_finalerrorstate'); - this.preventCloseTimerCancel = true; - this.startCloseTimer(myself.autocloseTimingFinalState); - } - this.getTranslations = function() - { - this.dictJSON = window.pocketStrings; - }; -}; - -PKT_SAVED_OVERLAY.prototype = { - create : function() - { - if (this.active) - { - return; - } - this.active = true; - - // set translations - this.getTranslations(); - - // set host - this.dictJSON.pockethost = this.pockethost; - - // extra modifier class for collapsed state - if (this.inoverflowmenu) - { - $('body').addClass('pkt_ext_saved_overflow'); - } - - // extra modifier class for language - if (this.locale) - { - $('body').addClass('pkt_ext_saved_' + this.locale); - } - - // Create actual content - $('body').append(Handlebars.templates.saved_shell(this.dictJSON)); - - // Add in premium content (if applicable based on premium status) - this.createPremiumFunctionality(); - - // Initialize functionality for overlay - this.wrapper = $('.pkt_ext_containersaved'); - this.initTagInput(); - this.initAddTagInput(); - this.initRemovePageInput(); - this.initOpenListInput(); - this.initAutoCloseEvents(); - }, - createPremiumFunctionality: function() - { - if (this.premiumStatus && !$('.pkt_ext_suggestedtag_detail').length) - { - $('body').append(Handlebars.templates.saved_premiumshell(this.dictJSON)); - $('.pkt_ext_initload').append(Handlebars.templates.saved_premiumextras(this.dictJSON)); - } - } -}; - - -// Layer between Bookmarklet and Extensions -var PKT_SAVED = function () {}; - -PKT_SAVED.prototype = { - init: function () { - if (this.inited) { - return; - } - this.panelId = pktPanelMessaging.panelIdFromURL(window.location.href); - this.overlay = new PKT_SAVED_OVERLAY(); - - this.inited = true; - }, - - addMessageListener: function(messageId, callback) { - pktPanelMessaging.addMessageListener(this.panelId, messageId, callback); - }, - - sendMessage: function(messageId, payload, callback) { - pktPanelMessaging.sendMessage(this.panelId, messageId, payload, callback); - }, - - create: function() { - var myself = this; - var url = window.location.href.match(/premiumStatus=([\w|\d|\.]*)&?/); - if (url && url.length > 1) - { - myself.overlay.premiumStatus = (url[1] == '1'); - } - var host = window.location.href.match(/pockethost=([\w|\.]*)&?/); - if (host && host.length > 1) - { - myself.overlay.pockethost = host[1]; - } - var inoverflowmenu = window.location.href.match(/inoverflowmenu=([\w|\.]*)&?/); - if (inoverflowmenu && inoverflowmenu.length > 1) - { - myself.overlay.inoverflowmenu = (inoverflowmenu[1] == 'true'); - } - var locale = window.location.href.match(/locale=([\w|\.]*)&?/); - if (locale && locale.length > 1) - { - myself.overlay.locale = locale[1].toLowerCase(); - } - - myself.overlay.create(); - - // tell back end we're ready - thePKT_SAVED.sendMessage("show"); - - // wait confirmation of save before flipping to final saved state - thePKT_SAVED.addMessageListener("saveLink", function(resp) - { - if (resp.status == 'error') { - if (typeof resp.error == 'object') - { - if (resp.error.localizedKey) - { - myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved, myself.overlay.dictJSON[resp.error.localizedKey]); - } - else - { - myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved, resp.error.message); - } - } - else - { - myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved, myself.overlay.dictJSON.errorgeneric); - } - return; - } - - myself.overlay.showStateSaved(resp); - }); - - } -} - -$(function() -{ - if (!window.thePKT_SAVED) { - var thePKT_SAVED = new PKT_SAVED(); - window.thePKT_SAVED = thePKT_SAVED; - thePKT_SAVED.init(); - } - - var pocketHost = thePKT_SAVED.overlay.pockethost; - // send an async message to get string data - thePKT_SAVED.sendMessage("initL10N", { - tos: [ - 'https://'+ pocketHost +'/tos?s=ffi&t=tos&tv=panel_tryit', - 'https://'+ pocketHost +'/privacy?s=ffi&t=privacypolicy&tv=panel_tryit' - ] - }, function(resp) { - window.pocketStrings = resp.strings; - window.thePKT_SAVED.create(); - }); -}); diff --git a/browser/extensions/pocket/content/panels/js/signup.js b/browser/extensions/pocket/content/panels/js/signup.js deleted file mode 100644 index af55cc2a7..000000000 --- a/browser/extensions/pocket/content/panels/js/signup.js +++ /dev/null @@ -1,193 +0,0 @@ -/* -PKT_SIGNUP_OVERLAY is the view itself and contains all of the methods to manipute the overlay and messaging. -It does not contain any logic for saving or communication with the extension or server. -*/ -var PKT_SIGNUP_OVERLAY = function (options) -{ - var myself = this; - this.inited = false; - this.active = false; - this.delayedStateSaved = false; - this.wrapper = null; - this.variant = window.___PKT__SIGNUP_VARIANT; - this.tagline = window.___PKT__SIGNUP_TAGLINE || ''; - this.preventCloseTimerCancel = false; - this.translations = {}; - this.closeValid = true; - this.mouseInside = false; - this.autocloseTimer = null; - this.variant = ""; - this.inoverflowmenu = false; - this.controlvariant; - this.pockethost = "getpocket.com"; - this.fxasignedin = false; - this.dictJSON = {}; - this.initCloseTabEvents = function() { - $('.btn,.pkt_ext_learnmore,.alreadyhave > a').click(function(e) - { - e.preventDefault(); - thePKT_SIGNUP.sendMessage("openTabWithUrl", - { - url: $(this).attr('href'), - activate: true - }); - myself.closePopup(); - }); - }; - this.closePopup = function() { - thePKT_SIGNUP.sendMessage("close"); - }; - this.sanitizeText = function(s) { - var sanitizeMap = { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''' - }; - if (typeof s !== 'string') - { - return ''; - } - return String(s).replace(/[&<>"']/g, function (str) { - return sanitizeMap[str]; - }); - }; - this.getTranslations = function() - { - this.dictJSON = window.pocketStrings; - }; - -}; - -PKT_SIGNUP_OVERLAY.prototype = { - create : function() - { - var controlvariant = window.location.href.match(/controlvariant=([\w|\.]*)&?/); - if (controlvariant && controlvariant.length > 1) - { - this.controlvariant = controlvariant[1]; - } - var variant = window.location.href.match(/variant=([\w|\.]*)&?/); - if (variant && variant.length > 1) - { - this.variant = variant[1]; - } - var fxasignedin = window.location.href.match(/fxasignedin=([\w|\d|\.]*)&?/); - if (fxasignedin && fxasignedin.length > 1) - { - this.fxasignedin = (fxasignedin[1] == '1'); - } - var host = window.location.href.match(/pockethost=([\w|\.]*)&?/); - if (host && host.length > 1) - { - this.pockethost = host[1]; - } - var inoverflowmenu = window.location.href.match(/inoverflowmenu=([\w|\.]*)&?/); - if (inoverflowmenu && inoverflowmenu.length > 1) - { - this.inoverflowmenu = (inoverflowmenu[1] == 'true'); - } - var locale = window.location.href.match(/locale=([\w|\.]*)&?/); - if (locale && locale.length > 1) - { - this.locale = locale[1].toLowerCase(); - } - - if (this.active) - { - return; - } - this.active = true; - - // set translations - this.getTranslations(); - this.dictJSON.fxasignedin = this.fxasignedin ? 1 : 0; - this.dictJSON.controlvariant = this.controlvariant == 'true' ? 1 : 0; - this.dictJSON.variant = (this.variant ? this.variant : 'undefined'); - this.dictJSON.variant += this.fxasignedin ? '_fxa' : '_nonfxa'; - this.dictJSON.pockethost = this.pockethost; - this.dictJSON.showlearnmore = true; - - // extra modifier class for collapsed state - if (this.inoverflowmenu) - { - $('body').addClass('pkt_ext_signup_overflow'); - } - - // extra modifier class for language - if (this.locale) - { - $('body').addClass('pkt_ext_signup_' + this.locale); - } - - // Create actual content - if (this.variant == 'overflow') - { - $('body').append(Handlebars.templates.signup_shell(this.dictJSON)); - } - else - { - $('body').append(Handlebars.templates.signupstoryboard_shell(this.dictJSON)); - } - - - // tell background we're ready - thePKT_SIGNUP.sendMessage("show"); - - // close events - this.initCloseTabEvents(); - } -}; - - -// Layer between Bookmarklet and Extensions -var PKT_SIGNUP = function () {}; - -PKT_SIGNUP.prototype = { - init: function () { - if (this.inited) { - return; - } - this.panelId = pktPanelMessaging.panelIdFromURL(window.location.href); - this.overlay = new PKT_SIGNUP_OVERLAY(); - - this.inited = true; - }, - - addMessageListener: function(messageId, callback) { - pktPanelMessaging.addMessageListener(this.panelId, messageId, callback); - }, - - sendMessage: function(messageId, payload, callback) { - pktPanelMessaging.sendMessage(this.panelId, messageId, payload, callback); - }, - - create: function() { - this.overlay.create(); - - // tell back end we're ready - thePKT_SIGNUP.sendMessage("show"); - } -} - -$(function() -{ - if (!window.thePKT_SIGNUP) { - var thePKT_SIGNUP = new PKT_SIGNUP(); - window.thePKT_SIGNUP = thePKT_SIGNUP; - thePKT_SIGNUP.init(); - } - - var pocketHost = thePKT_SIGNUP.overlay.pockethost; - // send an async message to get string data - thePKT_SIGNUP.sendMessage("initL10N", { - tos: [ - 'https://'+ pocketHost +'/tos?s=ffi&t=tos&tv=panel_tryit', - 'https://'+ pocketHost +'/privacy?s=ffi&t=privacypolicy&tv=panel_tryit' - ] - }, function(resp) { - window.pocketStrings = resp.strings; - window.thePKT_SIGNUP.create(); - }); -}); diff --git a/browser/extensions/pocket/content/panels/js/tmpl.js b/browser/extensions/pocket/content/panels/js/tmpl.js deleted file mode 100644 index a03ffda70..000000000 --- a/browser/extensions/pocket/content/panels/js/tmpl.js +++ /dev/null @@ -1,242 +0,0 @@ -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['saved_premiumextras'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - return "<div class=\"pkt_ext_suggestedtag_detailshown\">\r\n</div> "; - },"useData":true}); -templates['saved_premiumshell'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return "<div class=\"pkt_ext_suggestedtag_detail pkt_ext_suggestedtag_detail_loading\">\n <h4>" - + escapeExpression(((helper = (helper = helpers.suggestedtags || (depth0 != null ? depth0.suggestedtags : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"suggestedtags","hash":{},"data":data}) : helper))) - + "</h4>\n <div class=\"pkt_ext_loadingspinner\"><div></div></div>\n <ul class=\"pkt_ext_cf\">\n </ul>\n</div>"; -},"useData":true}); -templates['saved_shell'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return "<div class=\"pkt_ext_initload\">\n <div class=\"pkt_ext_logo\"></div> \n <div class=\"pkt_ext_topdetail\">\n <h2>" - + escapeExpression(((helper = (helper = helpers.saving || (depth0 != null ? depth0.saving : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"saving","hash":{},"data":data}) : helper))) - + "</h2>\n </div> \n <div class=\"pkt_ext_loadingspinner\"><div></div></div>\n</div> \n<div class=\"pkt_ext_detail\"> \n <div class=\"pkt_ext_logo\"></div>\n <div class=\"pkt_ext_topdetail\">\n <h2>" - + escapeExpression(((helper = (helper = helpers.pagesaved || (depth0 != null ? depth0.pagesaved : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pagesaved","hash":{},"data":data}) : helper))) - + "</h2>\n <h3 class=\"pkt_ext_errordetail\"></h3>\n <nav class=\"pkt_ext_item_actions pkt_ext_cf\">\n <ul>\n <li><a class=\"pkt_ext_removeitem\" href=\"#\">" - + escapeExpression(((helper = (helper = helpers.removepage || (depth0 != null ? depth0.removepage : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"removepage","hash":{},"data":data}) : helper))) - + "</a></li>\n <li class=\"pkt_ext_actions_separator\"></li> \n <li><a class=\"pkt_ext_openpocket\" href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/a?src=ff_ext_saved\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.viewlist || (depth0 != null ? depth0.viewlist : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"viewlist","hash":{},"data":data}) : helper))) - + "</a></li>\n </ul>\n </nav> \n </div>\n <div class=\"pkt_ext_tag_detail pkt_ext_cf\">\n <div class=\"pkt_ext_tag_input_wrapper\">\n <div class=\"pkt_ext_tag_input_blocker\"></div>\n <input class=\"pkt_ext_tag_input\" type=\"text\" placeholder=\"" - + escapeExpression(((helper = (helper = helpers.addtags || (depth0 != null ? depth0.addtags : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"addtags","hash":{},"data":data}) : helper))) - + "\">\n </div>\n <a href=\"#\" class=\"pkt_ext_btn pkt_ext_btn_disabled\">" - + escapeExpression(((helper = (helper = helpers.save || (depth0 != null ? depth0.save : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"save","hash":{},"data":data}) : helper))) - + "</a>\n </div>\n <p class=\"pkt_ext_edit_msg\"></p>\n</div>"; -},"useData":true}); -templates['signup_shell'] = template({"1":function(depth0,helpers,partials,data) { - var stack1, buffer = ""; - stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.controlvariant : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data}); - if (stack1 != null) { buffer += stack1; } - return buffer; -},"2":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <p class=\"pkt_ext_learnmorecontainer\"><a class=\"pkt_ext_learnmore\" href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/firefox_learnmore?s=ffi&t=learnmore&tv=panel_control&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper))) - + "</a></p>\n"; -},"4":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <p class=\"pkt_ext_learnmorecontainer\"><a class=\"pkt_ext_learnmore\" href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/firefox_learnmore?s=ffi&t=learnmore&tv=panel_tryit&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper))) - + "</a></p>\n"; -},"6":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <p class=\"pkt_ext_learnmorecontainer\"><a class=\"pkt_ext_learnmore pkt_ext_learnmoreinactive\" href=\"#\">" - + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper))) - + "</a></p>\n"; -},"8":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <h4>" - + escapeExpression(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signuptosave","hash":{},"data":data}) : helper))) - + "</h4>\n <p class=\"btn-container\"><a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/ff_signup?s=ffi&t=signupff&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\" class=\"btn signup-btn-firefox\"><span class=\"logo\"></span><span class=\"text\">" - + escapeExpression(((helper = (helper = helpers.signinfirefox || (depth0 != null ? depth0.signinfirefox : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signinfirefox","hash":{},"data":data}) : helper))) - + "</span></a></p>\n <p class=\"alreadyhave\">" - + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) - + " <a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/login?ep=3&src=extension&s=ffi&t=login&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper))) - + "</a>.</p>\n"; -},"10":function(depth0,helpers,partials,data) { - var stack1, buffer = ""; - stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.controlvariant : depth0), {"name":"if","hash":{},"fn":this.program(11, data),"inverse":this.program(13, data),"data":data}); - if (stack1 != null) { buffer += stack1; } - return buffer; -},"11":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <h4>" - + escapeExpression(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signuptosave","hash":{},"data":data}) : helper))) - + "</h4>\n <p class=\"btn-container\"><a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/ff_signup?s=ffi&tv=panel_control&t=signupff&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\" class=\"btn signup-btn-firefox\"><span class=\"logo\"></span><span class=\"text\">" - + escapeExpression(((helper = (helper = helpers.signupfirefox || (depth0 != null ? depth0.signupfirefox : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signupfirefox","hash":{},"data":data}) : helper))) - + "</span></a></p>\n <p class=\"btn-container\"><a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/signup?force=email&tv=panel_control&src=extension&s=ffi&t=signupemail&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\" class=\"btn btn-secondary signup-btn-email signup-btn-initstate\">" - + escapeExpression(((helper = (helper = helpers.signupemail || (depth0 != null ? depth0.signupemail : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signupemail","hash":{},"data":data}) : helper))) - + "</a></p>\n <p class=\"alreadyhave\">" - + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) - + " <a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/login?ep=3&tv=panel_control&src=extension&s=ffi&t=login&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper))) - + "</a>.</p>\n"; -},"13":function(depth0,helpers,partials,data) { - var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = " <p class=\"btn-container\"><a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/firefox_tryitnow?s=ffi&tv=panel_tryit&t=tryitnow\" target=\"_blank\" class=\"btn signup-btn-tryitnow\"><span class=\"text\">" - + escapeExpression(((helper = (helper = helpers.tryitnow || (depth0 != null ? depth0.tryitnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tryitnow","hash":{},"data":data}) : helper))) - + "</span></a></p>\n <p class=\"alreadyhave tryitnowspace\">" - + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) - + " <a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/login?ep=3&s=ffi&tv=panel_tryit&src=extension&t=login&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper))) - + "</a>.</p>\n <p class=\"pkt_ext_tos\">"; - stack1 = ((helper = (helper = helpers.tos || (depth0 != null ? depth0.tos : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tos","hash":{},"data":data}) : helper)); - if (stack1 != null) { buffer += stack1; } - return buffer + "</p>\n"; -},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"pkt_ext_introdetail pkt_ext_introdetailhero\">\n <h2 class=\"pkt_ext_logo\">Pocket</h2>\n <p class=\"pkt_ext_tagline\">" - + escapeExpression(((helper = (helper = helpers.tagline || (depth0 != null ? depth0.tagline : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tagline","hash":{},"data":data}) : helper))) - + "</p>\n"; - stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.showlearnmore : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.program(6, data),"data":data}); - if (stack1 != null) { buffer += stack1; } - buffer += " <div class=\"pkt_ext_introimg\"></div>\n</div>\n<div class=\"pkt_ext_signupdetail pkt_ext_signupdetail_hero\">\n"; - stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.fxasignedin : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.program(10, data),"data":data}); - if (stack1 != null) { buffer += stack1; } - return buffer + "</div>\n"; -},"useData":true}); -templates['signupstoryboard_shell'] = template({"1":function(depth0,helpers,partials,data) { - var stack1, buffer = ""; - stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.controlvariant : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data}); - if (stack1 != null) { buffer += stack1; } - return buffer; -},"2":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <p><a class=\"pkt_ext_learnmore\" href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/firefox_learnmore?s=ffi&t=learnmore&tv=panel_control&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper))) - + "</a></p>\n"; -},"4":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <p><a class=\"pkt_ext_learnmore\" href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/firefox_learnmore?s=ffi&t=learnmore&tv=panel_tryit&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper))) - + "</a></p>\n"; -},"6":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <p><a class=\"pkt_ext_learnmore pkt_ext_learnmoreinactive\" href=\"#\">" - + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper))) - + "</a></p>\n"; -},"8":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <h4>" - + escapeExpression(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signuptosave","hash":{},"data":data}) : helper))) - + "</h4>\n <p class=\"btn-container\"><a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/ff_signup?s=ffi&t=signupff&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\" class=\"btn signup-btn-firefox\"><span class=\"logo\"></span><span class=\"text\">" - + escapeExpression(((helper = (helper = helpers.signinfirefox || (depth0 != null ? depth0.signinfirefox : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signinfirefox","hash":{},"data":data}) : helper))) - + "</span></a></p>\n <p class=\"alreadyhave\">" - + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) - + " <a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/login?ep=3&src=extension&s=ffi&t=login&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper))) - + "</a>.</p>\n"; -},"10":function(depth0,helpers,partials,data) { - var stack1, buffer = ""; - stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.controlvariant : depth0), {"name":"if","hash":{},"fn":this.program(11, data),"inverse":this.program(13, data),"data":data}); - if (stack1 != null) { buffer += stack1; } - return buffer; -},"11":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return " <h4>" - + escapeExpression(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signuptosave","hash":{},"data":data}) : helper))) - + "</h4>\n <p class=\"btn-container\"><a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/ff_signup?s=ffi&tv=panel_control&t=signupff&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\" class=\"btn signup-btn-firefox\"><span class=\"logo\"></span><span class=\"text\">" - + escapeExpression(((helper = (helper = helpers.signupfirefox || (depth0 != null ? depth0.signupfirefox : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signupfirefox","hash":{},"data":data}) : helper))) - + "</span></a></p>\n <p class=\"btn-container\"><a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/signup?force=email&tv=panel_control&src=extension&s=ffi&t=signupemail&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\" class=\"btn btn-secondary signup-btn-email signup-btn-initstate\">" - + escapeExpression(((helper = (helper = helpers.signupemail || (depth0 != null ? depth0.signupemail : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signupemail","hash":{},"data":data}) : helper))) - + "</a></p>\n <p class=\"alreadyhave\">" - + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) - + " <a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/login?ep=3&tv=panel_control&src=extension&s=ffi&t=login&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper))) - + "</a>.</p>\n"; -},"13":function(depth0,helpers,partials,data) { - var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = " <p class=\"btn-container\"><a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/firefox_tryitnow?s=ffi&tv=panel_tryit&t=tryitnow\" target=\"_blank\" class=\"btn signup-btn-tryitnow\"><span class=\"text\">" - + escapeExpression(((helper = (helper = helpers.tryitnow || (depth0 != null ? depth0.tryitnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tryitnow","hash":{},"data":data}) : helper))) - + "</span></a></p>\n <p class=\"alreadyhave tryitnowspace\">" - + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) - + " <a href=\"https://" - + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper))) - + "/login?ep=3&s=ffi&tv=panel_tryit&src=extension&t=login&v=" - + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper))) - + "\" target=\"_blank\">" - + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper))) - + "</a>.</p>\n <p class=\"pkt_ext_tos\">"; - stack1 = ((helper = (helper = helpers.tos || (depth0 != null ? depth0.tos : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tos","hash":{},"data":data}) : helper)); - if (stack1 != null) { buffer += stack1; } - return buffer + "</p>\n"; -},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"pkt_ext_introdetail pkt_ext_introdetailstoryboard\">\n <div class=\"pkt_ext_introstory pkt_ext_introstoryone\">\n <div class=\"pkt_ext_introstory_text\">\n <p class=\"pkt_ext_tagline\">" - + escapeExpression(((helper = (helper = helpers.taglinestory_one || (depth0 != null ? depth0.taglinestory_one : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"taglinestory_one","hash":{},"data":data}) : helper))) - + "</p>\n </div>\n <div class=\"pkt_ext_introstoryone_img\"></div>\n </div>\n <div class=\"pkt_ext_introstorydivider\"></div>\n <div class=\"pkt_ext_introstory pkt_ext_introstorytwo\">\n <div class=\"pkt_ext_introstory_text\">\n <p class=\"pkt_ext_tagline\">" - + escapeExpression(((helper = (helper = helpers.taglinestory_two || (depth0 != null ? depth0.taglinestory_two : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"taglinestory_two","hash":{},"data":data}) : helper))) - + "</p>\n"; - stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.showlearnmore : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.program(6, data),"data":data}); - if (stack1 != null) { buffer += stack1; } - buffer += " </div>\n <div class=\"pkt_ext_introstorytwo_img\"></div>\n </div>\n</div>\n<div class=\"pkt_ext_signupdetail\">\n"; - stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.fxasignedin : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.program(10, data),"data":data}); - if (stack1 != null) { buffer += stack1; } - return buffer + "\n</div>\n"; -},"useData":true}); -})(); diff --git a/browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js b/browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js deleted file mode 100644 index c8bb1c452..000000000 --- a/browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js +++ /dev/null @@ -1,660 +0,0 @@ -/* - - handlebars v2.0.0 - -Copyright (C) 2011-2014 by Yehuda Katz - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -@license -*/ -/* exported Handlebars */ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.Handlebars = root.Handlebars || factory(); - } -}(this, function () { -// handlebars/safe-string.js -var __module3__ = (function() { - "use strict"; - var __exports__; - // Build out our basic SafeString type - function SafeString(string) { - this.string = string; - } - - SafeString.prototype.toString = function() { - return "" + this.string; - }; - - __exports__ = SafeString; - return __exports__; -})(); - -// handlebars/utils.js -var __module2__ = (function(__dependency1__) { - "use strict"; - var __exports__ = {}; - /*jshint -W004 */ - var SafeString = __dependency1__; - - var escape = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", - "`": "`" - }; - - var badChars = /[&<>"'`]/g; - var possible = /[&<>"'`]/; - - function escapeChar(chr) { - return escape[chr]; - } - - function extend(obj /* , ...source */) { - for (var i = 1; i < arguments.length; i++) { - for (var key in arguments[i]) { - if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { - obj[key] = arguments[i][key]; - } - } - } - - return obj; - } - - __exports__.extend = extend;var toString = Object.prototype.toString; - __exports__.toString = toString; - // Sourced from lodash - // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt - var isFunction = function(value) { - return typeof value === 'function'; - }; - // fallback for older versions of Chrome and Safari - /* istanbul ignore next */ - if (isFunction(/x/)) { - isFunction = function(value) { - return typeof value === 'function' && toString.call(value) === '[object Function]'; - }; - } - var isFunction; - __exports__.isFunction = isFunction; - /* istanbul ignore next */ - var isArray = Array.isArray || function(value) { - return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; - }; - __exports__.isArray = isArray; - - function escapeExpression(string) { - // don't escape SafeStrings, since they're already safe - if (string instanceof SafeString) { - return string.toString(); - } else if (string == null) { - return ""; - } else if (!string) { - return string + ''; - } - - // Force a string conversion as this will be done by the append regardless and - // the regex test will do this transparently behind the scenes, causing issues if - // an object's to string has escaped characters in it. - string = "" + string; - - if(!possible.test(string)) { return string; } - return string.replace(badChars, escapeChar); - } - - __exports__.escapeExpression = escapeExpression;function isEmpty(value) { - if (!value && value !== 0) { - return true; - } else if (isArray(value) && value.length === 0) { - return true; - } else { - return false; - } - } - - __exports__.isEmpty = isEmpty;function appendContextPath(contextPath, id) { - return (contextPath ? contextPath + '.' : '') + id; - } - - __exports__.appendContextPath = appendContextPath; - return __exports__; -})(__module3__); - -// handlebars/exception.js -var __module4__ = (function() { - "use strict"; - var __exports__; - - var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; - - function Exception(message, node) { - var line; - if (node && node.firstLine) { - line = node.firstLine; - - message += ' - ' + line + ':' + node.firstColumn; - } - - var tmp = Error.prototype.constructor.call(this, message); - - // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. - for (var idx = 0; idx < errorProps.length; idx++) { - this[errorProps[idx]] = tmp[errorProps[idx]]; - } - - if (line) { - this.lineNumber = line; - this.column = node.firstColumn; - } - } - - Exception.prototype = new Error(); - - __exports__ = Exception; - return __exports__; -})(); - -// handlebars/base.js -var __module1__ = (function(__dependency1__, __dependency2__) { - "use strict"; - var __exports__ = {}; - var Utils = __dependency1__; - var Exception = __dependency2__; - - var VERSION = "2.0.0"; - __exports__.VERSION = VERSION;var COMPILER_REVISION = 6; - __exports__.COMPILER_REVISION = COMPILER_REVISION; - var REVISION_CHANGES = { - 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it - 2: '== 1.0.0-rc.3', - 3: '== 1.0.0-rc.4', - 4: '== 1.x.x', - 5: '== 2.0.0-alpha.x', - 6: '>= 2.0.0-beta.1' - }; - __exports__.REVISION_CHANGES = REVISION_CHANGES; - var isArray = Utils.isArray, - isFunction = Utils.isFunction, - toString = Utils.toString, - objectType = '[object Object]'; - - function HandlebarsEnvironment(helpers, partials) { - this.helpers = helpers || {}; - this.partials = partials || {}; - - registerDefaultHelpers(this); - } - - __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { - constructor: HandlebarsEnvironment, - - logger: logger, - log: log, - - registerHelper: function(name, fn) { - if (toString.call(name) === objectType) { - if (fn) { throw new Exception('Arg not supported with multiple helpers'); } - Utils.extend(this.helpers, name); - } else { - this.helpers[name] = fn; - } - }, - unregisterHelper: function(name) { - delete this.helpers[name]; - }, - - registerPartial: function(name, partial) { - if (toString.call(name) === objectType) { - Utils.extend(this.partials, name); - } else { - this.partials[name] = partial; - } - }, - unregisterPartial: function(name) { - delete this.partials[name]; - } - }; - - function registerDefaultHelpers(instance) { - instance.registerHelper('helperMissing', function(/* [args, ]options */) { - if(arguments.length === 1) { - // A missing field in a {{foo}} constuct. - return undefined; - } else { - // Someone is actually trying to call something, blow up. - throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'"); - } - }); - - instance.registerHelper('blockHelperMissing', function(context, options) { - var inverse = options.inverse, - fn = options.fn; - - if(context === true) { - return fn(this); - } else if(context === false || context == null) { - return inverse(this); - } else if (isArray(context)) { - if(context.length > 0) { - if (options.ids) { - options.ids = [options.name]; - } - - return instance.helpers.each(context, options); - } else { - return inverse(this); - } - } else { - if (options.data && options.ids) { - var data = createFrame(options.data); - data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name); - options = {data: data}; - } - - return fn(context, options); - } - }); - - instance.registerHelper('each', function(context, options) { - if (!options) { - throw new Exception('Must pass iterator to #each'); - } - - var fn = options.fn, inverse = options.inverse; - var i = 0, ret = "", data; - - var contextPath; - if (options.data && options.ids) { - contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; - } - - if (isFunction(context)) { context = context.call(this); } - - if (options.data) { - data = createFrame(options.data); - } - - if(context && typeof context === 'object') { - if (isArray(context)) { - for(var j = context.length; i<j; i++) { - if (data) { - data.index = i; - data.first = (i === 0); - data.last = (i === (context.length-1)); - - if (contextPath) { - data.contextPath = contextPath + i; - } - } - ret = ret + fn(context[i], { data: data }); - } - } else { - for(var key in context) { - if(context.hasOwnProperty(key)) { - if(data) { - data.key = key; - data.index = i; - data.first = (i === 0); - - if (contextPath) { - data.contextPath = contextPath + key; - } - } - ret = ret + fn(context[key], {data: data}); - i++; - } - } - } - } - - if(i === 0){ - ret = inverse(this); - } - - return ret; - }); - - instance.registerHelper('if', function(conditional, options) { - if (isFunction(conditional)) { conditional = conditional.call(this); } - - // Default behavior is to render the positive path if the value is truthy and not empty. - // The `includeZero` option may be set to treat the condtional as purely not empty based on the - // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. - if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) { - return options.inverse(this); - } else { - return options.fn(this); - } - }); - - instance.registerHelper('unless', function(conditional, options) { - return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash}); - }); - - instance.registerHelper('with', function(context, options) { - if (isFunction(context)) { context = context.call(this); } - - var fn = options.fn; - - if (!Utils.isEmpty(context)) { - if (options.data && options.ids) { - var data = createFrame(options.data); - data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]); - options = {data:data}; - } - - return fn(context, options); - } else { - return options.inverse(this); - } - }); - - instance.registerHelper('log', function(message, options) { - var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; - instance.log(level, message); - }); - - instance.registerHelper('lookup', function(obj, field) { - return obj && obj[field]; - }); - } - - var logger = { - methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' }, - - // State enum - DEBUG: 0, - INFO: 1, - WARN: 2, - ERROR: 3, - level: 3, - - // can be overridden in the host environment - log: function(level, message) { - if (logger.level <= level) { - var method = logger.methodMap[level]; - if (typeof console !== 'undefined' && console[method]) { - console[method].call(console, message); - } - } - } - }; - __exports__.logger = logger; - var log = logger.log; - __exports__.log = log; - var createFrame = function(object) { - var frame = Utils.extend({}, object); - frame._parent = object; - return frame; - }; - __exports__.createFrame = createFrame; - return __exports__; -})(__module2__, __module4__); - -// handlebars/runtime.js -var __module5__ = (function(__dependency1__, __dependency2__, __dependency3__) { - "use strict"; - var __exports__ = {}; - var Utils = __dependency1__; - var Exception = __dependency2__; - var COMPILER_REVISION = __dependency3__.COMPILER_REVISION; - var REVISION_CHANGES = __dependency3__.REVISION_CHANGES; - var createFrame = __dependency3__.createFrame; - - function checkRevision(compilerInfo) { - var compilerRevision = compilerInfo && compilerInfo[0] || 1, - currentRevision = COMPILER_REVISION; - - if (compilerRevision !== currentRevision) { - if (compilerRevision < currentRevision) { - var runtimeVersions = REVISION_CHANGES[currentRevision], - compilerVersions = REVISION_CHANGES[compilerRevision]; - throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+ - "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."); - } else { - // Use the embedded version info since the runtime doesn't know about this revision yet - throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+ - "Please update your runtime to a newer version ("+compilerInfo[1]+")."); - } - } - } - - __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial - - function template(templateSpec, env) { - /* istanbul ignore next */ - if (!env) { - throw new Exception("No environment passed to template"); - } - if (!templateSpec || !templateSpec.main) { - throw new Exception('Unknown template object: ' + typeof templateSpec); - } - - // Note: Using env.VM references rather than local var references throughout this section to allow - // for external users to override these as psuedo-supported APIs. - env.VM.checkRevision(templateSpec.compiler); - - var invokePartialWrapper = function(partial, indent, name, context, hash, helpers, partials, data, depths) { - if (hash) { - context = Utils.extend({}, context, hash); - } - - var result = env.VM.invokePartial.call(this, partial, name, context, helpers, partials, data, depths); - - if (result == null && env.compile) { - var options = { helpers: helpers, partials: partials, data: data, depths: depths }; - partials[name] = env.compile(partial, { data: data !== undefined, compat: templateSpec.compat }, env); - result = partials[name](context, options); - } - if (result != null) { - if (indent) { - var lines = result.split('\n'); - for (var i = 0, l = lines.length; i < l; i++) { - if (!lines[i] && i + 1 === l) { - break; - } - - lines[i] = indent + lines[i]; - } - result = lines.join('\n'); - } - return result; - } else { - throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); - } - }; - - // Just add water - var container = { - lookup: function(depths, name) { - var len = depths.length; - for (var i = 0; i < len; i++) { - if (depths[i] && depths[i][name] != null) { - return depths[i][name]; - } - } - }, - lambda: function(current, context) { - return typeof current === 'function' ? current.call(context) : current; - }, - - escapeExpression: Utils.escapeExpression, - invokePartial: invokePartialWrapper, - - fn: function(i) { - return templateSpec[i]; - }, - - programs: [], - program: function(i, data, depths) { - var programWrapper = this.programs[i], - fn = this.fn(i); - if (data || depths) { - programWrapper = program(this, i, fn, data, depths); - } else if (!programWrapper) { - programWrapper = this.programs[i] = program(this, i, fn); - } - return programWrapper; - }, - - data: function(data, depth) { - while (data && depth--) { - data = data._parent; - } - return data; - }, - merge: function(param, common) { - var ret = param || common; - - if (param && common && (param !== common)) { - ret = Utils.extend({}, common, param); - } - - return ret; - }, - - noop: env.VM.noop, - compilerInfo: templateSpec.compiler - }; - - var ret = function(context, options) { - options = options || {}; - var data = options.data; - - ret._setup(options); - if (!options.partial && templateSpec.useData) { - data = initData(context, data); - } - var depths; - if (templateSpec.useDepths) { - depths = options.depths ? [context].concat(options.depths) : [context]; - } - - return templateSpec.main.call(container, context, container.helpers, container.partials, data, depths); - }; - ret.isTop = true; - - ret._setup = function(options) { - if (!options.partial) { - container.helpers = container.merge(options.helpers, env.helpers); - - if (templateSpec.usePartial) { - container.partials = container.merge(options.partials, env.partials); - } - } else { - container.helpers = options.helpers; - container.partials = options.partials; - } - }; - - ret._child = function(i, data, depths) { - if (templateSpec.useDepths && !depths) { - throw new Exception('must pass parent depths'); - } - - return program(container, i, templateSpec[i], data, depths); - }; - return ret; - } - - __exports__.template = template;function program(container, i, fn, data, depths) { - var prog = function(context, options) { - options = options || {}; - - return fn.call(container, context, container.helpers, container.partials, options.data || data, depths && [context].concat(depths)); - }; - prog.program = i; - prog.depth = depths ? depths.length : 0; - return prog; - } - - __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data, depths) { - var options = { partial: true, helpers: helpers, partials: partials, data: data, depths: depths }; - - if(partial === undefined) { - throw new Exception("The partial " + name + " could not be found"); - } else if(partial instanceof Function) { - return partial(context, options); - } - } - - __exports__.invokePartial = invokePartial;function noop() { return ""; } - - __exports__.noop = noop;function initData(context, data) { - if (!data || !('root' in data)) { - data = data ? createFrame(data) : {}; - data.root = context; - } - return data; - } - return __exports__; -})(__module2__, __module4__, __module1__); - -// handlebars.runtime.js -var __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { - "use strict"; - var __exports__; - /*globals Handlebars: true */ - var base = __dependency1__; - - // Each of these augment the Handlebars object. No need to setup here. - // (This is done to easily share code between commonjs and browse envs) - var SafeString = __dependency2__; - var Exception = __dependency3__; - var Utils = __dependency4__; - var runtime = __dependency5__; - - // For compatibility and usage outside of module systems, make the Handlebars object a namespace - var create = function() { - var hb = new base.HandlebarsEnvironment(); - - Utils.extend(hb, base); - hb.SafeString = SafeString; - hb.Exception = Exception; - hb.Utils = Utils; - hb.escapeExpression = Utils.escapeExpression; - - hb.VM = runtime; - hb.template = function(spec) { - return runtime.template(spec, hb); - }; - - return hb; - }; - - var Handlebars = create(); - Handlebars.create = create; - - Handlebars['default'] = Handlebars; - - __exports__ = Handlebars; - return __exports__; -})(__module1__, __module3__, __module4__, __module2__, __module5__); - - return __module0__; -})); diff --git a/browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js b/browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js deleted file mode 100644 index 9ed2acc66..000000000 --- a/browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v2.1.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+Math.random()}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b) -},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:"0",fontWeight:"400"},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?zb.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=yb(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(n.cssHooks[a+b].set=Gb)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}n.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Kb.prototype.init,n.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=n.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||tb(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?tb(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ub(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return n.map(k,Ub,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xb,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xb(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),n.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Lb=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Lb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Mb||(Mb=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Mb),Mb=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Yb,Zb,$b=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b)) -},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec,fc,gc=/#.*$/,hc=/([?&])_=[^&]*/,ic=/^(.*?):[ \t]*([^\r\n]*)$/gm,jc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kc=/^(?:GET|HEAD)$/,lc=/^\/\//,mc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,nc={},oc={},pc="*/".concat("*");try{fc=location.href}catch(qc){fc=l.createElement("a"),fc.href="",fc=fc.href}ec=mc.exec(fc.toLowerCase())||[];function rc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function sc(a,b,c,d){var e={},f=a===oc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function tc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function uc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function vc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:fc,type:"GET",isLocal:jc.test(ec[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":pc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?tc(tc(a,n.ajaxSettings),b):tc(n.ajaxSettings,a)},ajaxPrefilter:rc(nc),ajaxTransport:rc(oc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=ic.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||fc)+"").replace(gc,"").replace(lc,ec[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=mc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===ec[1]&&h[2]===ec[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(ec[3]||("http:"===ec[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),sc(nc,k,b,v),2===t)return v;i=k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!kc.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=hc.test(d)?d.replace(hc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+pc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=sc(oc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=uc(k,v,f)),u=vc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var wc=/%20/g,xc=/\[\]$/,yc=/\r?\n/g,zc=/^(?:submit|button|image|reset|file)$/i,Ac=/^(?:input|select|textarea|keygen)/i;function Bc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||xc.test(a)?d(a,e):Bc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Bc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Bc(c,a[c],b,e);return d.join("&").replace(wc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Ac.test(this.nodeName)&&!zc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(yc,"\r\n")}}):{name:b.name,value:c.replace(yc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Cc=0,Dc={},Ec={0:200,1223:204},Fc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Dc)Dc[a]()}),k.cors=!!Fc&&"withCredentials"in Fc,k.ajax=Fc=!!Fc,n.ajaxTransport(function(a){var b;return k.cors||Fc&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Cc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Dc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Ec[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Dc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Gc=[],Hc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Gc.pop()||n.expando+"_"+cc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Hc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Hc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Hc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Gc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Ic=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Jc=a.document.documentElement;function Kc(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Kc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Jc;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Jc})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Kc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=yb(k.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Lc=a.jQuery,Mc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Mc),b&&a.jQuery===n&&(a.jQuery=Lc),n},typeof b===U&&(a.jQuery=a.$=n),n});
\ No newline at end of file diff --git a/browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js b/browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js deleted file mode 100644 index 40d323df0..000000000 --- a/browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js +++ /dev/null @@ -1,954 +0,0 @@ -/*
- * jQuery Plugin: Tokenizing Autocomplete Text Entry
- * Version 1.6.0
- *
- * Copyright (c) 2009 James Smith (http://loopj.com)
- * Licensed jointly under the GPL and MIT licenses,
- * choose which one suits your project best!
- *
- * Licensed under MIT
- * With modifications
- *
- */
-
-(function ($) {
-// Default settings
-var DEFAULT_SETTINGS = {
- // Search settings
- method: "GET",
- contentType: "json",
- queryParam: "q",
- searchDelay: 300,
- minChars: 1,
- propertyToSearch: "name",
- jsonContainer: null,
- scrollKeyboard: false,
-
- // Display settings
- hintText: null,
- noResultsText: null,
- noResultsHideDropdown: false,
- searchingText: null,
- deleteText: "×",
- animateDropdown: true,
- emptyInputLength: null,
-
- // Tokenization settings
- tokenLimit: null,
- tokenDelimiter: ",",
- preventDuplicates: false,
-
- // Output settings
- tokenValue: "id",
-
- // Prepopulation settings
- prePopulate: null,
- processPrePopulate: false,
-
- // Manipulation settings
- idPrefix: "token-input-",
-
- // Formatters
- resultsFormatter: function(item) {
- let listItem = document.createElement("li");
- listItem.textContent = item[this.propertyToSearch];
- return listItem.outerHTML;
- },
- tokenFormatter: function(item) {
- let listItem = document.createElement("li");
- let p = document.createElement("p");
- p.textContent = item[this.propertyToSearch];
- listItem.appendChild(p);
- return listItem.outerHTML;
- },
-
- // Validations
- validateItem: null,
-
- // Force selections only on mouse click
- noHoverSelect: false,
-
- // Callbacks
- onResult: null,
- onAdd: null,
- onDelete: null,
- onReady: null
-};
-
-// Default classes to use when theming
-var DEFAULT_CLASSES = {
- tokenList: "token-input-list",
- token: "token-input-token",
- tokenDelete: "token-input-delete-token",
- selectedToken: "token-input-selected-token",
- highlightedToken: "token-input-highlighted-token",
- dropdown: "token-input-dropdown",
- dropdownItem: "token-input-dropdown-item",
- dropdownItem2: "token-input-dropdown-item2",
- selectedDropdownItem: "token-input-selected-dropdown-item",
- inputToken: "token-input-input-token"
-};
-
-// Input box position "enum"
-var POSITION = {
- BEFORE: 0,
- AFTER: 1,
- END: 2
-};
-
-// Keys "enum"
-var KEY = {
- BACKSPACE: 8,
- TAB: 9,
- ENTER: 13,
- ESCAPE: 27,
- SPACE: 32,
- PAGE_UP: 33,
- PAGE_DOWN: 34,
- END: 35,
- HOME: 36,
- LEFT: 37,
- UP: 38,
- RIGHT: 39,
- DOWN: 40,
- NUMPAD_ENTER: 108,
- COMMA: 188
-};
-
-// Additional public (exposed) methods
-var methods = {
- init: function(url_or_data_or_function, options) {
- var settings = $.extend({}, DEFAULT_SETTINGS, options || {});
-
- return this.each(function () {
- $(this).data("tokenInputObject", new $.TokenList(this, url_or_data_or_function, settings));
- });
- },
- clear: function() {
- this.data("tokenInputObject").clear();
- return this;
- },
- add: function(item) {
- this.data("tokenInputObject").add(item);
- return this;
- },
- remove: function(item) {
- this.data("tokenInputObject").remove(item);
- return this;
- },
- get: function() {
- return this.data("tokenInputObject").getTokens();
- }
-}
-
-// Expose the .tokenInput function to jQuery as a plugin
-$.fn.tokenInput = function (method) {
- // Method calling and initialization logic
- if(methods[method]) {
- return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
- } else {
- return methods.init.apply(this, arguments);
- }
-};
-
-// TokenList class for each input
-$.TokenList = function (input, url_or_data, settings) {
- //
- // Initialization
- //
-
- // Configure the data source
- if($.type(url_or_data) === "string" || $.type(url_or_data) === "function") {
- // Set the url to query against
- settings.url = url_or_data;
-
- // If the URL is a function, evaluate it here to do our initalization work
- var url = computeURL();
-
- // Make a smart guess about cross-domain if it wasn't explicitly specified
- if(settings.crossDomain === undefined) {
- if(url.indexOf("://") === -1) {
- settings.crossDomain = false;
- } else {
- settings.crossDomain = (location.href.split(/\/+/g)[1] !== url.split(/\/+/g)[1]);
- }
- }
- } else if(typeof(url_or_data) === "object") {
- // Set the local data to search through
- settings.local_data = url_or_data;
- }
-
- // Build class names
- if(settings.classes) {
- // Use custom class names
- settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes);
- } else if(settings.theme) {
- // Use theme-suffixed default class names
- settings.classes = {};
- $.each(DEFAULT_CLASSES, function(key, value) {
- settings.classes[key] = value + "-" + settings.theme;
- });
- } else {
- settings.classes = DEFAULT_CLASSES;
- }
-
-
- // Save the tokens
- var saved_tokens = [];
-
- // Keep track of the number of tokens in the list
- var token_count = 0;
-
- // Basic cache to save on db hits
- var cache = new $.TokenList.Cache();
-
- // Keep track of the timeout, old vals
- var timeout;
- var input_val;
-
- function tokenize(){
- var item = $(selected_dropdown_item).data("tokeninput");
- if(!item && settings.textToData){
- item = settings.textToData(input_box.val());
- }
-
- if(item) {
- add_token(item);
- hidden_input.change();
- return false;
- }
- }
-
- // Create a new text input an attach keyup events
- var input_box = $("<input type=\"text\" autocomplete=\"off\">")
- .css({
- outline: "none"
- })
- .attr("id", settings.idPrefix + input.id)
- .focus(function () {
- if (settings.minChars == 0) {
- setTimeout(function(){do_search();}, 5);
- }
- if (settings.tokenLimit === null || settings.tokenLimit !== token_count) {
- show_dropdown_hint();
- }
- })
- .blur(function () {
- tokenize();
- hide_dropdown();
- $(this).val("");
- })
- .bind("keyup keydown blur update", resize_input)
- .keydown(function (event) {
- var previous_token;
- var next_token;
-
- switch(event.keyCode) {
- case KEY.LEFT:
- case KEY.RIGHT:
- case KEY.UP:
- case KEY.DOWN:
- if(!$(this).val()) {
- previous_token = input_token.prev();
- next_token = input_token.next();
-
- if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
- // Check if there is a previous/next token and it is selected
- if(event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) {
- deselect_token($(selected_token), POSITION.BEFORE);
- } else {
- deselect_token($(selected_token), POSITION.AFTER);
- }
- } else if((event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) && previous_token.length) {
- // We are moving left, select the previous token if it exists
- select_token($(previous_token.get(0)));
- } else if((event.keyCode === KEY.RIGHT || event.keyCode === KEY.DOWN) && next_token.length) {
- // We are moving right, select the next token if it exists
- select_token($(next_token.get(0)));
- }
- } else {
- if (event.keyCode === KEY.UP || event.keyCode === KEY.DOWN) {
- var dropdown_item = null;
- if(!selected_dropdown_item && (event.keyCode === KEY.DOWN)) {
- dropdown_item = $('.token-input-dropdown li').first();
- }
- else if(event.keyCode === KEY.DOWN) {
- dropdown_item = $(selected_dropdown_item).next();
- } else {
- dropdown_item = $(selected_dropdown_item).prev();
- }
-
- if(dropdown_item.length) {
- select_dropdown_item(dropdown_item,true);
- }
- else if (!(event.keyCode === KEY.DOWN) && $(selected_dropdown_item).length) {
- deselect_dropdown_item($(selected_dropdown_item));
- }
- return false;
- }
- }
- break;
-
- case KEY.BACKSPACE:
- previous_token = input_token.prev();
-
- if(!$(this).val().length) {
- if(selected_token) {
- delete_token($(selected_token));
- hidden_input.change();
- } else if(previous_token.length) {
- select_token($(previous_token.get(0)));
- }
-
- return false;
- } else if($(this).val().length === 1) {
- hide_dropdown();
- } else {
- // set a timeout just long enough to let this function finish.
- setTimeout(function(){do_search();}, 5);
- }
- break;
-
- case KEY.TAB:
- case KEY.ENTER:
- case KEY.NUMPAD_ENTER:
- case KEY.COMMA:
- if (event.keyCode != KEY.ENTER && event.keyCode != KEY.NUMPAD_ENTER)
- {
- event.preventDefault();
- }
- tokenize();
- break;
-
- case KEY.ESCAPE:
- hide_dropdown();
- return true;
-
- default:
- if(String.fromCharCode(event.which)) {
- // set a timeout just long enough to let this function finish.
- setTimeout(function(){do_search();}, 5);
- }
- break;
- }
- });
-
- // Keep a reference to the original input box
- var hidden_input = $(input)
- .hide()
- .val("")
- .focus(function () {
- input_box.focus();
- })
- .blur(function () {
- input_box.blur();
- });
-
- // Keep a reference to the selected token and dropdown item
- var selected_token = null;
- var selected_token_index = 0;
- var selected_dropdown_item = null;
-
- // The list to store the token items in
- var token_list = $("<ul />")
- .addClass(settings.classes.tokenList)
- .click(function (event) {
- var li = $(event.target).closest("li");
- if(li && li.get(0) && $.data(li.get(0), "tokeninput")) {
- toggle_select_token(li);
- } else {
- // Deselect selected token
- if(selected_token) {
- deselect_token($(selected_token), POSITION.END);
- }
-
- // Focus input box
- input_box.focus();
- }
- })
- .mouseover(function (event) {
- var li = $(event.target).closest("li");
- if(li && selected_token !== this) {
- li.addClass(settings.classes.highlightedToken);
- }
- })
- .mouseout(function (event) {
- var li = $(event.target).closest("li");
- if(li && selected_token !== this) {
- li.removeClass(settings.classes.highlightedToken);
- }
- })
- .insertBefore(hidden_input);
-
- // The token holding the input box
- var input_token = $("<li />")
- .addClass(settings.classes.inputToken)
- .appendTo(token_list)
- .append(input_box);
-
- // The list to store the dropdown items in
- var dropdown = $("<div>")
- .addClass(settings.classes.dropdown)
- .appendTo("body")
- .hide();
-
- // Magic element to help us resize the text input
- var input_resizer = $("<tester/>")
- .insertAfter(input_box)
- .css({
- position: "absolute",
- top: -9999,
- left: -9999,
- width: "auto",
- fontSize: input_box.css("fontSize"),
- fontFamily: input_box.css("fontFamily"),
- fontWeight: input_box.css("fontWeight"),
- letterSpacing: input_box.css("letterSpacing"),
- whiteSpace: "nowrap"
- });
-
- // Pre-populate list if items exist
- hidden_input.val("");
- var li_data = settings.prePopulate || hidden_input.data("pre");
- if(settings.processPrePopulate && $.isFunction(settings.onResult)) {
- li_data = settings.onResult.call(hidden_input, li_data);
- }
- if(li_data && li_data.length) {
- $.each(li_data, function (index, value) {
- insert_token(value);
- checkTokenLimit();
- });
- }
-
- // Initialization is done
- if($.isFunction(settings.onReady)) {
- settings.onReady.call();
- if (settings.minChars == 0)
- {
- setTimeout(function(){do_search();}, 5);
- }
- }
-
- //
- // Public functions
- //
-
- this.clear = function() {
- token_list.children("li").each(function() {
- if ($(this).children("input").length === 0) {
- delete_token($(this));
- }
- });
- }
-
- this.add = function(item) {
- add_token(item);
- }
-
- this.remove = function(item) {
- token_list.children("li").each(function() {
- if ($(this).children("input").length === 0) {
- var currToken = $(this).data("tokeninput");
- var match = true;
- for (var prop in item) {
- if (item[prop] !== currToken[prop]) {
- match = false;
- break;
- }
- }
- if (match) {
- delete_token($(this));
- }
- }
- });
- }
-
- this.getTokens = function() {
- return saved_tokens;
- }
-
- //
- // Private functions
- //
-
- function checkTokenLimit() {
- if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
- input_box.hide();
- hide_dropdown();
- return;
- }
- }
-
- function resize_input() {
- if(input_val === (input_val = input_box.val())) {return;}
-
- // Enter new content into resizer and resize input accordingly
- var escaped = input_val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>');
- input_resizer.html(escaped);
- var minwidth = 30;
- if (settings.emptyInputLength && token_list.children().length < 2) {
- minwidth = settings.emptyInputLength;
- }
- input_box.width(input_resizer.width() + minwidth);
- }
-
- function is_printable_character(keycode) {
- return ((keycode >= 48 && keycode <= 90) || // 0-1a-z
- (keycode >= 96 && keycode <= 111) || // numpad 0-9 + - / * .
- (keycode >= 186 && keycode <= 192) || // ; = , - . / ^
- (keycode >= 219 && keycode <= 222)); // ( \ ) '
- }
-
- // Inner function to a token to the list
- function insert_token(item) {
- var this_token = settings.tokenFormatter(item);
- this_token = $(this_token)
- .addClass(settings.classes.token)
- .insertBefore(input_token);
-
- // The 'delete token' button
- $("<span>" + settings.deleteText + "</span>")
- .addClass(settings.classes.tokenDelete)
- .appendTo(this_token)
- .click(function () {
- delete_token($(this).parent());
- hidden_input.change();
- return false;
- });
-
- // Store data on the token
- var token_data = {"id": item.id};
- token_data[settings.propertyToSearch] = item[settings.propertyToSearch];
- token_data.item = item;
- $.data(this_token.get(0), "tokeninput", item);
-
- // Save this token for duplicate checking
- saved_tokens = saved_tokens.slice(0,selected_token_index).concat([token_data]).concat(saved_tokens.slice(selected_token_index));
- selected_token_index++;
-
- // Update the hidden input
- update_hidden_input(saved_tokens, hidden_input);
-
- token_count += 1;
-
- // Check the token limit
- if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
- input_box.hide();
- hide_dropdown();
- }
-
- return this_token;
- }
-
- // Add a token to the token list based on user input
- function add_token (item) {
- if(!item) return;
-
- // Check for item validation
- if ($.isFunction(settings.validateItem) && !settings.validateItem(item)) {
- return false;
- }
-
- var callback = settings.onAdd;
-
- // See if the token already exists and select it if we don't want duplicates
- if(token_count > 0 && settings.preventDuplicates) {
- var found_existing_token = null;
- token_list.children().each(function () {
- var existing_token = $(this);
- var existing_data = $.data(existing_token.get(0), "tokeninput");
- if(existing_data && existing_data.id === item.id) {
- found_existing_token = existing_token;
- return false;
- }
- });
-
- if(found_existing_token) {
- select_token(found_existing_token);
- input_token.insertAfter(found_existing_token);
- input_box.focus();
- return;
- }
- }
-
- // Insert the new tokens
- if(settings.tokenLimit == null || token_count < settings.tokenLimit) {
- insert_token(item);
- checkTokenLimit();
- }
-
- // Clear input box
- input_box.val("");
-
- // Don't show the help dropdown, they've got the idea
- hide_dropdown();
-
- // Execute the onAdd callback if defined
- if($.isFunction(callback)) {
- callback.call(hidden_input,item);
- }
- }
-
- // Select a token in the token list
- function select_token (token) {
- token.addClass(settings.classes.selectedToken);
- selected_token = token.get(0);
-
- // Hide input box
- input_box.val("");
-
- // Hide dropdown if it is visible (eg if we clicked to select token)
- hide_dropdown();
- }
-
- // Deselect a token in the token list
- function deselect_token (token, position) {
- token.removeClass(settings.classes.selectedToken);
- selected_token = null;
-
- if(position === POSITION.BEFORE) {
- input_token.insertBefore(token);
- selected_token_index--;
- } else if(position === POSITION.AFTER) {
- input_token.insertAfter(token);
- selected_token_index++;
- } else {
- input_token.appendTo(token_list);
- selected_token_index = token_count;
- }
-
- // Show the input box and give it focus again
- input_box.focus();
- }
-
- // Toggle selection of a token in the token list
- function toggle_select_token(token) {
- var previous_selected_token = selected_token;
-
- if(selected_token) {
- deselect_token($(selected_token), POSITION.END);
- }
-
- if(previous_selected_token === token.get(0)) {
- deselect_token(token, POSITION.END);
- } else {
- select_token(token);
- }
- }
-
- // Delete a token from the token list
- function delete_token (token) {
- // Remove the id from the saved list
- var token_data = $.data(token.get(0), "tokeninput");
- var callback = settings.onDelete;
-
- var index = token.prevAll().length;
- if(index > selected_token_index) index--;
-
- // Delete the token
- token.remove();
- selected_token = null;
-
- // Show the input box and give it focus again
- input_box.focus();
-
- // Remove this token from the saved list
- saved_tokens = saved_tokens.slice(0,index).concat(saved_tokens.slice(index+1));
- if(index < selected_token_index) selected_token_index--;
-
- // Update the hidden input
- update_hidden_input(saved_tokens, hidden_input);
-
- token_count -= 1;
-
- if(settings.tokenLimit !== null) {
- input_box
- .show()
- .val("")
- .focus();
- }
-
- // Execute the onDelete callback if defined
- if($.isFunction(callback)) {
- callback.call(hidden_input,token_data);
- }
- }
-
- // Update the hidden input box value
- function update_hidden_input(saved_tokens, hidden_input) {
- var token_values = $.map(saved_tokens, function (el) {
- return el[settings.tokenValue];
- });
- hidden_input.val(token_values.join(settings.tokenDelimiter));
-
- }
-
- // Hide and clear the results dropdown
- function hide_dropdown () {
- dropdown.hide().empty();
- selected_dropdown_item = null;
- if (settings.onHideDropdown)
- settings.onHideDropdown();
- }
-
- function show_dropdown() {
- dropdown
- .css({
- position: "absolute",
- top: $(token_list).offset().top + $(token_list).outerHeight(),
- left: $(token_list).offset().left,
- zindex: 999
- })
- .show();
- if (settings.onShowDropdown)
- settings.onShowDropdown();
- }
-
- function show_dropdown_searching () {
- if(settings.searchingText) {
- dropdown.html("<p>"+settings.searchingText+"</p>");
- show_dropdown();
- }
- }
-
- function show_dropdown_hint () {
- if(settings.hintText) {
- dropdown.html("<p>"+settings.hintText+"</p>");
- show_dropdown();
- }
- }
-
- // Highlight the query part of the search term
- function highlight_term(value, term) {
- return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>");
- }
-
- function find_value_and_highlight_term(template, value, term) {
- return template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + value + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term));
- }
-
- // Populate the results dropdown with some results
- function populate_dropdown (query, results) {
- if(results && results.length) {
- dropdown.empty();
- var dropdown_ul = $("<ul>")
- .appendTo(dropdown)
- .mouseover(function (event) {
- select_dropdown_item($(event.target).closest("li"));
- })
- .mousedown(function (event) {
- add_token($(event.target).closest("li").data("tokeninput"));
- hidden_input.change();
- return false;
- })
- .hide();
- if (settings.noHoverSelect) {
- dropdown_ul.off('mouseover');
- dropdown_ul.on('mouseover',function (event) {
- $(this).find("li").removeClass(settings.classes.selectedDropdownItem);
- $(event.target).closest("li").addClass(settings.classes.selectedDropdownItem);
- });
- }
-
- $.each(results, function(index, value) {
- var this_li = settings.resultsFormatter(value);
-
- // this_li = find_value_and_highlight_term(this_li ,value[settings.propertyToSearch], query);
-
- this_li = $(this_li).appendTo(dropdown_ul);
-
- if(index % 2) {
- this_li.addClass(settings.classes.dropdownItem);
- } else {
- this_li.addClass(settings.classes.dropdownItem2);
- }
-
- // if(index === 0) {
- // select_dropdown_item(this_li);
- // }
-
- $.data(this_li.get(0), "tokeninput", value);
- });
-
- show_dropdown();
-
- if(settings.animateDropdown) {
- dropdown_ul.slideDown("fast");
- } else {
- dropdown_ul.show();
- }
- } else {
- if(settings.noResultsText) {
- dropdown.html("<p>"+settings.noResultsText+"</p>");
- show_dropdown();
- }
- if (settings.noResultsHideDropdown) {
- hide_dropdown();
- }
- }
- }
-
- // Highlight an item in the results dropdown
- function select_dropdown_item (item,withkeyboard) {
- if(item) {
- if(selected_dropdown_item) {
- deselect_dropdown_item($(selected_dropdown_item));
- }
- if (settings.scrollKeyboard && withkeyboard) {
- var list = $('.token-input-dropdown-tag ul');
- var listheight = list.height();
- var itemheight = item.outerHeight();
- var itemtop = item.position().top;
- if (itemtop > listheight) {
- var listscroll = list.scrollTop();
- list.scrollTop(listscroll + itemheight);
- }
- else if (itemtop < 0) {
- var listscroll = list.scrollTop();
- list.scrollTop(listscroll - itemheight);
- }
-
- }
- item.addClass(settings.classes.selectedDropdownItem);
- selected_dropdown_item = item.get(0);
- }
- }
-
- // Remove highlighting from an item in the results dropdown
- function deselect_dropdown_item (item) {
- item.removeClass(settings.classes.selectedDropdownItem);
- selected_dropdown_item = null;
- }
-
- // Do a search and show the "searching" dropdown if the input is longer
- // than settings.minChars
- function do_search() {
- var query = input_box.val().toLowerCase();
- if(query && query.length || settings.minChars == 0) {
- if(selected_token) {
- deselect_token($(selected_token), POSITION.AFTER);
- }
-
- if(query.length >= settings.minChars) {
- show_dropdown_searching();
- clearTimeout(timeout);
-
- timeout = setTimeout(function(){
- run_search(query);
- }, settings.searchDelay);
- } else {
- hide_dropdown();
- }
- }
- }
-
- // Do the actual search
- function run_search(query) {
- var cache_key = query + computeURL();
- var cached_results = cache.get(cache_key);
- if(cached_results) {
- populate_dropdown(query, cached_results);
- } else {
- // Are we doing an ajax search or local data search?
- if(settings.url) {
- var url = computeURL();
- // Extract exisiting get params
- var ajax_params = {};
- ajax_params.data = {};
- if(url.indexOf("?") > -1) {
- var parts = url.split("?");
- ajax_params.url = parts[0];
-
- var param_array = parts[1].split("&");
- $.each(param_array, function (index, value) {
- var kv = value.split("=");
- ajax_params.data[kv[0]] = kv[1];
- });
- } else {
- ajax_params.url = url;
- }
-
- // Prepare the request
- ajax_params.data[settings.queryParam] = query;
- ajax_params.type = settings.method;
- ajax_params.dataType = settings.contentType;
- if(settings.crossDomain) {
- ajax_params.dataType = "jsonp";
- }
-
- // Attach the success callback
- ajax_params.success = function(results) {
- if($.isFunction(settings.onResult)) {
- results = settings.onResult.call(hidden_input, results);
- }
- cache.add(cache_key, settings.jsonContainer ? results[settings.jsonContainer] : results);
-
- // only populate the dropdown if the results are associated with the active search query
- if(input_box.val().toLowerCase() === query) {
- populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
- }
- };
-
- // Make the request
- $.ajax(ajax_params);
- } else if(settings.search_function){
- settings.search_function(query, function(results){
- cache.add(cache_key, results);
- populate_dropdown(query, results);
- });
- } else if(settings.local_data) {
- // Do the search through local data
- var results = $.grep(settings.local_data, function (row) {
- return row[settings.propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1;
- });
-
- if($.isFunction(settings.onResult)) {
- results = settings.onResult.call(hidden_input, results);
- }
- cache.add(cache_key, results);
- populate_dropdown(query, results);
- }
- }
- }
-
- // compute the dynamic URL
- function computeURL() {
- var url = settings.url;
- if(typeof settings.url == 'function') {
- url = settings.url.call();
- }
- return url;
- }
-};
-
-// Really basic cache for the results
-$.TokenList.Cache = function (options) {
- var settings = $.extend({
- max_size: 500
- }, options);
-
- var data = {};
- var size = 0;
-
- var flush = function () {
- data = {};
- size = 0;
- };
-
- this.add = function (query, results) {
- if(size > settings.max_size) {
- flush();
- }
-
- if(!data[query]) {
- size += 1;
- }
-
- data[query] = results;
- };
-
- this.get = function (query) {
- return data[query];
- };
-};
-}(jQuery));
diff --git a/browser/extensions/pocket/content/panels/license.txt b/browser/extensions/pocket/content/panels/license.txt deleted file mode 100644 index 7f3f806ba..000000000 --- a/browser/extensions/pocket/content/panels/license.txt +++ /dev/null @@ -1,35 +0,0 @@ -
-Unless where otherwise noted, the following license applies to the files
-within this directory and descendents of this directory.
-
-POCKET MARKS
-
-Notwithstanding the permitted uses of the Software (as defined below) pursuant
-to the license set forth below, "Pocket," "Read It Later" and the Pocket icon
-and logos (collectively, the “Pocket Marks”) are registered and common law
-trademarks of Read It Later, Inc. This means that, while you have considerable
-freedom to redistribute and modify the Software, there are tight restrictions
-on your ability to use the Pocket Marks. This license does not grant you any
-rights to use the Pocket Marks except as they are embodied in the Software.
-
----
-
-SOFTWARE
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/browser/extensions/pocket/content/panels/saved.html b/browser/extensions/pocket/content/panels/saved.html deleted file mode 100644 index 93477d8ee..000000000 --- a/browser/extensions/pocket/content/panels/saved.html +++ /dev/null @@ -1,19 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="utf-8"> - <base href="chrome://pocket/content/panels/"> - <title>Pocket: Page Saved</title> - <link rel="stylesheet" href="css/normalize.css"> - <link rel="stylesheet" href="css/firasans.css"> - <link rel="stylesheet" href="css/saved.css"> - </head> - <body class="pkt_ext_containersaved" aria-live="polite"> - <script type="text/javascript" src="js/vendor/jquery-2.1.1.min.js"></script> - <script type="text/javascript" src="js/vendor/handlebars.runtime.js"></script> - <script type="text/javascript" src="js/vendor/jquery.tokeninput.min.js"></script> - <script type="text/javascript" src="js/tmpl.js"></script> - <script type="text/javascript" src="js/messages.js"></script> - <script type="text/javascript" src="js/saved.js"></script> - </body> -</html> diff --git a/browser/extensions/pocket/content/panels/signup.html b/browser/extensions/pocket/content/panels/signup.html deleted file mode 100644 index bcdf66ed4..000000000 --- a/browser/extensions/pocket/content/panels/signup.html +++ /dev/null @@ -1,18 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="utf-8"> - <base href="chrome://pocket/content/panels/"> - <title>Pocket: Sign Up</title> - <link rel="stylesheet" href="css/normalize.css"> - <link rel="stylesheet" href="css/firasans.css"> - <link rel="stylesheet" href="css/signup.css"> - </head> - <body class="pkt_ext_containersignup" aria-live="polite"> - <script type="text/javascript" src="js/vendor/jquery-2.1.1.min.js"></script> - <script type="text/javascript" src="js/vendor/handlebars.runtime.js"></script> - <script type="text/javascript" src="js/tmpl.js"></script> - <script type="text/javascript" src="js/messages.js"></script> - <script type="text/javascript" src="js/signup.js"></script> - </body> -</html> diff --git a/browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars b/browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars deleted file mode 100644 index b224450ec..000000000 --- a/browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars +++ /dev/null @@ -1,2 +0,0 @@ -<div class="pkt_ext_suggestedtag_detailshown">
-</div>
\ No newline at end of file diff --git a/browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars b/browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars deleted file mode 100644 index 5ef042636..000000000 --- a/browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars +++ /dev/null @@ -1,6 +0,0 @@ -<div class="pkt_ext_suggestedtag_detail pkt_ext_suggestedtag_detail_loading"> - <h4>{{suggestedtags}}</h4> - <div class="pkt_ext_loadingspinner"><div></div></div> - <ul class="pkt_ext_cf"> - </ul> -</div>
\ No newline at end of file diff --git a/browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars b/browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars deleted file mode 100644 index 89b7500cd..000000000 --- a/browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars +++ /dev/null @@ -1,29 +0,0 @@ -<div class="pkt_ext_initload"> - <div class="pkt_ext_logo"></div> - <div class="pkt_ext_topdetail"> - <h2>{{saving}}</h2> - </div> - <div class="pkt_ext_loadingspinner"><div></div></div> -</div> -<div class="pkt_ext_detail"> - <div class="pkt_ext_logo"></div> - <div class="pkt_ext_topdetail"> - <h2>{{pagesaved}}</h2> - <h3 class="pkt_ext_errordetail"></h3> - <nav class="pkt_ext_item_actions pkt_ext_cf"> - <ul> - <li><a class="pkt_ext_removeitem" href="#">{{removepage}}</a></li> - <li class="pkt_ext_actions_separator"></li> - <li><a class="pkt_ext_openpocket" href="https://{{pockethost}}/a?src=ff_ext_saved" target="_blank">{{viewlist}}</a></li> - </ul> - </nav> - </div> - <div class="pkt_ext_tag_detail pkt_ext_cf"> - <div class="pkt_ext_tag_input_wrapper"> - <div class="pkt_ext_tag_input_blocker"></div> - <input class="pkt_ext_tag_input" type="text" placeholder="{{addtags}}"> - </div> - <a href="#" class="pkt_ext_btn pkt_ext_btn_disabled">{{save}}</a> - </div> - <p class="pkt_ext_edit_msg"></p> -</div>
\ No newline at end of file diff --git a/browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars b/browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars deleted file mode 100644 index 8dddaef60..000000000 --- a/browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars +++ /dev/null @@ -1,32 +0,0 @@ -<div class="pkt_ext_introdetail pkt_ext_introdetailhero"> - <h2 class="pkt_ext_logo">Pocket</h2> - <p class="pkt_ext_tagline">{{tagline}}</p> - {{#if showlearnmore}} - {{#if controlvariant}} - <p class="pkt_ext_learnmorecontainer"><a class="pkt_ext_learnmore" href="https://{{pockethost}}/firefox_learnmore?s=ffi&t=learnmore&tv=panel_control&v={{variant}}" target="_blank">{{learnmore}}</a></p> - {{else}} - <p class="pkt_ext_learnmorecontainer"><a class="pkt_ext_learnmore" href="https://{{pockethost}}/firefox_learnmore?s=ffi&t=learnmore&tv=panel_tryit&v={{variant}}" target="_blank">{{learnmore}}</a></p> - {{/if}} - {{else}} - <p class="pkt_ext_learnmorecontainer"><a class="pkt_ext_learnmore pkt_ext_learnmoreinactive" href="#">{{learnmore}}</a></p> - {{/if}} - <div class="pkt_ext_introimg"></div> -</div> -<div class="pkt_ext_signupdetail pkt_ext_signupdetail_hero"> - {{#if fxasignedin}} - <h4>{{signuptosave}}</h4> - <p class="btn-container"><a href="https://{{pockethost}}/ff_signup?s=ffi&t=signupff&v={{variant}}" target="_blank" class="btn signup-btn-firefox"><span class="logo"></span><span class="text">{{signinfirefox}}</span></a></p> - <p class="alreadyhave">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&src=extension&s=ffi&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p> - {{else}} - {{#if controlvariant}} - <h4>{{signuptosave}}</h4> - <p class="btn-container"><a href="https://{{pockethost}}/ff_signup?s=ffi&tv=panel_control&t=signupff&v={{variant}}" target="_blank" class="btn signup-btn-firefox"><span class="logo"></span><span class="text">{{signupfirefox}}</span></a></p> - <p class="btn-container"><a href="https://{{pockethost}}/signup?force=email&tv=panel_control&src=extension&s=ffi&t=signupemail&v={{variant}}" target="_blank" class="btn btn-secondary signup-btn-email signup-btn-initstate">{{signupemail}}</a></p> - <p class="alreadyhave">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&tv=panel_control&src=extension&s=ffi&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p> - {{else}} - <p class="btn-container"><a href="https://{{pockethost}}/firefox_tryitnow?s=ffi&tv=panel_tryit&t=tryitnow" target="_blank" class="btn signup-btn-tryitnow"><span class="text">{{tryitnow}}</span></a></p> - <p class="alreadyhave tryitnowspace">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&s=ffi&tv=panel_tryit&src=extension&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p> - <p class="pkt_ext_tos">{{{tos}}}</p> - {{/if}} - {{/if}} -</div> diff --git a/browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars b/browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars deleted file mode 100644 index 8a181e23d..000000000 --- a/browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars +++ /dev/null @@ -1,43 +0,0 @@ -<div class="pkt_ext_introdetail pkt_ext_introdetailstoryboard"> - <div class="pkt_ext_introstory pkt_ext_introstoryone"> - <div class="pkt_ext_introstory_text"> - <p class="pkt_ext_tagline">{{taglinestory_one}}</p> - </div> - <div class="pkt_ext_introstoryone_img"></div> - </div> - <div class="pkt_ext_introstorydivider"></div> - <div class="pkt_ext_introstory pkt_ext_introstorytwo"> - <div class="pkt_ext_introstory_text"> - <p class="pkt_ext_tagline">{{taglinestory_two}}</p> - {{#if showlearnmore}} - {{#if controlvariant}} - <p><a class="pkt_ext_learnmore" href="https://{{pockethost}}/firefox_learnmore?s=ffi&t=learnmore&tv=panel_control&v={{variant}}" target="_blank">{{learnmore}}</a></p> - {{else}} - <p><a class="pkt_ext_learnmore" href="https://{{pockethost}}/firefox_learnmore?s=ffi&t=learnmore&tv=panel_tryit&v={{variant}}" target="_blank">{{learnmore}}</a></p> - {{/if}} - {{else}} - <p><a class="pkt_ext_learnmore pkt_ext_learnmoreinactive" href="#">{{learnmore}}</a></p> - {{/if}} - </div> - <div class="pkt_ext_introstorytwo_img"></div> - </div> -</div> -<div class="pkt_ext_signupdetail"> - {{#if fxasignedin}} - <h4>{{signuptosave}}</h4> - <p class="btn-container"><a href="https://{{pockethost}}/ff_signup?s=ffi&t=signupff&v={{variant}}" target="_blank" class="btn signup-btn-firefox"><span class="logo"></span><span class="text">{{signinfirefox}}</span></a></p> - <p class="alreadyhave">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&src=extension&s=ffi&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p> - {{else}} - {{#if controlvariant}} - <h4>{{signuptosave}}</h4> - <p class="btn-container"><a href="https://{{pockethost}}/ff_signup?s=ffi&tv=panel_control&t=signupff&v={{variant}}" target="_blank" class="btn signup-btn-firefox"><span class="logo"></span><span class="text">{{signupfirefox}}</span></a></p> - <p class="btn-container"><a href="https://{{pockethost}}/signup?force=email&tv=panel_control&src=extension&s=ffi&t=signupemail&v={{variant}}" target="_blank" class="btn btn-secondary signup-btn-email signup-btn-initstate">{{signupemail}}</a></p> - <p class="alreadyhave">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&tv=panel_control&src=extension&s=ffi&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p> - {{else}} - <p class="btn-container"><a href="https://{{pockethost}}/firefox_tryitnow?s=ffi&tv=panel_tryit&t=tryitnow" target="_blank" class="btn signup-btn-tryitnow"><span class="text">{{tryitnow}}</span></a></p> - <p class="alreadyhave tryitnowspace">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&s=ffi&tv=panel_tryit&src=extension&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p> - <p class="pkt_ext_tos">{{{tos}}}</p> - {{/if}} - {{/if}} - -</div> diff --git a/browser/extensions/pocket/content/pktApi.jsm b/browser/extensions/pocket/content/pktApi.jsm deleted file mode 100644 index 63b6d415c..000000000 --- a/browser/extensions/pocket/content/pktApi.jsm +++ /dev/null @@ -1,657 +0,0 @@ -/* - * LICENSE - * - * POCKET MARKS - * - * Notwithstanding the permitted uses of the Software (as defined below) pursuant to the license set forth below, "Pocket," "Read It Later" and the Pocket icon and logos (collectively, the “Pocket Marks”) are registered and common law trademarks of Read It Later, Inc. This means that, while you have considerable freedom to redistribute and modify the Software, there are tight restrictions on your ability to use the Pocket Marks. This license does not grant you any rights to use the Pocket Marks except as they are embodied in the Software. - * - * --- - * - * SOFTWARE - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* - * Pocket API module - * - * Public API Documentation: http://getpocket.com/developer/ - * - * - * Definition of keys stored in preferences to preserve user state: - * premium_status: Current premium status for logged in user if available - * Can be 0 for no premium and 1 for premium - * latestSince: Last timestamp a save happened - * tags: All tags for logged in user - * usedTags: All used tags from within the extension sorted by recency - */ - -const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components; -this.EXPORTED_SYMBOLS = ["pktApi"]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - - -var pktApi = (function() { - - /** - * Configuration - */ - - // Base url for all api calls - var pocketAPIhost = Services.prefs.getCharPref("extensions.pocket.api"); // api.getpocket.com - var pocketSiteHost = Services.prefs.getCharPref("extensions.pocket.site"); // getpocket.com - var baseAPIUrl = "https://" + pocketAPIhost + "/v3"; - - - /** - * Auth keys for the API requests - */ - var oAuthConsumerKey = Services.prefs.getCharPref("extensions.pocket.oAuthConsumerKey"); - - /** - * - */ - var prefBranch = Services.prefs.getBranch("extensions.pocket.settings."); - - /** - * Helper - */ - - var extend = function(out) { - out = out || {}; - - for (var i = 1; i < arguments.length; i++) { - if (!arguments[i]) - continue; - - for (var key in arguments[i]) { - if (arguments[i].hasOwnProperty(key)) - out[key] = arguments[i][key]; - } - } - return out; - } - - var parseJSON = function(jsonString) { - try { - var o = JSON.parse(jsonString); - - // Handle non-exception-throwing cases: - // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking, - // but... JSON.parse(null) returns 'null', and typeof null === "object", - // so we must check for that, too. - if (o && typeof o === "object" && o !== null) { - return o; - } - } - catch (e) { } - - return undefined; - }; - - /** - * Settings - */ - - /** - * Wrapper for different plattforms to get settings for a given key - * @param {string} key A string containing the name of the key you want to - * retrieve the value of - * @return {string} String containing the value of the key. If the key - * does not exist, null is returned - */ - function getSetting(key) { - // TODO : Move this to sqlite or a local file so it's not editable (and is safer) - // https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Local_Storage - - if (!prefBranch.prefHasUserValue(key)) - return undefined; - - return prefBranch.getComplexValue(key, Components.interfaces.nsISupportsString).data; - } - - /** - * Wrapper for different plattforms to set a value for a given key in settings - * @param {string} key A string containing the name of the key you want - * to create/update. - * @param {string} value String containing the value you want to give - * the key you are creating/updating. - */ - function setSetting(key, value) { - // TODO : Move this to sqlite or a local file so it's not editable (and is safer) - // https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Local_Storage - - if (!value) - prefBranch.clearUserPref(key); - else - { - // We use complexValue as tags can have utf-8 characters in them - var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString); - str.data = value; - prefBranch.setComplexValue(key, Components.interfaces.nsISupportsString, str); - } - } - - /** - * Auth - */ - - /* - * All cookies from the Pocket domain - * The return format: { cookieName:cookieValue, cookieName:cookieValue, ... } - */ - function getCookiesFromPocket() { - - var cookieManager = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); - var pocketCookies = cookieManager.getCookiesFromHost(pocketSiteHost, {}); - var cookies = {}; - while (pocketCookies.hasMoreElements()) { - var cookie = pocketCookies.getNext().QueryInterface(Ci.nsICookie2); - cookies[cookie.name] = cookie.value; - } - return cookies; - } - - /** - * Returns access token or undefined if no logged in user was found - * @return {string | undefined} Access token for logged in user user - */ - function getAccessToken() { - var pocketCookies = getCookiesFromPocket(); - - // If no cookie was found just return undefined - if (typeof pocketCookies['ftv1'] === "undefined") { - return undefined; - } - - // Check if a new user logged in in the meantime and clearUserData if so - var sessionId = pocketCookies['fsv1']; - var lastSessionId = getSetting('fsv1'); - if (sessionId !== lastSessionId) { - clearUserData(); - setSetting("fsv1", sessionId); - } - - // Return access token - return pocketCookies['ftv1']; - } - - /** - * Get the current premium status of the user - * @return {number | undefined} Premium status of user - */ - function getPremiumStatus() { - var premiumStatus = getSetting("premium_status"); - if (typeof premiumStatus === "undefined") { - // Premium status is not in settings try get it from cookie - var pocketCookies = getCookiesFromPocket(); - premiumStatus = pocketCookies['ps']; - } - return premiumStatus; - } - - /** - * Helper method to check if a user is premium or not - * @return {Boolean} Boolean if user is premium or not - */ - function isPremiumUser() { - return getPremiumStatus() == 1; - } - - - /** - * Returns users logged in status - * @return {Boolean} Users logged in status - */ - function isUserLoggedIn() { - return (typeof getAccessToken() !== "undefined"); - } - - /** - * API - */ - - /** - * Helper function for executing api requests. It mainly configures the - * ajax call with default values like type, headers or dataType for an api call. - * This function is for internal usage only. - * @param {Object} options - * Possible keys: - * - {string} path: This should be the Pocket API - * endpoint to call. For example providing the path - * "/get" would result in a call to getpocket.com/v3/get - * - {Object|undefined} data: Gets passed on to the jQuery ajax - * call as data parameter - * - {function(Object data, XMLHttpRequest xhr) | undefined} success: - * A function to be called if the request succeeds. - * - {function(Error errorThrown, XMLHttpRequest xhr) | undefined} error: - * A function to be called if the request fails. - * @return {Boolean} Returns Boolean whether the api call started sucessfully - * - */ - function apiRequest(options) { - if ((typeof options === "undefined") || (typeof options.path === "undefined")) { - return false; - } - - var url = baseAPIUrl + options.path; - var data = options.data || {}; - data.locale_lang = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIXULChromeRegistry). - getSelectedLocale("browser"); - data.consumer_key = oAuthConsumerKey; - - var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest); - request.open("POST", url, true); - request.onreadystatechange = function(e) { - if (request.readyState == 4) { - if (request.status === 200) { - // There could still be an error if the response is no valid json - // or does not have status = 1 - var response = parseJSON(request.response); - if (options.success && response && response.status == 1) { - options.success(response, request); - return; - } - } - - // Handle error case - if (options.error) { - // In case the user did revoke the access token or it's not - // valid anymore clear the user data - if (request.status === 401) { - clearUserData(); - } - - // Handle error message - var errorMessage; - if (request.status !== 200) { - errorMessage = request.getResponseHeader("X-Error") || request.statusText; - errorMessage = JSON.parse('"' + errorMessage + '"'); - } - var error = {message: errorMessage}; - options.error(error, request); - } - } - }; - - // Set headers - request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); - request.setRequestHeader('X-Accept', ' application/json'); - - // Serialize and Fire off the request - var str = []; - for (var p in data) { - if (data.hasOwnProperty(p)) { - str.push(encodeURIComponent(p) + "=" + encodeURIComponent(data[p])); - } - } - - request.send(str.join("&")); - - return true; - } - - /** - * Cleans all settings for the previously logged in user - */ - function clearUserData() { - // Clear stored information - setSetting("premium_status", undefined); - setSetting("latestSince", undefined); - setSetting("tags", undefined); - setSetting("usedTags", undefined); - - setSetting("fsv1", undefined); - } - - /** - * Add a new link to Pocket - * @param {string} url URL of the link - * @param {Object | undefined} options Can provide a string-based title, a - * `success` callback and an `error` callback. - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function addLink(url, options) { - - var since = getSetting('latestSince'); - var accessToken = getAccessToken(); - - var sendData = { - access_token: accessToken, - url: url, - since: since ? since : 0 - }; - - if (options.title) { - sendData.title = options.title; - } - - return apiRequest({ - path: "/firefox/save", - data: sendData, - success: function(data) { - - // Update premium status, tags and since - var tags = data.tags; - if ((typeof tags !== "undefined") && Array.isArray(tags)) { - // If a tagslist is in the response replace the tags - setSetting('tags', JSON.stringify(data.tags)); - } - - // Update premium status - var premiumStatus = data.premium_status; - if (typeof premiumStatus !== "undefined") { - // If a premium_status is in the response replace the premium_status - setSetting("premium_status", premiumStatus); - } - - // Save since value for further requests - setSetting('latestSince', data.since); - - if (options.success) { - options.success.apply(options, Array.apply(null, arguments)); - } - }, - error: options.error - }); - } - - /** - * Delete an item identified by item id from the users list - * @param {string} itemId The id from the item we want to remove - * @param {Object | undefined} options Can provide an actionInfo object with - * further data to send to the API. Can - * have success and error callbacks - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function deleteItem(itemId, options) { - var action = { - action: "delete", - item_id: itemId - }; - return sendAction(action, options); - } - - /** - * General function to send all kinds of actions like adding of links or - * removing of items via the API - * @param {Object} action Action object - * @param {Object | undefined} options Can provide an actionInfo object - * with further data to send to the - * API. Can have success and error - * callbacks - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function sendAction(action, options) { - // Options can have an 'actionInfo' object. This actionInfo object gets - // passed through to the action object that will be send to the API endpoint - if (typeof options.actionInfo !== 'undefined') { - action = extend(action, options.actionInfo); - } - return sendActions([action], options); - } - - /** - * General function to send all kinds of actions like adding of links or - * removing of items via the API - * @param {Array} actions Array of action objects - * @param {Object | undefined} options Can have success and error callbacks - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function sendActions(actions, options) { - return apiRequest({ - path: "/send", - data: { - access_token: getAccessToken(), - actions: JSON.stringify(actions) - }, - success: options.success, - error: options.error - }); - } - - /** - * Handling Tags - */ - - /** - * Add tags to the item identified by the url. Also updates the used tags - * list - * @param {string} itemId The item identifier by item id - * @param {Array} tags Tags adding to the item - * @param {Object | undefined} options Can provide an actionInfo object with - * further data to send to the API. Can - * have success and error callbacks - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function addTagsToItem(itemId, tags, options) { - return addTags({item_id: itemId}, tags, options); - } - - /** - * Add tags to the item identified by the url. Also updates the used tags - * list - * @param {string} url The item identifier by url - * @param {Array} tags Tags adding to the item - * @param {Object} options Can provide an actionInfo object with further - * data to send to the API. Can have success and error - * callbacks - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function addTagsToURL(url, tags, options) { - return addTags({url: url}, tags, options); - } - - /** - * Helper function to execute the add tags api call. Will be used from addTagsToURL - * and addTagsToItem but not exposed outside - * @param {string} actionPart Specific action part to add to action - * @param {Array} tags Tags adding to the item - * @param {Object | undefined} options Can provide an actionInfo object with - * further data to send to the API. Can - * have success and error callbacks - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function addTags(actionPart, tags, options) { - // Tags add action - var action = { - action: "tags_add", - tags: tags - }; - action = extend(action, actionPart); - - // Backup the success callback as we need it later - var finalSuccessCallback = options.success; - - // Switch the success callback - options.success = function(data) { - - // Update used tags - var usedTagsJSON = getSetting("usedTags"); - var usedTags = usedTagsJSON ? JSON.parse(usedTagsJSON) : {}; - - // Check for each tag if it's already in the used tags - for (var i = 0; i < tags.length; i++) { - var tagToSave = tags[i].trim(); - var newUsedTagObject = { - "tag": tagToSave, - "timestamp": new Date().getTime() - }; - usedTags[tagToSave] = newUsedTagObject; - } - setSetting("usedTags", JSON.stringify(usedTags)); - - // Let the callback know that we are finished - if (finalSuccessCallback) { - finalSuccessCallback(data); - } - }; - - // Execute the action - return sendAction(action, options); - } - - /** - * Get all cached tags and used tags within the callback - * @param {function(Array, Array, Boolean)} callback - * Function with tags and used tags as parameter. - */ - function getTags(callback) { - - var tagsFromSettings = function() { - var tagsJSON = getSetting("tags"); - if (typeof tagsJSON !== "undefined") { - return JSON.parse(tagsJSON) - } - return []; - } - - var sortedUsedTagsFromSettings = function() { - // Get and Sort used tags - var usedTags = []; - - var usedTagsJSON = getSetting("usedTags"); - if (typeof usedTagsJSON !== "undefined") { - var usedTagsObject = JSON.parse(usedTagsJSON); - var usedTagsObjectArray = []; - for (var tagKey in usedTagsObject) { - usedTagsObjectArray.push(usedTagsObject[tagKey]); - } - - // Sort usedTagsObjectArray based on timestamp - usedTagsObjectArray.sort(function(usedTagA, usedTagB) { - var a = usedTagA.timestamp; - var b = usedTagB.timestamp; - return a - b; - }); - - // Get all keys tags - for (var j = 0; j < usedTagsObjectArray.length; j++) { - usedTags.push(usedTagsObjectArray[j].tag); - } - - // Reverse to set the last recent used tags to the front - usedTags.reverse(); - } - - return usedTags; - } - - if (callback) { - var tags = tagsFromSettings(); - var usedTags = sortedUsedTagsFromSettings(); - callback(tags, usedTags); - } - } - - /** - * Fetch suggested tags for a given item id - * @param {string} itemId Item id of - * @param {Object | undefined} options Can provide an actionInfo object - * with further data to send to the API. - * Can have success and error callbacks - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function getSuggestedTagsForItem(itemId, options) { - return getSuggestedTags({item_id: itemId}, options); - } - - /** - * Fetch suggested tags for a given URL - * @param {string} url (required) The item identifier by url - * @param {Object} options Can provide an actionInfo object with further - * data to send to the API. Can have success and error - * callbacks - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function getSuggestedTagsForURL(url, options) { - return getSuggestedTags({url: url}, options); - } - - /** - * Helper function to get suggested tags - * @return {Boolean} Returns Boolean whether the api call started sucessfully - */ - function getSuggestedTags(data, options) { - - data = data || {}; - options = options || {}; - - data.access_token = getAccessToken(); - - return apiRequest({ - path: "/getSuggestedTags", - data: data, - success: options.success, - error: options.error - }); - } - - /** - * Helper function to get current signup AB group the user is in - */ - function getSignupPanelTabTestVariant() { - return getMultipleTestOption('panelSignUp', {control: 1, v1: 8, v2: 1 }) - } - - function getMultipleTestOption(testName, testOptions) { - // Get the test from preferences if we've already assigned the user to a test - var settingName = 'test.' + testName; - var assignedValue = getSetting(settingName); - var valArray = []; - - // If not assigned yet, pick and store a value - if (!assignedValue) - { - // Get a weighted array of test variants from the testOptions object - Object.keys(testOptions).forEach(function(key) { - for (var i = 0; i < testOptions[key]; i++) { - valArray.push(key); - } - }); - - // Get a random test variant and set the user to it - assignedValue = valArray[Math.floor(Math.random() * valArray.length)]; - setSetting(settingName, assignedValue); - } - - return assignedValue; - - } - - /** - * Public functions - */ - return { - isUserLoggedIn : isUserLoggedIn, - clearUserData: clearUserData, - addLink: addLink, - deleteItem: deleteItem, - addTagsToItem: addTagsToItem, - addTagsToURL: addTagsToURL, - getTags: getTags, - isPremiumUser: isPremiumUser, - getSuggestedTagsForItem: getSuggestedTagsForItem, - getSuggestedTagsForURL: getSuggestedTagsForURL, - getSignupPanelTabTestVariant: getSignupPanelTabTestVariant, - }; -}()); diff --git a/browser/extensions/pocket/content/pocket-content-process.js b/browser/extensions/pocket/content/pocket-content-process.js deleted file mode 100644 index 9b158a0ed..000000000 --- a/browser/extensions/pocket/content/pocket-content-process.js +++ /dev/null @@ -1,54 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -// This file is loaded as a process script, it will be loaded in the parent -// process as well as all content processes. - -const { utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("chrome://pocket/content/AboutPocket.jsm"); - -function AboutPocketChildListener() { -} -AboutPocketChildListener.prototype = { - onStartup: function onStartup() { - - // Only do this in content processes since, as the broadcaster of this - // message, the parent process doesn't also receive it. We handlers - // the shutting down separately. - if (Services.appinfo.processType == - Services.appinfo.PROCESS_TYPE_CONTENT) { - - Services.cpmm.addMessageListener("PocketShuttingDown", this, true); - } - - AboutPocket.aboutSaved.register(); - AboutPocket.aboutSignup.register(); - }, - - onShutdown: function onShutdown() { - AboutPocket.aboutSignup.unregister(); - AboutPocket.aboutSaved.unregister(); - - Services.cpmm.removeMessageListener("PocketShuttingDown", this); - Cu.unload("chrome://pocket/content/AboutPocket.jsm"); - }, - - receiveMessage: function receiveMessage(message) { - switch (message.name) { - case "PocketShuttingDown": - this.onShutdown(); - break; - default: - break; - } - - return; - } -}; - -const listener = new AboutPocketChildListener(); -listener.onStartup(); diff --git a/browser/extensions/pocket/install.rdf.in b/browser/extensions/pocket/install.rdf.in deleted file mode 100644 index babccfa5a..000000000 --- a/browser/extensions/pocket/install.rdf.in +++ /dev/null @@ -1,32 +0,0 @@ -<?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/. --> - -#filter substitution - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>firefox@getpocket.com</em:id> - <em:version>1.0.5</em:version> - <em:type>2</em:type> - <em:bootstrap>true</em:bootstrap> - <em:multiprocessCompatible>true</em:multiprocessCompatible> - - <!-- Target Application this theme can install into, - with minimum and maximum supported versions. --> - <em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>@MOZ_APP_VERSION@</em:minVersion> - <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion> - </Description> - </em:targetApplication> - - <!-- Front End MetaData --> - <em:name>Pocket</em:name> - <em:description>When you find something you want to view later, put it in Pocket.</em:description> - </Description> -</RDF> diff --git a/browser/extensions/pocket/jar.mn b/browser/extensions/pocket/jar.mn deleted file mode 100644 index 5fab627fe..000000000 --- a/browser/extensions/pocket/jar.mn +++ /dev/null @@ -1,32 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -[features/firefox@getpocket.com] chrome.jar: -% content pocket %content/ contentaccessible=yes -% skin pocket classic/1.0 %skin/linux/ -% skin pocket classic/1.0 %skin/osx/ os=Darwin -% skin pocket classic/1.0 %skin/windows/ os=WINNT -% skin pocket-shared classic/1.0 %skin/shared/ - content/ (content/*) - skin/ (skin/*) -# windows overrides -% override chrome://pocket/skin/menuPanel.png chrome://pocket/skin/menuPanel-aero.png os=WINNT osversion=6 -% override chrome://pocket/skin/menuPanel.png chrome://pocket/skin/menuPanel-aero.png os=WINNT osversion=6.1 -% override chrome://pocket/skin/menuPanel@2x.png chrome://pocket/skin/menuPanel-aero@2x.png os=WINNT osversion=6 -% override chrome://pocket/skin/menuPanel@2x.png chrome://pocket/skin/menuPanel-aero@2x.png os=WINNT osversion=6.1 -% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-aero@2x.png os=WINNT osversion=6 -% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-aero@2x.png os=WINNT osversion=6.1 -% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-win8@2x.png os=WINNT osversion=6.2 -% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-win8@2x.png os=WINNT osversion=6.3 -% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-XP.png os=WINNT osversion<6 -% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-aero.png os=WINNT osversion=6 -% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-aero.png os=WINNT osversion=6.1 -% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-win8.png os=WINNT osversion=6.2 -% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-win8.png os=WINNT osversion=6.3 -# osx overrides -% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-yosemite.png os=Darwin osversion>=10.10 -% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-yosemite@2x.png os=Darwin osversion>=10.10 -% override chrome://pocket/skin/menuPanel.png chrome://pocket/skin/menuPanel-yosemite.png os=Darwin osversion>=10.10 -% override chrome://pocket/skin/menuPanel@2x.png chrome://pocket/skin/menuPanel-yosemite@2x.png os=Darwin osversion>=10.10 - diff --git a/browser/extensions/pocket/locale/ast/pocket.properties b/browser/extensions/pocket/locale/ast/pocket.properties deleted file mode 100644 index c32e53b54..000000000 --- a/browser/extensions/pocket/locale/ast/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Amestar etiquetes -alreadyhaveacct = ¿Yá yes un usuariu de Pocket? -continueff = Siguir con Firefox -errorgeneric = Hebo un fallu tentando de guardar en Pocket. -learnmore = Depriendi más -loginnow = Aniciar sesión -maxtaglength = Les etiquetes lléndense a 25 caráuteres -mustbeconnected = Has tar coneutáu a internet pa guardar en Pocket. Comprueba la to conexón y volvi tentalo, por favor. -onlylinkssaved = Namái puen guardase enllaces -pagenotsaved = Páxina non guardada -pageremoved = Páxina desaniciada -pagesaved = Guardóse en Pocket -processingremove = Desaniciando páxina… -processingtags = Amestando etiquetes… -removepage = Desanicia páxina -save = Guardar -saving = Guardando… -signupemail = Rexistrase con corréu -signuptosave = Rexístrate en Pocket. Ye de baldre. -suggestedtags = Etiquetes suxeríes -tagline = Guardar artículos y vídeos dende Firefox pa ver en Pocket o en cualquier preséu, en cualquier momentu. -taglinestory_one = Fai clic nel botón de Pocket pa guardar cualquier artículu, videu o páxina dende Firefox. -taglinestory_two = Ver en Pocker o en cualquier preséu, en cualquier momentu. -tagssaved = Etiquetes amestaes -tos = Sigiuiendo, tas acordies colos <a href="%1$S" target="_blank">Términos de Serviciu</a> y la <a href="%2$S" target="_blank">Política de privacidá</a> de Pocket -tryitnow = Pruébalu agora -signinfirefox = Anicia sesión con Firefox -signupfirefox = Rexístrate con Firefox -viewlist = Ver llista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Guardar en Pocket -saveToPocketCmd.label = Guardar páxina en Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Guardar enllaz en Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Ver la llista de Pocket diff --git a/browser/extensions/pocket/locale/az/pocket.properties b/browser/extensions/pocket/locale/az/pocket.properties deleted file mode 100644 index a228ca026..000000000 --- a/browser/extensions/pocket/locale/az/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Etiket əlavə et -alreadyhaveacct = Artıq Pocket istifadəçisisiniz? -continueff = Firefox ilə davam et -errorgeneric = Pocket-ə saxlarkən xəta baş verdi. -learnmore = Ətraflı Öyrən -loginnow = Daxil ol -maxtaglength = Etiketlər 25 simvol ilə limitlidir -mustbeconnected = Pocket-ə saxlamaq üçün internetə qoşulu olmalısınız. Lütfən internetə qoşulu olduğunuza əmin olub təkrar yoxlayın. -onlylinkssaved = Ancaq keçidlər saxlana bilər -pagenotsaved = Səhifə saxlanmadı -pageremoved = Səhifə silindi -pagesaved = Pocket-ə saxlandı -processingremove = Səhifə silinir… -processingtags = Etiketlər əlavə edilir… -removepage = Səhifəni sil -save = Saxla -saving = Saxlanır… -signupemail = E-poçt ilə qeyd ol -signuptosave = Pocket üçün qeyd ol. Bu pulsuzdur. -suggestedtags = Məsləhərli etiketlər -tagline = Firefoxdan məqalə və videoları Pocket-ə saxlayın, istədiyiniz vaxt, istədiyiniz yerdə baxın. -taglinestory_one = Firefoxda hər hansı bir məqalə, video və ya səhifəni saxlamaq üçün Pocket Düyməsinə klikləyin. -taglinestory_two = İstənilən cihazda, istənilən vaxt Pocket-də görün. -tagssaved = Etiketlər əlavə edildi -tos = Davam etməklə, Pocket-in <a href="%1$S" target="_blank">İstifadə Şərtləri</a> və <a href="%2$S" target="_blank">Məxfilik Siyasəti</a> ilə razılaşmış olursunuz -tryitnow = İndi Yoxlayın -signinfirefox = Firefox ilə daxil ol -signupfirefox = Firefox ilə qeyd ol -viewlist = Siyahını gör - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Pocket-ə Saxla -saveToPocketCmd.label = Səhifəni Pocket-ə Saxla -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Keçidi Pocket-ə Saxla -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Pocket Siyahısını Gör diff --git a/browser/extensions/pocket/locale/bg/pocket.properties b/browser/extensions/pocket/locale/bg/pocket.properties deleted file mode 100644 index ba86dd7f6..000000000 --- a/browser/extensions/pocket/locale/bg/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Добавяне на етикети -alreadyhaveacct = Вече сте потребител на Pocket? -continueff = Продължаване с Firefox -errorgeneric = Получи се грешка при опит за запис в Pocket. -learnmore = Научете повече -loginnow = Вписване -maxtaglength = Етикетите могат да са до 25 знака -mustbeconnected = Трябва да сте свързан към Интернет, за да запазвате в Pocket. Моля, проверете свързаността си с Интернет и пробвайте отново. -onlylinkssaved = Могат да бъдат запазвани само връзки -pagenotsaved = Страницата не е запазена -pageremoved = Страницата е премахната -pagesaved = Запазена в Pocket -processingremove = Премахване на страница… -processingtags = Добавяне на етикети… -removepage = Премахване на страница -save = Запазване -saving = Запазване… -signupemail = Регистриране с мейл -signuptosave = Регистрирайте се в Pocket. Безплатно е. -suggestedtags = Предложени етикети -tagline = Запазвайте статии и видеота от Firefox и можете да ги преглеждате в Pocket на всяко устройство по всяко време. -taglinestory_one = Щракнете на бутона на Pocket за запазване на статия, видео или страница от Firefox. -taglinestory_two = Преглеждайте в Pocket на всяко устройство и по всяко време. -tagssaved = Етикетите са добавени -tos = Продължавайки, вие се съгласявате с <a href="%1$S" target="_blank">Условията за ползване</a> и <a href="%2$S" target="_blank">Политиката за поверителност</a> на Pocket -tryitnow = Опитайте сега -signinfirefox = Вписване с Firefox -signupfirefox = Регистриране с Firefox -viewlist = Преглед на списъка - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Запазване в Pocket -saveToPocketCmd.label = Запазване на страницата в Pocket -saveToPocketCmd.accesskey = с -saveLinkToPocketCmd.label = Запазване на връзката в Pocket -saveLinkToPocketCmd.accesskey = в -pocketMenuitem.label = Преглед списъка на Pocket diff --git a/browser/extensions/pocket/locale/bn-BD/pocket.properties b/browser/extensions/pocket/locale/bn-BD/pocket.properties deleted file mode 100644 index 7a43edad1..000000000 --- a/browser/extensions/pocket/locale/bn-BD/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = ট্যাগ যোগ করুন -alreadyhaveacct = আপনি Pocket ব্যবহার করছেন? -continueff = Firefox ব্যবহার চালিয়ে যান -errorgeneric = Pocket এ সংরক্ষণ করতে ত্রুটি ঘটেছে। -learnmore = আরও জানুন -loginnow = লগ ইন -maxtaglength = ট্যাগ ২৫ অক্ষরের মধ্যে সীমাবদ্ধ -mustbeconnected = Pocket এ কোন কিছু সংরক্ষণ করে রাখতে চাইলে, ইন্টারনেটে সংযুক্ত থাকতে হবে। ইন্টারনেট সংযোগ পরীক্ষা করুন এবং আবার চেষ্টা করুন। -onlylinkssaved = শুধু লিঙ্ক সংরক্ষণ করা যাবে -pagenotsaved = পাতা সংরক্ষণ করা হয়নি -pageremoved = পাতা অপসারণ করা হয়েছে -pagesaved = Pocket এ সংরক্ষিত হয়েছে -processingremove = পাতা অপসারিত হচ্ছে… -processingtags = ট্যাগ যুক্ত করা হচ্ছে… -removepage = পেজ মুছে ফেলুন -save = সংরক্ষণ -saving = সংরক্ষণ করা হচ্ছে... -signupemail = ইমেইল দিয়ে সাইন আপ করুন -signuptosave = Pocket সাইন আপ করুন। এটি মুফত। -suggestedtags = প্রস্তাবিত ট্যাগ -tagline = Pocket এর মাধ্যমে যেকোন সময়, যেকোন ডিভাইসে নিবন্ধ এবং ভিডিও দেখতে Firefox থেকে সেগুলো সংরক্ষণ করুন। -taglinestory_one = Firefox থেকে আর্টিকেল, ভিডিও বা পৃষ্ঠা সংরক্ষণ করার জন্য Pocket বাটন ক্লিক করুন। -taglinestory_two = যেকোন সময়ে, যেকোন স্থানে Pocket এ দেখুন। -tagssaved = ট্যাগ যোগ করা হয়েছে -tos = এটি অব্যহত রেখে, আপনি Pocket এর <a href="%1$S" target="_blank">সেবার শর্তাবলী</a> এবং <a href="%2$S" target="_blank">গোপনীয়তা নীতিমালায়</a> সম্মত হবেন। -tryitnow = এখনই ব্যবহার করুন -signinfirefox = ফায়ারফক্স দিয়ে সাইন ইন করুন -signupfirefox = ফায়ারফক্স দিয়ে সাইন আপ করুন -viewlist = তালিকা দেখুন - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Pocket এ সংরক্ষণ করুন -saveToPocketCmd.label = Pocket এ পাতাটি সংরক্ষণ করুন k -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Pocket এ লিঙ্কটি সংরক্ষণ করুন o -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Pocket তালিকা দেখুন diff --git a/browser/extensions/pocket/locale/cs/pocket.properties b/browser/extensions/pocket/locale/cs/pocket.properties deleted file mode 100644 index 619b0a01a..000000000 --- a/browser/extensions/pocket/locale/cs/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Přidat štítky -alreadyhaveacct = Jste již uživatel služby Pocket? -continueff = Pokračovat pomocí Firefoxu -errorgeneric = Při pokusu o uložení do služby Pocket došlo k chybě. -learnmore = Zjistit více -loginnow = Přihlásit se -maxtaglength = Štítky jsou omezeny na 25 znaků -mustbeconnected = Abyste mohli ukládat do služby Pocket, musíte být připojeni k internetu. Zkontrolujte prosím své připojení a zkuste to znovu. -onlylinkssaved = Pouze odkazy mohou být uloženy -pagenotsaved = Stránka nebyla uložena -pageremoved = Stránka byla odstraněna -pagesaved = Uloženo do služby Pocket -processingremove = Odstraňování stránky… -processingtags = Přidávání štítků… -removepage = Odstranit stránku -save = Uložit -saving = Ukládání… -signupemail = Registrace e-mailem -signuptosave = Registrujte se do služby Pocket. Je to zdarma. -suggestedtags = Doporučené štítky -tagline = Ukládejte si články a videa z Firefoxu pro zobrazení ve službě Pocket kdykoliv a na jakémkoli zařízení. -taglinestory_one = Klepněte na tlačítko služby Pocket pro uložení jakéhokoliv článku, videa nebo stránky přímo z Firefoxu. -taglinestory_two = Zobrazení ve službě Pocket kdykoliv a na jakémkoliv zařízení. -tagssaved = Štítky přidány -tos = Pokračování souhlasíte s <a href="%1$S" target="_blank">Podmínkami služby</a> Pocket a <a href="%2$S" target="_blank">Zásadami ochrany osobních údajů</a> -tryitnow = Vyzkoušejte nyní -signinfirefox = Přihlášení ve Firefoxu -signupfirefox = Registrace ve Firefoxu -viewlist = Zobrazit seznam - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Uloží do služby Pocket -saveToPocketCmd.label = Uložit stránku do služby Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Uložit odkaz do služby Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Zobrazit seznam služby Pocket diff --git a/browser/extensions/pocket/locale/da/pocket.properties b/browser/extensions/pocket/locale/da/pocket.properties deleted file mode 100644 index 5e5438359..000000000 --- a/browser/extensions/pocket/locale/da/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Tilføj tags -alreadyhaveacct = Er du allerede Pocket-bruger? -continueff = Fortsæt med Firefox -errorgeneric = Der opstod en fejl ved forsøg på at gemme til Pocket. -learnmore = Læs mere -loginnow = Log ind -maxtaglength = Tags er begrænset til 25 tegn -mustbeconnected = Du skal have forbindelse til internettet for at kunne gemme til Pocket. Kontroller din internetforbindelse og prøv igen. -onlylinkssaved = Kun links kan gemmes -pagenotsaved = Siden blev ikke gemt -pageremoved = Siden er fjernet -pagesaved = Gemt til Pocket -processingremove = Fjerner side… -processingtags = Tilføjer tags… -removepage = Fjern side -save = Gem -saving = Gemmer… -signupemail = Log ind med mailadresse -signuptosave = Meld dig til Pocket. Det er gratis. -suggestedtags = Foreslåede tags -tagline = Gemmer artikler og videoer fra Firefox i Pocket, så du senere kan se dem hvor og hvornår, du har lyst. -taglinestory_one = Klik på knappen Pocket for at gemme en artikel, video eller webside fra Firefox. -taglinestory_two = Se i Pocket hvor og hvornår, du har lyst. -tagssaved = Tags tilføjet -tos = Fortsætter du, accepterer du Pockets <a href="%1$S" target="_blank">tjenestevilkår</a> og <a href="%2$S" target="_blank">privatlivspolitik</a> -tryitnow = Prøv det nu -signinfirefox = Log ind med Firefox -signupfirefox = Meld dig til med Firefox -viewlist = Vis liste - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Gem til Pocket -saveToPocketCmd.label = Gem siden til Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Gem link til Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Vis Pocket-liste diff --git a/browser/extensions/pocket/locale/de/pocket.properties b/browser/extensions/pocket/locale/de/pocket.properties deleted file mode 100644 index f02f5da05..000000000 --- a/browser/extensions/pocket/locale/de/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Tags hinzufügen -alreadyhaveacct = Sind Sie bereits Pocket-Nutzer? -continueff = Mit Firefox fortfahren -errorgeneric = Beim Speichern des Links bei Pocket ist ein Fehler aufgetreten. -learnmore = Mehr erfahren -loginnow = Anmelden -maxtaglength = Tags dürfen höchsten 25 Zeichen lang sein. -mustbeconnected = Bitte überprüfen Sie, ob Sie mit dem Internet verbunden sind. -onlylinkssaved = Es können nur Links gespeichert werden -pagenotsaved = Seite nicht gespeichert -pageremoved = Seite entfernt -pagesaved = Bei Pocket gespeichert -processingremove = Seite wird entfernt… -processingtags = Tags werden hinzugefügt… -removepage = Seite entfernen -save = Speichern -saving = Speichern… -signupemail = Mit E-Mail registrieren -signuptosave = Registrieren Sie sich bei Pocket. Das ist kostenlos. -suggestedtags = Vorgeschlagene Tags -tagline = Speichern Sie Artikel und Videos aus Firefox bei Pocket, um sie jederzeit und auf jedem Gerät ansehen zu können. -taglinestory_one = Klicken Sie auf die Pocket-Schaltfläche, um beliebige Artikel, Videos und Seiten aus Firefox zu speichern. -taglinestory_two = Lesen Sie diese mit Pocket, jederzeit und auf jedem Gerät. -tagssaved = Tags hinzugefügt -tos = Indem Sie fortfahren, akzeptieren Sie die <a href="%1$S" target="_blank">Nutzungsbedingungen</a> und die <a href="%2$S" target="_blank">Datenschutzerklärung</a> von Pocket. -tryitnow = Jetzt ausprobieren -signinfirefox = Mit Firefox anmelden -signupfirefox = Mit Firefox registrieren -viewlist = Liste anzeigen - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Bei Pocket speichern -saveToPocketCmd.label = Seite bei Pocket speichern -saveToPocketCmd.accesskey = b -saveLinkToPocketCmd.label = Link bei Pocket speichern -saveLinkToPocketCmd.accesskey = c -pocketMenuitem.label = Pocket-Liste anzeigen diff --git a/browser/extensions/pocket/locale/dsb/pocket.properties b/browser/extensions/pocket/locale/dsb/pocket.properties deleted file mode 100644 index a878de329..000000000 --- a/browser/extensions/pocket/locale/dsb/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Wobznamjenja pśidaś -alreadyhaveacct = Sćo južo wužywaŕ Pocket? -continueff = Z Firefox pókšacowaś -errorgeneric = Pśi składowanju do Pocket jo zmólka nastała. -learnmore = Dalšne informacije -loginnow = Pśizjawiś -maxtaglength = Wobznamjenja su na 25 znamuškow wobgranicowane -mustbeconnected = Musyśo z internetom zwězany byś, aby do Pocket składował. Pšosym pśeglědajśo swój zwisk a wopytajśo hyšći raz. -onlylinkssaved = Jano wótkaze daju se składowaś -pagenotsaved = Bok njejo se składł -pageremoved = Bok jo se wótwónoźeł -pagesaved = Do Pocket skłaźony -processingremove = Bok se wótwónoźujo… -processingtags = Wobznamjenja se pśidawaju… -removepage = Bok wótwónoźeś -save = Składowaś -saving = Składujo se… -signupemail = Registrěrujśo se z mejlku -signuptosave = Registrěrujśo se za Pocket. Jo dermo. -suggestedtags = Naraźone wobznamjenja -tagline = Składujśo nastawki a wideo z Firefox, aby se je kuždy cas w Pocket na kuždem rěźe woglědał. -taglinestory_one = Klikniśo na tłocašk Pocket, aby nastawk, wideo abo bok z Firefox składował. -taglinestory_two = Se w Pocket na kuždem rěźee kuždy cas woglědaś. -tagssaved = Wobznamjenja su se pśidali -tos = Gaž pókšacujośo, zwólijośo do <a href="%1$S" target="_blank">wužywarskich wuměnjenjow</a> a <a href="%2$S" target="_blank">pšawidłow priwatnosći</a> Pocket -tryitnow = Wopytajśo to něnto -signinfirefox = Z Firefox pśizjawiś -signupfirefox = Z Firefox registrěrowaś -viewlist = Lisćinu pokazaś - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Do Pocket składowaś -saveToPocketCmd.label = Bok do Pocket składowaś -saveToPocketCmd.accesskey = b -saveLinkToPocketCmd.label = Wótkaz do Pocket składowaś -saveLinkToPocketCmd.accesskey = w -pocketMenuitem.label = Lisćinu Pocket pokazaś diff --git a/browser/extensions/pocket/locale/en-GB/pocket.properties b/browser/extensions/pocket/locale/en-GB/pocket.properties deleted file mode 100644 index bddd825c5..000000000 --- a/browser/extensions/pocket/locale/en-GB/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Add Tags -alreadyhaveacct = Already a Pocket user? -continueff = Continue with Firefox -errorgeneric = There was an error when trying to save to Pocket. -learnmore = Learn More -loginnow = Log in -maxtaglength = Tags are limited to 25 characters -mustbeconnected = You must be connected to the Internet in order to save to Pocket. Please check your connection and try again. -onlylinkssaved = Only links can be saved -pagenotsaved = Page Not Saved -pageremoved = Page Removed -pagesaved = Saved to Pocket -processingremove = Removing Page… -processingtags = Adding tags… -removepage = Remove Page -save = Save -saving = Saving… -signupemail = Sign up with email -signuptosave = Sign up for Pocket. It’s free. -suggestedtags = Suggested Tags -tagline = Save articles and videos from Firefox to view in Pocket on any device, any time. -taglinestory_one = Click the Pocket Button to save any article, video or page from Firefox. -taglinestory_two = View in Pocket on any device, any time. -tagssaved = Tags Added -tos = By continuing, you agree to Pocket’s <a href="%1$S" target="_blank">Terms of Service</a> and <a href="%2$S" target="_blank">Privacy Policy</a> -tryitnow = Try It Now -signinfirefox = Sign in with Firefox -signupfirefox = Sign up with Firefox -viewlist = View List - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Save to Pocket -saveToPocketCmd.label = Save Page to Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Save Link to Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = View Pocket List diff --git a/browser/extensions/pocket/locale/en-US/pocket.properties b/browser/extensions/pocket/locale/en-US/pocket.properties deleted file mode 100644 index dee2681dc..000000000 --- a/browser/extensions/pocket/locale/en-US/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Add Tags -alreadyhaveacct = Already a Pocket user? -continueff = Continue with Firefox -errorgeneric = There was an error when trying to save to Pocket. -learnmore = Learn More -loginnow = Log in -maxtaglength = Tags are limited to 25 characters -mustbeconnected = You must be connected to the Internet in order to save to Pocket. Please check your connection and try again. -onlylinkssaved = Only links can be saved -pagenotsaved = Page Not Saved -pageremoved = Page Removed -pagesaved = Saved to Pocket -processingremove = Removing Page… -processingtags = Adding tags… -removepage = Remove Page -save = Save -saving = Saving… -signupemail = Sign up with email -signuptosave = Sign up for Pocket. It’s free. -suggestedtags = Suggested Tags -tagline = Save articles and videos from Firefox to view in Pocket on any device, any time. -taglinestory_one = Click the Pocket Button to save any article, video or page from Firefox. -taglinestory_two = View in Pocket on any device, any time. -tagssaved = Tags Added -tos = By continuing, you agree to Pocket's <a href="%1$S" target="_blank">Terms of Service</a> and <a href="%2$S" target="_blank">Privacy Policy</a> -tryitnow = Try It Now -signinfirefox = Sign in with Firefox -signupfirefox = Sign up with Firefox -viewlist = View List - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Save to Pocket -saveToPocketCmd.label = Save Page to Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Save Link to Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = View Pocket List diff --git a/browser/extensions/pocket/locale/es-AR/pocket.properties b/browser/extensions/pocket/locale/es-AR/pocket.properties deleted file mode 100644 index 2782d3ccf..000000000 --- a/browser/extensions/pocket/locale/es-AR/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Agregar etiquetas -alreadyhaveacct = ¿Ya es un usuario de Pocket? -continueff = Continuar con Firefox -errorgeneric = Hubo un error al tratar de guardar en Pocket. -learnmore = Conocer más -loginnow = Ingresar -maxtaglength = Las etiquetas están limitadas a 25 caracteres -mustbeconnected = Debe estar conectado a Internet para poder guardar en Pocket. Verifique la conexión e intente nuevamente. -onlylinkssaved = Solamente pueden guardarle enlaces -pagenotsaved = Página no guardada -pageremoved = Página eliminada -pagesaved = Guardado en Pocket -processingremove = Eliminando página… -processingtags = Agregando etiquetas… -removepage = Eliminar página -save = Guardar -saving = Guardando… -signupemail = Ingresar con correo electrónico -signuptosave = Registrarse en Pocket. En grátis. -suggestedtags = Etiquetas sugeridas -tagline = Guardar artículos y videos desde Firefox para ver en Pocket en cualquier dispositivo en cualquier momento. -taglinestory_one = Clic en el botón Pocket para guardar cualquier artículo, video o página desde Firefox. -taglinestory_two = Ver en Pocket en cualquier dispositivo en cualquier momento. -tagssaved = Etiquetas agregadas -tos = Al continuar acepta los <a href="%1$S" target="_blank">términos de servicio</a> y la <a href="%2$S" target="_blank">política de privacidad</a> de Pocket -tryitnow = Probalo ahora -signinfirefox = Ingresar con Firefox -signupfirefox = Registrarse con Firefox -viewlist = Ver lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Guardar en Pocket -saveToPocketCmd.label = Guardar página en Pocket -saveToPocketCmd.accesskey = G -saveLinkToPocketCmd.label = Guardar enlace en Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Ver lista de Pocket diff --git a/browser/extensions/pocket/locale/es-CL/pocket.properties b/browser/extensions/pocket/locale/es-CL/pocket.properties deleted file mode 100644 index 7a4e6872b..000000000 --- a/browser/extensions/pocket/locale/es-CL/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Añadir etiquetas -alreadyhaveacct = ¿Ya eres usuario de Pocket? -continueff = Continuar con Firefox -errorgeneric = Hubo un error al intentar guardarla en Pocket. -learnmore = Aprender más -loginnow = Conectarse -maxtaglength = Las etiquetas están limitadas a 25 caracteres -mustbeconnected = Debes estar conectado a Internet para guardar en Pocket. Por favor, revisa tu conexión y vuelve a intentarlo. -onlylinkssaved = Solo se pueden guardar enlaces -pagenotsaved = Página no guardada -pageremoved = Página eliminada -pagesaved = Guardada en Pocket -processingremove = Eliminando página… -processingtags = Añadiendo etiquetas… -removepage = Eliminar página -save = Guardar -saving = Guardando… -signupemail = Registrarse usando un email -signuptosave = Registrarse en Pocket. Es gratis. -suggestedtags = Etiquetas sugeridas -tagline = Guarda artículos y videos desde Firefox para verlos en Pocket en cualquier dispositivo y momento. -taglinestory_one = Aprieta el botón Pocket para guardar cualquier artículo, video o página de Firefox. -taglinestory_two = Mírala en Pocket en cualquier dispositivo y momento -tagssaved = Etiquetas añadidas -tos = Al continuar, aceptas los <a href="%1$S" target="_blank">Términos del servicio</a> y la <a href="%2$S" target="_blank">Política de privacidad</a> de Pocket. -tryitnow = Probarlo ahora -signinfirefox = Conectarse con Firefox -signupfirefox = Registrarse con Firefox -viewlist = Ver lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Guardar en Pocket -saveToPocketCmd.label = Guardar página en Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Guardar enlace en Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Ver lista de Pocket diff --git a/browser/extensions/pocket/locale/es-ES/pocket.properties b/browser/extensions/pocket/locale/es-ES/pocket.properties deleted file mode 100644 index f10a20525..000000000 --- a/browser/extensions/pocket/locale/es-ES/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Añadir etiquetas -alreadyhaveacct = ¿Ya es usuario de Pocket? -continueff = Continuar con Firefox -errorgeneric = Ha sucedido un error al intentar guardar en Pocket. -learnmore = Más información -loginnow = Iniciar sesión -maxtaglength = Las etiquetas están limitadas a 25 caracteres -mustbeconnected = Debe estar conectado a Internet para poder guardar en Pocket. Compruebe su conexión y vuelva a intentarlo. -onlylinkssaved = Solo se pueden guardar enlaces -pagenotsaved = Página no guardada -pageremoved = Página eliminada -pagesaved = Guardado en Pocket -processingremove = Eliminando página… -processingtags = Añadiendo etiquetas… -removepage = Eliminar página -save = Guardar -saving = Guardando… -signupemail = Regístrese con su dirección de correo -signuptosave = Regístrese en Pocket. Es gratis. -suggestedtags = Etiquetas sugeridas -tagline = Guarde artículos y vídeos desde Firefox para verlos en Pocket en cualquier dispositivo, en cualquier momento. -taglinestory_one = Pulse el botón Pocket para guardar cualquier artículo, vídeo o página desde Firefox. -taglinestory_two = Véalo en Pocket en cualquier dispositivo, en cualquier momento. -tagssaved = Etiquetas añadidas -tos = Al continuar, aceptas los <a href="%1$S" target="_blank">Términos del servicio</a> y la <a href="%2$S" target="_blank">Política de privacidad</a> de Pocket -tryitnow = Pruébalo ahora -signinfirefox = Iniciar sesión con Firefox -signupfirefox = Registrarse con Firefox -viewlist = Ver lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Guardar en Pocket -saveToPocketCmd.label = Guardar página en Pocket -saveToPocketCmd.accesskey = G -saveLinkToPocketCmd.label = Guardar enlace en Pocket -saveLinkToPocketCmd.accesskey = P -pocketMenuitem.label = Ver la lista de Pocket diff --git a/browser/extensions/pocket/locale/es-MX/pocket.properties b/browser/extensions/pocket/locale/es-MX/pocket.properties deleted file mode 100644 index 4d2bb9c4f..000000000 --- a/browser/extensions/pocket/locale/es-MX/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Agregar Etiquetas -alreadyhaveacct = ¿Ya eres usuario de Pocket? -continueff = Continúa con Firefox -errorgeneric = Hubo un error cuando se intentaba guardar en Pocket. -learnmore = Aprende más -loginnow = Ingresar -maxtaglength = Las etiquetas están limitadas a 25 caracteres -mustbeconnected = Debes estar conectado a Internet para guardar en Pocket. Por favor, revisa tu conexión e intenta de nuevo. -onlylinkssaved = Sólo los enlaces pueden guardarse -pagenotsaved = Página no guardada -pageremoved = Página eliminada -pagesaved = Guardado en Pocket -processingremove = Eliminando página… -processingtags = Agregando etiquetas… -removepage = Eliminar página -save = Guardar -saving = Guardando… -signupemail = Regístrate con un correo electrónico -signuptosave = Regístrate en Pocket. Es gratis. -suggestedtags = Etiquetas sugeridas -tagline = Guardar artículos y videos desde Firefox para ver en Pocket o en cualquier dispositivo, en cualquier momento. -taglinestory_one = Haz clic en el botón de Pocket para guardar cualquier artículo, video o página desde Firefox. -taglinestory_two = Ver en Pocker o en cualquier dispositivo, en cualquier momento. -tagssaved = Etiquetas agregadas -tos = Al continuar, aceptas los <a href="%1$S" target="_blank">Términos del servicio</a> y la <a href="%2$S" target="_blank">Política de privacidad</a> de Pocket -tryitnow = Pruébalo ahora -signinfirefox = Ingresa con Firefox -signupfirefox = Regístrate con Firefox -viewlist = Ver lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Guardar en Pocket -saveToPocketCmd.label = Guardar página en Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Guardar enlace en Pocket -saveLinkToPocketCmd.accesskey = n -pocketMenuitem.label = Ver la lista de Pocket diff --git a/browser/extensions/pocket/locale/et/pocket.properties b/browser/extensions/pocket/locale/et/pocket.properties deleted file mode 100644 index 5f2d68f9c..000000000 --- a/browser/extensions/pocket/locale/et/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Lisa silte -alreadyhaveacct = Kas oled juba Pocketi kasutaja? -continueff = Jätka Firefoxiga -errorgeneric = Pocketisse salvestamisel esines viga. -learnmore = Rohkem teavet -loginnow = Logi sisse -maxtaglength = Siltide pikkus võib olla kuni 25 tähemärki -mustbeconnected = Pocketisse salvestamiseks on vajalik töötav internetiühendus. Palun kontrolli oma ühendust ja proovi uuesti. -onlylinkssaved = Salvestada saab ainult linke -pagenotsaved = Lehte ei salvestatud -pageremoved = Leht eemaldati -pagesaved = Pocketisse salvestatud -processingremove = Lehe eemaldamine… -processingtags = Siltide lisamine… -removepage = Eemalda leht -save = Salvesta -saving = Salvestamine… -signupemail = Registreeru e-posti teel -signuptosave = Liitu Pocketiga. See on tasuta. -suggestedtags = Soovitatud sildid -tagline = Salvesta Firefoxist artikleid ja videoid, et vaadata neid Pocketist kõigil seadmeil just siis, kui ise soovid. -taglinestory_one = Artikli, video või lehe salvestamiseks klõpsa Pocketi nupul. -taglinestory_two = Vaata Pocketist kõigil seadmeil just siis, kui ise soovid. -tagssaved = Sildid on lisatud -tos = Jätkates nõustud Pocket'i <a href="%1$S" target="_blank">kasutustingimuste</a> ja <a href="%2$S" target="_blank">privaatsuspoliitikaga</a>. -tryitnow = Proovi kohe -signinfirefox = Logi sisse Firefoxiga -signupfirefox = Registreeru Firefoxiga -viewlist = Vaata nimekirja - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Salvesta Pocketisse -saveToPocketCmd.label = Salvesta leht Pocketisse -saveToPocketCmd.accesskey = l -saveLinkToPocketCmd.label = Salvesta link Pocketisse -saveLinkToPocketCmd.accesskey = i -pocketMenuitem.label = Vaata Pocketi nimekirja diff --git a/browser/extensions/pocket/locale/fi/pocket.properties b/browser/extensions/pocket/locale/fi/pocket.properties deleted file mode 100644 index 3cd47e891..000000000 --- a/browser/extensions/pocket/locale/fi/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Lisää tunnisteita -alreadyhaveacct = Oletko jo Pocket-palvelun käyttäjä? -continueff = Jatka Firefoxin parissa -errorgeneric = Tapahtui virhe tallennettaessa Pocket-palveluun. -learnmore = Lue lisää -loginnow = Kirjaudu sisään -maxtaglength = Tunnisteet voivat olla enintään 25 merkkiä pitkiä -mustbeconnected = Tarvitset aktiivisen Internet-yhteyden talllentaaksesi sivuja Pocket-palveluun. Tarkista Internet-yhteytesi ja yritä uudestaan. -onlylinkssaved = Vain linkkejä voidaan tallentaa -pagenotsaved = Sivua ei ole tallennettu -pageremoved = Sivu poistettiin -pagesaved = Tallennettiin Pocket-palveluun -processingremove = Poistetaan sivu… -processingtags = Lisätään tunnisteet… -removepage = Poista sivu -save = Tallenna -saving = Tallennetaan… -signupemail = Rekisteröidy sähköpostiosoitteella -signuptosave = Rekisteröidy Pocket-palveluun. Se on ilmaista. -suggestedtags = Ehdotetut tunnisteet -tagline = Tallenna artikkelit ja videot Firefoxista Pocket-palveluun katseltaviksi millä tahansa laitteella, koska tahansa. -taglinestory_one = Napsauta Pocket-painiketta tallentaaksesi artikkelin, videon tai sivun Firefoxissa. -taglinestory_two = Katsele Pocket-palvelussa millä tahansa laitteella, koska tahansa. -tagssaved = Tunnisteet lisättiin -tos = Jatkamalla hyväksyt Pocketin <a href="%1$S" target="_blank">käyttöehdot</a> ja <a href="%2$S" target="_blank">tietosuojakäytännön</a> -tryitnow = Kokeile nyt -signinfirefox = Kirjaudu sisään Firefox-tilillä -signupfirefox = Rekisteröidy Firefox-tilillä -viewlist = Näytä lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Tallenna Pocket-palveluun -saveToPocketCmd.label = Tallenna sivu Pocket-palveluun -saveToPocketCmd.accesskey = c -saveLinkToPocketCmd.label = Tallenna linkki Pocket-palveluun -saveLinkToPocketCmd.accesskey = k -pocketMenuitem.label = Näytä Pocket-palvelun lista diff --git a/browser/extensions/pocket/locale/fr/pocket.properties b/browser/extensions/pocket/locale/fr/pocket.properties deleted file mode 100644 index cb9b0ca8f..000000000 --- a/browser/extensions/pocket/locale/fr/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Ajouter des étiquettes -alreadyhaveacct = Vous utilisez déjà Pocket ? -continueff = Continuer avec Firefox -errorgeneric = Une erreur s’est produite lors de l’enregistrement dans Pocket. -learnmore = En savoir plus -loginnow = Connectez-vous -maxtaglength = Les étiquettes sont limitées à 25 caractères -mustbeconnected = Vous devez être connecté à Internet pour enregistrer des liens dans Pocket. Veuillez vérifier votre connexion puis réessayer. -onlylinkssaved = Seuls les liens peuvent être enregistrés -pagenotsaved = Page non enregistrée -pageremoved = Page supprimée -pagesaved = Page enregistrée dans Pocket -processingremove = Suppression de la page… -processingtags = Ajout des étiquettes… -removepage = Supprimer la page -save = Enregistrer -saving = Enregistrement… -signupemail = S’inscrire avec une adresse électronique -signuptosave = Inscrivez-vous à Pocket, c’est gratuit. -suggestedtags = Étiquettes suggérées -tagline = Enregistrez des articles et des vidéos depuis Firefox pour les visualiser dans Pocket sur n’importe quel appareil, à tout moment. -taglinestory_one = Cliquez sur le bouton Pocket pour enregistrer depuis Firefox n’importe quel article, vidéo ou page. -taglinestory_two = Affichez vos pages dans Pocket sur n’importe quel appareil, à tout moment. -tagssaved = Étiquettes ajoutées -tos = En continuant, vous acceptez les <a href="%1$S" target="_blank">conditions d’utilisation</a> et la <a href="%2$S" target="_blank">politique de confidentialité</a> de Pocket -tryitnow = Essayer -signinfirefox = Connexion via Firefox -signupfirefox = S’inscrire avec Firefox -viewlist = Afficher la liste - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Enregistrer dans Pocket -saveToPocketCmd.label = Enregistrer la page dans Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Enregistrer le lien dans Pocket -saveLinkToPocketCmd.accesskey = k -pocketMenuitem.label = Afficher la liste Pocket diff --git a/browser/extensions/pocket/locale/fy-NL/pocket.properties b/browser/extensions/pocket/locale/fy-NL/pocket.properties deleted file mode 100644 index 5b41c652f..000000000 --- a/browser/extensions/pocket/locale/fy-NL/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Labels tafoegje -alreadyhaveacct = Al in Pocket-brûker? -continueff = Trochgean mei Firefox -errorgeneric = Der is in flater bard by it bewarjen nei Pocket. -learnmore = Mear ynfo -loginnow = Meld jo oan -maxtaglength = Labels binne beheint ta 25 tekens -mustbeconnected = Jo moatte mei it ynternet ferbûn wêze om nei Pocket bewarje te kinnen. Kontrolearje jo ferbining en probearje it opnij. -onlylinkssaved = Allinnich keppelingen kinne bewarre wurde -pagenotsaved = Side net bewarre -pageremoved = Side fuortsmiten -pagesaved = Bewarre nei Pocket -processingremove = Side fuortsmite… -processingtags = Labels tafoegje… -removepage = Side fuortsmite -save = Bewarje -saving = Bewarje… -signupemail = Registrearje mei e-mailadres -signuptosave = Registrearje foar Pocket. It is fergees. -suggestedtags = Foarstelde labels -tagline = Bewarje artikelen en fideo’s fan Firefox út foar werjaan yn Pocket op ferskate apparaten, wannear dan ek. -taglinestory_one = Klik op de Pocket-knop om artikelen, fideo’s of siden fan Firefox út te bewarjen. -taglinestory_two = Besjoch se op ferskate apparaten, wannear dan ek. -tagssaved = Labels tafoege -tos = Troch fierder te gean, geane jo akkoard mei de <a href="%1$S" target="_blank">Tsjinstbetingsten</a> en it <a href="%2$S" target="_blank">Privacybelied</a> fan Pocket -tryitnow = No probearje -signinfirefox = Oanmelde mei Firefox -signupfirefox = Registrearje mei Firefox -viewlist = List werjaan - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Bewarje nei Pocket -saveToPocketCmd.label = Side bewarje nei Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Keppeling bewarje nei Pocket -saveLinkToPocketCmd.accesskey = e -pocketMenuitem.label = Pocket-list werjaan diff --git a/browser/extensions/pocket/locale/gu-IN/pocket.properties b/browser/extensions/pocket/locale/gu-IN/pocket.properties deleted file mode 100644 index 2261ff5b4..000000000 --- a/browser/extensions/pocket/locale/gu-IN/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = ટૅગ્સ ઉમેરો -alreadyhaveacct = પહેલેથી જ એક પોકેટ વપરાશકર્તા છો? -continueff = ફાયરફોક્સ સાથે ચાલુ રાખો -errorgeneric = પોકેટ સાચવી રાખવા માટે પ્રયાસ હતો ત્યારે એક ભૂલ હતી. -learnmore = વધુ શીખો -loginnow = પ્રવેશ કરો -maxtaglength = ટૅગ્સ 25 અક્ષરો સુધી મર્યાદિત છે -mustbeconnected = તમે પોકેટ પર સેવ કરવા માટે ઇન્ટરનેટ સાથે જોડાયેલ હોવા જ જોઈએ. કૃપા કરીને તમારા જોડાણ તપાસ કરો અને ફરીથી પ્રયત્ન કરો. -onlylinkssaved = માત્ર લિંક્સ સાચવી શકાય છે -pagenotsaved = પૃષ્ઠ સાચવેલા નથી -pageremoved = પૃષ્ઠ દૂર -pagesaved = પોકેટ પર સાચવ્યું -processingremove = પૃષ્ઠ દૂર કરી રહ્યા છીએ… -processingtags = ટૅગ્સ ઉમેરી રહ્યું છે… -removepage = પૃષ્ઠ દૂર -save = સાચવો -saving = સાચવી રહ્યું છે… -signupemail = ઇમેઇલ સાથે સાઇનઅપ -signuptosave = પોકેટ માટે સાઇન અપ કરો. તે મફત છે. -suggestedtags = સૂચવેલ ટૅગ્સ -tagline = કોઈપણ ઉપકરણ, કોઈ પણ સમય પર પોકેટ માં જોવા માટે ફાયરફોક્સ ના લેખો અને વીડિયો સાચવો. -taglinestory_one = ફાયરફોક્સ એક લેખ, વિડિઓ અથવા પાનું સેવ કરવા પોકેટ બટન પર ક્લિક કરો. -taglinestory_two = કોઈપણ ઉપકરણ, કોઈ પણ સમય પર પોકેટ માં જુઓ. -tagssaved = ટૅગ્સ ઉમેર્યું -tos = ચાલુ કરવાથી, તમે પોકેટ માટેની <a href="%1$S" target="_blank">સેવાની શરતો</a> અને <a href="%2$S" target="_blank">ગોપનીયતા નીતિ</a>સંમત થશો -tryitnow = અત્યારે પ્રયાસ કરો -signinfirefox = ફાયરફોક્સ સાથે ચાલુ રાખો -signupfirefox = ફાયરફોક્સ સાથે સાઇન અપ કરો -viewlist = યાદી જુઓ - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = પોકેટ -pocket-button.tooltiptext = પોકેટ પર સાચવો -saveToPocketCmd.label = પોકેટ પર પૃષ્ઠ સાચવો -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = પોકેટ પર લિંક સાચવો -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = જુઓ પોકેટની યાદી diff --git a/browser/extensions/pocket/locale/hr/pocket.properties b/browser/extensions/pocket/locale/hr/pocket.properties deleted file mode 100644 index 3b723499f..000000000 --- a/browser/extensions/pocket/locale/hr/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Dodaj oznake -alreadyhaveacct = Postojeći ste Pocket korisnik? -continueff = Nastavite s Firefoxom -errorgeneric = Došlo je do greške pri snimanju u Pocket. -learnmore = Saznajte više -loginnow = Prijava -maxtaglength = Oznake su ograničene na 25 znakova -mustbeconnected = Morate biti povezani na Internet da bi ste mogli snimiti u Pocket. Molimo vas da provjerite vašu vezu i pokušate ponovno. -onlylinkssaved = Mogu se spremiti samo poveznice -pagenotsaved = Stranica nije spremljena -pageremoved = Stranica uklonjena -pagesaved = Spremljeno u Pocket -processingremove = Uklanjanje stranice… -processingtags = Dodavanje oznaka… -removepage = Ukloni stranicu -save = Spremi -saving = Spremanje… -signupemail = Registracija s e-poštom -signuptosave = Registrirajte se na Pocket. Besplatno je. -suggestedtags = Predložene oznake -tagline = Spremite članke, video snimke iz Firefoxa za prikaz u Pocketu, na bilo kojem uređaju, bilo kada. -taglinestory_one = Kliknite na Pocket tipku da biste snimili bilo koji članak, video ili stranicu iz Firefoxa. -taglinestory_two = Pregledajte u Pocketu na bilo kojem uređaju, bilo kada. -tagssaved = Oznake dodane -tos = Nastavljajući, prihvaćate Pocket <a href="%1$S" target="_blank">Uvjete pružanja usluge</a> i <a href="%2$S" target="_blank">Izjavu o privatnosti</a> -tryitnow = Isprobajte odmah -signinfirefox = Prijava s Firefoxom -signupfirefox = Registracija s Firefoxom -viewlist = Prikaži popis - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Spremi u Pocket -saveToPocketCmd.label = Spremi stranicu u Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Spremi poveznicu u Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Prikaži Pocket popis diff --git a/browser/extensions/pocket/locale/hsb/pocket.properties b/browser/extensions/pocket/locale/hsb/pocket.properties deleted file mode 100644 index a5f5583e7..000000000 --- a/browser/extensions/pocket/locale/hsb/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Znački přidać -alreadyhaveacct = Sće hižo wužiwar Pocket? -continueff = Z Firefox pokročować -errorgeneric = Při składowanju do Pocket je zmylk wustupił. -learnmore = Dalše informacije -loginnow = Přizjewić -maxtaglength = Znački su na 25 znamješkow wobmjezowane -mustbeconnected = Dyrbiće z internetom zwjazany być, zo byšće do Pocket składował. Prošu přepruwujće swój zwisk a spytajće hišće raz. -onlylinkssaved = Jenož wotkazy dadźa so składować -pagenotsaved = Strona njeje so składowała -pageremoved = Strona je so wotstroniła -pagesaved = Do Pocket składowany -processingremove = Strona so wotstronja… -processingtags = Znački so přidawaja… -removepage = Stronu wotstronić -save = Składować -saving = Składuje so… -signupemail = Registrujće so z e-mejlku -signuptosave = Registrujće so za Pocket. Je darmo. -suggestedtags = Namjetowane znački -tagline = Składujće nastawki a wideja z Firefox, zo byšće sej je kóždy čas w Pocket na kóždym graće wobhladał. -taglinestory_one = Klikńće na tłóčatko Pocket, zo byšće nastawk, widejo abo stronu z Firefox składował. -taglinestory_two = Sej w Pocket na kóždym graće kóždy čas wobhladać. -tagssaved = Znački su so přidali -tos = Hdyž pokročujeće, zwoliće do <a href="%1$S" target="_blank">wužiwarskich wuměnjenjow</a> a <a href="%2$S" target="_blank">prawidłow priwatnosće</a> Pocket -tryitnow = Spytajće to nětko -signinfirefox = Z Firefox přizjewić -signupfirefox = Z Firefox registrować -viewlist = Lisćinu pokazać - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Do Pocket składować -saveToPocketCmd.label = Stronu do Pocket składować -saveToPocketCmd.accesskey = d -saveLinkToPocketCmd.label = Wotkaz do Pocket składować -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Lisćinu Pocket pokazać diff --git a/browser/extensions/pocket/locale/hu/pocket.properties b/browser/extensions/pocket/locale/hu/pocket.properties deleted file mode 100644 index 767638e82..000000000 --- a/browser/extensions/pocket/locale/hu/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Címkék hozzáadása -alreadyhaveacct = Már Pocket felhasználó? -continueff = Folytatás a Firefoxszal -errorgeneric = Hiba történt a Pocketre mentés közben. -learnmore = Tudjon meg többet -loginnow = Bejelentkezés -maxtaglength = A címkék legfeljebb 25 karakter hosszúak lehetnek -mustbeconnected = Csatlakoznia kell az internethez a Pocketre mentéshez. Ellenőrizze a kapcsolatot, és próbálja újra. -onlylinkssaved = Csak hivatkozások menthetők -pagenotsaved = Az oldal nem lett mentve -pageremoved = Oldal eltávolítva -pagesaved = Mentve a Pocketbe -processingremove = Oldal eltávolítása… -processingtags = Címkék hozzáadása… -removepage = Oldal eltávolítása -save = Mentés -saving = Mentés… -signupemail = Regisztráció e-maillel -signuptosave = Regisztráljon ingyenesen a Pocketre. -suggestedtags = Javasolt címkék -tagline = Mentsen cikkeket és videókat a Firefoxból a Pocketen való megtekintéshez bármely eszközön, bármikor. -taglinestory_one = Kattintson a Pocket gombra bármely cikk, videó vagy oldal mentéséhez a Firefoxból. -taglinestory_two = Nézze meg a Pocketen bármely eszközön, bármikor. -tagssaved = Címkék hozzáadva -tos = A folytatással elfogadja a Pocket <a href="%1$S" target="_blank">Szolgáltatási feltételeit</a> és az <a href="%2$S" target="_blank">Adatvédelmi nyilatkozatot</a> -tryitnow = Próbálja ki most -signinfirefox = Bejelentkezés a Firefoxszal -signupfirefox = Regisztráció a Firefoxszal -viewlist = Lista megjelenítése - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Mentés a Pocketbe -saveToPocketCmd.label = Oldal mentése a Pocketbe -saveToPocketCmd.accesskey = c -saveLinkToPocketCmd.label = Hivatkozás mentése a Pocketbe -saveLinkToPocketCmd.accesskey = H -pocketMenuitem.label = Pocket lista megjelenítése diff --git a/browser/extensions/pocket/locale/it/pocket.properties b/browser/extensions/pocket/locale/it/pocket.properties deleted file mode 100644 index 2105011eb..000000000 --- a/browser/extensions/pocket/locale/it/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Aggiungi etichette -alreadyhaveacct = Hai già un account registrato su Pocket? -continueff = Prosegui con Firefox -errorgeneric = Si è verificato un errore durante il salvataggio in Pocket. -learnmore = Ulteriori informazioni -loginnow = Accedi -maxtaglength = La lunghezza massima per le etichette è di 25 caratteri -mustbeconnected = È necessario essere connessi a Internet per salvare in Pocket. Verificare la connessione e riprovare. -onlylinkssaved = È possibile salvare solo link -pagenotsaved = Pagina non salvata -pageremoved = Pagina rimossa -pagesaved = Salvata in Pocket -processingremove = Rimozione pagina… -processingtags = Salvataggio etichette… -removepage = Rimuovi pagina -save = Salva -saving = Salvataggio… -signupemail = Accedi con email -signuptosave = Registrati su Pocket. È gratis. -suggestedtags = Etichette suggerite -tagline = Salva articoli e video da Firefox per visualizzarli in Pocket da qualunque dispositivo e in qualunque momento. -taglinestory_one = Fai clic sul pulsante Pocket per salvare qualunque articolo, video o pagina da Firefox. -taglinestory_two = Visualizza in Pocket da qualunque dispositivo e in qualunque momento. -tagssaved = Aggiunte etichette -tos = Proseguendo si accettano i <a href="%1$S" target="_blank">termini di servizio</a> e l’<a href="%2$S" target="_blank">informativa sulla privacy</a> -tryitnow = Provalo subito -signinfirefox = Accedi con Firefox -signupfirefox = Registrati con Firefox -viewlist = Visualizza elenco - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Salva in Pocket -saveToPocketCmd.label = Salva pagina in Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Salva link in Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Visualizza elenco Pocket diff --git a/browser/extensions/pocket/locale/ja/pocket.properties b/browser/extensions/pocket/locale/ja/pocket.properties deleted file mode 100644 index 1aef6bba1..000000000 --- a/browser/extensions/pocket/locale/ja/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = タグを追加 -alreadyhaveacct = Pocket に登録済みですか? -continueff = Firefox で続行 -errorgeneric = Pocket への保存中にエラーがありました。 -learnmore = 詳細 -loginnow = ログイン -maxtaglength = タグは 25 文字までです -mustbeconnected = Pocket に保存するには、インターネット接続が必要です。接続状況を確認してから、試してみたください。 -onlylinkssaved = リンクのみ保存しました -pagenotsaved = ページを保存しませんでした -pageremoved = ページを削除しました -pagesaved = Pocket に保存しました -processingremove = ページを削除しています... -processingtags = タグを追加しています... -removepage = ページを削除 -save = 保存 -saving = 保存しています... -signupemail = メールアドレスで新規登録 -signuptosave = Pocket に新規登録します。無料です。 -suggestedtags = 提案タグ -tagline = Firefox で記事や動画を保存すると、いつでもどこでも Pocket で閲覧できます。 -taglinestory_one = Firefox で Pocket ボタンをクリックすると、様々な記事や動画やページを保存できます。 -taglinestory_two = Pocket でいつでもどこでも閲覧できます。 -tagssaved = タグを追加しました -tos = 続けることで、Pocket の <a href="%1$S" target="_blank">利用規約</a> と <a href="%2$S" target="_blank">プライバシーポリシー</a> に同意したことになります -tryitnow = 今すぐ試す -signinfirefox = Firefox でログイン -signupfirefox = Firefox で新規登録 -viewlist = リストを表示 - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Pocket に保存 -saveToPocketCmd.label = ページを Pocket に保存 -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = リンクを Pocket に保存 -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Pocket のリストを表示 diff --git a/browser/extensions/pocket/locale/jar.mn b/browser/extensions/pocket/locale/jar.mn deleted file mode 100644 index f29ca7367..000000000 --- a/browser/extensions/pocket/locale/jar.mn +++ /dev/null @@ -1,33 +0,0 @@ -#filter substitution -# 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/. - -# These are used for the big if statement, as the preprocessor can't handle -# dashes. -#define bn_BD bn-BD -#define en_GB en-GB -#define en_US en-US -#define es_AR es-AR -#define es_CL es-CL -#define es_ES es-ES -#define es_MX es-MX -#define fy_NL fy-NL -#define gu_IN gu-IN -#define nn_NO nn-NO -#define pt_BR pt-BR -#define pt_PT pt-PT -#define sv_SE sv-SE -#define zh_CN zh-CN -#define zh_TW zh-TW - -[features/firefox@getpocket.com] @AB_CD@.jar: -% locale pocket @AB_CD@ %locale/@AB_CD@/ - # For locales we support, include the file from the locale's directory in the - # source tree. - # For other locales (and en-US) fallback to the en-US directory. -#if AB_CD == ast || AB_CD == az || AB_CD == bg || AB_CD == bn_BD || AB_CD == cs || AB_CD == da || AB_CD == de || AB_CD == dsb || AB_CD == en_GB || AB_CD == en_US || AB_CD == es_AR || AB_CD == es_CL || AB_CD == es_ES || AB_CD == es_MX || AB_CD == et || AB_CD == fi || AB_CD == fr || AB_CD == fy_NL || AB_CD == gu_IN || AB_CD == hr || AB_CD == hsb || AB_CD == hu || AB_CD == it || AB_CD == ja || AB_CD == ka || AB_CD == kab || AB_CD == lt || AB_CD == lv || AB_CD == mr || AB_CD == ms || AB_CD == nl || AB_CD == nn_NO || AB_CD == or || AB_CD == pl || AB_CD == pt_BR || AB_CD == pt_PT || AB_CD == rm || AB_CD == ro || AB_CD == ru || AB_CD == sk || AB_CD == sl || AB_CD == sq || AB_CD == sr || AB_CD == sv_SE || AB_CD == te || AB_CD == th || AB_CD == tr || AB_CD == uk || AB_CD == zh_CN || AB_CD == zh_TW - locale/@AB_CD@/ (@AB_CD@/*) -#else - locale/@AB_CD@/ (en-US/*) -#endif diff --git a/browser/extensions/pocket/locale/ka/pocket.properties b/browser/extensions/pocket/locale/ka/pocket.properties deleted file mode 100644 index 266ded044..000000000 --- a/browser/extensions/pocket/locale/ka/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = იარლიყების დამატება -alreadyhaveacct = უკვე იყენებთ Pocket-ს? -continueff = Firefox-ით გაგრძელება -errorgeneric = Pocket-ში შენახვისას დაფიქსირდა შეცდომა. -learnmore = დაწვრილებით -loginnow = შესვლა -maxtaglength = იარლიყები შეზღუდულია 25 ასომდე -mustbeconnected = Pocket-ში შესანახად საჭიროა ინტერნეთთან კავშირი. გთხოვთ შეამოწმეთ თქვენი კავშირი და ხელახლა ცადეთ. -onlylinkssaved = შესაძლებელია მხოლოდ ბმულების შენახვა -pagenotsaved = გვერდი არ შეინახა -pageremoved = გვერდი წაიშალა -pagesaved = შეინახა Pocket-ში -processingremove = იშლება გვერდი… -processingtags = ემატება იარლიყები… -removepage = გვერდის წაშლა -save = შენახვა -saving = ინახება… -signupemail = რეგისტრაცია ელ-ფოსტით -signuptosave = დარეგისტრირდით Pocket-ზე. ეს უფასოა. -suggestedtags = შემოთავაზებული იარლიყები -tagline = შეინახეთ სტატიები და ვიდეობეი Firefox-იდან მათ Pocket-ში სანახავად ნებისმიერ მოწყობილობაზე, ნებისმიერ დროს. -taglinestory_one = Firefox-იდან ნებისმიერი სტატიის, ვიდეოს ან გვერდის შესანახად დააწკაპეთ Pocket-ის ღილაკს. -taglinestory_two = დაათვალიერეთ Pocket-ში ნებისმიერ მოწყობილობაზე, ნებისმიერ დროს. -tagssaved = იარლიყები დაემატა -tos = გაგრძელების შემთხვევაში თქვენ ეთანხმებით Pocket-ის <a href="%1$S" target="_blank">მომსახურების პირობებს</a> და <a href="%2$S" target="_blank">პრივატულობის პოლიტიკას</a> -tryitnow = სცადეთ ახლავე -signinfirefox = შესვლა Firefox-ით -signupfirefox = რეგისრაცია Firefox-ით -viewlist = სიის ნახვა - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Pocket-ში შენახვა -saveToPocketCmd.label = გვერდის შენახვა Pocket-ში -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = ბმულის შენახვა Pocket-ში -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Pocket სიის ნახვა diff --git a/browser/extensions/pocket/locale/kab/pocket.properties b/browser/extensions/pocket/locale/kab/pocket.properties deleted file mode 100644 index 3f4cc642a..000000000 --- a/browser/extensions/pocket/locale/kab/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Rnu tibzimin -alreadyhaveacct = Aseqdac yakan n Pocket? -continueff = Kemmel s Firefox -errorgeneric = Teḍra-d tuccḍa deg aɛraḍ n usekles ɣer Pocket. -learnmore = Issin ugar -loginnow = Kcem -maxtaglength = Tibzimin ɣur-sent talast n 25 n isekkilen -mustbeconnected = Yessefk ad tiliḍ teqqneḍ ɣer Internet akken ad tizmireḍ ad teskelseḍ ɣer Pocket. Ma ulac aɣilif, senqed tuqqna yinek sakin ɛreḍ tikelt nniḍen. -onlylinkssaved = Al iseɣwan i yezmren ad ttwakelsen -pagenotsaved = Asebter ur yettwakles ara -pageremoved = Asebter yettwakkes -pagesaved = Yettwakles ɣer Pocket -processingremove = Tukksa n isebtar… -processingtags = Timerna n tebzimin… -removepage = Kkes asebter -save = Sekles -saving = Asekles… -signupemail = Jerred s yimayl -signuptosave = Jerred ɣer Pocket. Baṭel. -suggestedtags = Tibzimin yettwasumren -tagline = Sekles imagraden akked tvidyutin si Firefox akken ad twaliḍ di Pocket ɣef yal ibenk, melmi tebɣiḍ. -taglinestory_one = Sit ɣef tqeffalt Pocket akken ad teskelseḍ yal amagrad, tavidyut neɣ asebter si Firefox. -taglinestory_two = Sken di Pocket ɣef yal ibenk yellan, melmi tebɣiḍ. -tagssaved = Tibzimin yettwarnan -tos = Ma tkemleḍ, ad tqebleḍ <a href="%1$S" target="_blank">tiwtilin n useqdec</a> akked <a href="%2$S" target="_blank">tsertit tabaḍnit</a> n Pocket -tryitnow = Ɛreḍ-it tura -signinfirefox = Kcem s Firefox -signupfirefox = Jerred s Firefox -viewlist = Sken tabdart - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Sekles ɣer Pocket -saveToPocketCmd.label = Sekles asebter ɣer Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Sekles aseɣwen ɣer Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Sken tabdart n Pocket diff --git a/browser/extensions/pocket/locale/lt/pocket.properties b/browser/extensions/pocket/locale/lt/pocket.properties deleted file mode 100644 index f3e8df077..000000000 --- a/browser/extensions/pocket/locale/lt/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Pridėkite gairių -alreadyhaveacct = Jau naudojatės „Pocket“? -continueff = Tęsti su „Firefox“ -errorgeneric = Bandant išsaugoti į „Pocket“ įvyko klaida. -learnmore = Sužinokite daugiau -loginnow = Prisijungti -maxtaglength = Gaires gali sudaryti iki 25 simbolių -mustbeconnected = Norėdami saugoti į „Pocket“, turite būti prisijungę prie interneto. Prašome patikrinti savo ryšį ir bandyti vėl. -onlylinkssaved = Išsaugoti galima tik nuorodas -pagenotsaved = Tinklalapis neišsaugotas -pageremoved = Tinklalapis pašalintas -pagesaved = Išsaugota į „Pocket“ -processingremove = Šalinamas tinklalapis… -processingtags = Pridedamos gairės… -removepage = Pašalinti tinklalapį -save = Išsaugoti -saving = Išsaugoma… -signupemail = Prisijungti su el. paštu -signuptosave = Pradėkite naudotis „Pocket“. Tai nemokama. -suggestedtags = Siūlomos gairės -tagline = Išsaugokite straipsnius bei vaizdo įrašus iš „Firefox“ norėdami juos peržiūrėti bet kokiame įrenginyje su „Pocket“, bet kuriuo metu. -taglinestory_one = Spustelėkite „Pocket“ mygtuką norėdami išsaugoti bet kokį straipsnį, vaizdo įrašą ar tinklalapį iš „Firefox“. -taglinestory_two = Peržiūrėkite bet kokiame įrenginyje su „Pocket“, bet kuriuo metu. -tagssaved = Gairės pridėtos -tos = Tęsdami sutinkate su „Pocket“ <a href="%1$S" target="_blank">paslaugos teikimo sąlygomis</a> bei <a href="%2$S" target="_blank">privatumo nuostatais</a> -tryitnow = Išbandykite dabar -signinfirefox = Prisijungti su „Firefox“ -signupfirefox = Prisijungti su „Firefox“ -viewlist = Peržiūrėti sąrašą - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Išsaugoti į „Pocket“ -saveToPocketCmd.label = Išsaugoti tinklalapį į „Pocket“ -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Išsaugoti saitą į „Pocket“ -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Peržiūrėti „Pocket“ sąrašą diff --git a/browser/extensions/pocket/locale/lv/pocket.properties b/browser/extensions/pocket/locale/lv/pocket.properties deleted file mode 100644 index 40e3bb367..000000000 --- a/browser/extensions/pocket/locale/lv/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Pievienot birkas -alreadyhaveacct = Jau lietojat Pocket? -continueff = Turpināt ar Firefox -errorgeneric = Kļūda saglabājot Pocket. -learnmore = Uzzināt vairāk -loginnow = Pieslēgties -maxtaglength = Birkas nevar būt garākas par 25 simboliem -mustbeconnected = Lai saglabātu Pocket, jābūt savienojumam ar internetu. Lūdzu pārbaudiet savienojumu un mēģiniet vēlreiz. -onlylinkssaved = Saglabāt var tikai saites -pagenotsaved = Lapa nav saglabāta -pageremoved = Lapa ir aizvākta -pagesaved = Saglabāt Pocket -processingremove = Aizvāc lapu… -processingtags = Pievieno birkas… -removepage = Izņemt lapu -save = Saglabāt -saving = Saglabā… -signupemail = Pierakstīties ar epastu -signuptosave = Pierakstīties Pocket. Tas ir bez maksas. -suggestedtags = Ieteiktās birkas -tagline = Saglabājiet Firefox rakstu vai video, lai skatītos to ar Pocket jebkurā ierīcē un jebkurā laikā. -taglinestory_one = Klikšķiniet uz Pocket pogas, lai saglabātu Firefox rakstus, video vai lapas. -taglinestory_two = Skatiet ar Pocket jebkurā ierīcē un jebkurā laikā. -tagssaved = Birkas pievienotas -tos = Turpinot, tu piekrīti Pocket <a href="%1$S" target="_blank">Noteikumiem</a> un <a href="%2$S" target="_blank">Privātuma politikai</a> -tryitnow = Izmēģini tagad -signinfirefox = Pieslēgties ar Firefox -signupfirefox = Pierakstīties ar Firefox -viewlist = Skatījumu saraksts - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Saglabāt Pocket -saveToPocketCmd.label = Saglabāt lapu Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Saglabāt saiti Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Aplūkot Pocket sarakstu diff --git a/browser/extensions/pocket/locale/mr/pocket.properties b/browser/extensions/pocket/locale/mr/pocket.properties deleted file mode 100644 index af330ec1e..000000000 --- a/browser/extensions/pocket/locale/mr/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = टॅग जोडा -alreadyhaveacct = आधीपासून Pocket वापरताय? -continueff = Firefox सोबत पुढे चला -errorgeneric = Pocket मध्ये जतन करताना त्रुटी आली. -learnmore = अधिक जाणून घ्या -loginnow = लॉग इन -maxtaglength = टॅग्ज साठी 25 वर्णांची मर्यादा आहे -mustbeconnected = Pocket मध्ये साठविण्यासाठी आपले इंटरनेट चालू असणे आवश्यक आहे. कृपया आपली जोडणी तपासा आणि पुन्हा प्रयत्न करा. -onlylinkssaved = फक्त दुवे जतन केले जाऊ शकतात -pagenotsaved = पृष्ठ जतन झाले नाही -pageremoved = पृष्ठ काढले गेले -pagesaved = Pocket मध्ये जतन झाले -processingremove = पृष्ठ काढून टाकत आहे... -processingtags = टॅग्ज जोडत आहे… -removepage = पृष्ठ काढून टाका -save = जतन करा -saving = जतन करत आहे... -signupemail = ईमेलसह साईन अप करा -signuptosave = Pocket साठी साईन अप करा. हे मोफत आहे. -suggestedtags = सूचविलेले टॅग्स -tagline = Firefox मधील नोंदी आणि व्हिडीओ कुठल्याही साधनावर केंव्हाही Pocket मध्ये पाहण्यासाठी साठवा. -taglinestory_one = Firefox वरील कोणताही लेख, व्हिडिओ किंवा पृष्ठ जतन करण्यासाठी Pocket बटणावर क्लिक करा. -taglinestory_two = कधीही कुठल्याही साधनावर Pocket मध्ये पाहा. -tagssaved = टॅग्स जोडले -tos = सुरु ठेवुन, आपण Pocketच्या <a href="%1$S" target="_blank">सेवेच्या अटी</a> आणि <a href="%2$S" target="_blank">गोपनीयता धोरणांशी</a> सहमत आहात -tryitnow = आत्ताच वापरुन पाहा -signinfirefox = Firefox सह साइन इन करा -signupfirefox = Firefox सह साईन अप करा -viewlist = यादी पहा - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Pocket मध्ये जतन करा -saveToPocketCmd.label = पृष्ठ Pocket मध्ये जतन करा -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = दुवा Pocket मध्ये संकलित करा -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = पॉकेट सूची पहा diff --git a/browser/extensions/pocket/locale/ms/pocket.properties b/browser/extensions/pocket/locale/ms/pocket.properties deleted file mode 100644 index 67a935be8..000000000 --- a/browser/extensions/pocket/locale/ms/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Tambah Tag -alreadyhaveacct = Sudah menjadi pengguna Poket? -continueff = Teruskan dengan Firefox -errorgeneric = Ada ralat semasa cuba menyimpan ke Pocket. -learnmore = Ketahui Selanjutnya -loginnow = Log masuk -maxtaglength = Tag dihadkan hanya 25 aksara -mustbeconnected = Anda mesti ada sambungan Internet untuk menyimpan ke Pocket. Sila periksa sambungan anda dan cuba lagi. -onlylinkssaved = Hanya pautan boleh disimpan -pagenotsaved = Halaman Tidak Disimpan -pageremoved = Halaman Dialih keluar -pagesaved = Disimpan ke Pocket -processingremove = Sedang mengalih keluar Halaman… -processingtags = Sedang menambah tag… -removepage = Alih keluar Halaman -save = Simpan -saving = Sedang menyimpan… -signupemail = Daftar dengan e-mel -signuptosave = Daftar masuk ke Pocket. Percuma. -suggestedtags = Tag Disyorkan -tagline = Simpan artikel dan video dari Firefox untuk dilihat dalam Pocket pada apa jua peranti pada bila-bila masa. -taglinestory_one = Klik butang Pocket untuk menyimpan apa jua artikel, video atau halaman daripada Firefox. -taglinestory_two = Papar dalam Pocket dalam mana-mana peranti, bila-bila masa saja. -tagssaved = Tag Ditambah -tos = Dengan meneruskan, anda setuju dengan <a href="%1$S" target="_blank">Terma Perkhidmatan</a> Pocket dan <a href="%2$S" target="_blank">Polisi Privasi</a> -tryitnow = Cubanya Sekarang -signinfirefox = Daftar masuk Firefox -signupfirefox = Daftar dengan Firefox -viewlist = Senarai Paparan - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Simpan ke Pocket -saveToPocketCmd.label = Simpan Halaman ke Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Simpan Pautan ke Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Papar Senarai Pocket diff --git a/browser/extensions/pocket/locale/nl/pocket.properties b/browser/extensions/pocket/locale/nl/pocket.properties deleted file mode 100644 index 3abe14491..000000000 --- a/browser/extensions/pocket/locale/nl/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Labels toevoegen -alreadyhaveacct = Al een Pocket-gebruiker? -continueff = Doorgaan met Firefox -errorgeneric = Er is een fout opgetreden bij het opslaan naar Pocket. -learnmore = Meer info -loginnow = Meld u aan -maxtaglength = Labels zijn beperkt tot 25 tekens -mustbeconnected = U moet met het internet zijn verbonden om naar Pocket te kunnen opslaan. Controleer uw verbinding en probeer het opnieuw. -onlylinkssaved = Alleen koppelingen kunnen worden opgeslagen -pagenotsaved = Pagina niet opgeslagen -pageremoved = Pagina verwijderd -pagesaved = Opgeslagen naar Pocket -processingremove = Pagina verwijderen… -processingtags = Labels toevoegen… -removepage = Pagina verwijderen -save = Opslaan -saving = Opslaan… -signupemail = Registreren met e-mailadres -signuptosave = Registreer voor Pocket. Het is gratis. -suggestedtags = Voorgestelde labels -tagline = Sla artikelen en video’s vanuit Firefox op voor weergeven in Pocket op diverse apparaten, wanneer dan ook. -taglinestory_one = Klik op de Pocket-knop om artikelen, video’s of pagina’s vanuit Firefox op te slaan. -taglinestory_two = Bekijk ze op diverse apparaten, wanneer dan ook. -tagssaved = Labels toegevoegd -tos = Door verder te gaan, gaat u akkoord met de <a href="%1$S" target="_blank">Servicevoorwaarden</a> en het <a href="%2$S" target="_blank">Privacybeleid</a> van Pocket -tryitnow = Nu proberen -signinfirefox = Aanmelden met Firefox -signupfirefox = Registreren met Firefox -viewlist = Lijst weergeven - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Opslaan naar Pocket -saveToPocketCmd.label = Pagina opslaan naar Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Koppeling opslaan naar Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Pocket-lijst weergeven diff --git a/browser/extensions/pocket/locale/nn-NO/pocket.properties b/browser/extensions/pocket/locale/nn-NO/pocket.properties deleted file mode 100644 index 3f3dc971e..000000000 --- a/browser/extensions/pocket/locale/nn-NO/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Legg til merkelapp-stikkord -alreadyhaveacct = Allereie ein Pocket-brukar? -continueff = Hald fram med Firefox -errorgeneric = Eit problem oppstod ved lagring til Pocket. -learnmore = Les meir -loginnow = Logg inn -maxtaglength = Merkelapp-stikkord er avgrensa til 25 teikn -mustbeconnected = Du må vera kopla til nettet for å lagra til Pocket. Kontroller tilkoplinga og prøv igjen. -onlylinkssaved = Berre lenker kan lagrast -pagenotsaved = Sida ikkje lagra -pageremoved = Sida fjerna -pagesaved = Lagrar til Pocket -processingremove = Fjernar sida … -processingtags = Legg til merkelapp-stikkord… -removepage = Fjern sida -save = Lagra -saving = Lagrar … -signupemail = Logg inn med e-postadresse -signuptosave = Registrer deg på Pocket. Det er gratis. -suggestedtags = Føreslåtte merkelapp-stikkord -tagline = Lagra artiklar og videoar frå Firefox for å visa dei i Pocket på kva som helst eining, når som helst. -taglinestory_one = Trykk på Pocket-knappen for å lagra kva som helst artikkel, video eller side frå Firefox. -taglinestory_two = Vis i Pocket, på kva som helst eining, når som helst. -tagssaved = Merkelapp-stikkord lagt til -tos = Ved å fortsetta godtek du Pocket sine <a href="%1$S" target="_blank">tenestevilkår</a> og <a href="%2$S" target="_blank">personvernpraksis</a> -tryitnow = Prøv no -signinfirefox = Logg inn med Firefox -signupfirefox = Registrer deg med Firefox -viewlist = Vis liste - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Lagra til Pocket -saveToPocketCmd.label = Lagra sida i Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Lagra lenke til Pocket -saveLinkToPocketCmd.accesskey = l -pocketMenuitem.label = Vis Pocket-liste diff --git a/browser/extensions/pocket/locale/or/pocket.properties b/browser/extensions/pocket/locale/or/pocket.properties deleted file mode 100644 index d2616e484..000000000 --- a/browser/extensions/pocket/locale/or/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = ଟ୍ୟାଗ ଯୋଡ଼ନ୍ତୁ -alreadyhaveacct = ଆଗରୁ Pocket ବ୍ୟବହାର କରୁଛନ୍ତି? -continueff = Firefox ଦେଇ ଆଗକୁ ଯିବେ -errorgeneric = Pocketରେ ସାଇତିବା ବେଳେ ଅସୁବିଧାଟିଏ ହେଲା । -learnmore = ଅଧିକ ଶିଖନ୍ତୁ -loginnow = ଲଗ ଇନ -maxtaglength = ଟ୍ୟାଗ 25 ଟି ଅକ୍ଷରରେ ସୀମିତ -mustbeconnected = Pocketରେ ସାଇତିବା ପାଇଁ ଆପଣ ଇଣ୍ଟରନେଟ ସହ ସଂଯୁକ୍ତ ହୋଇଥିବା ଲୋଡ଼ା । ଦୟାକରି ନିଜ ସଂଯୋଗ ପରଖି ଆଉଥରେ ଚେଷ୍ଟାକରନ୍ତୁ । -onlylinkssaved = କେବଳ ଲିଙ୍କ ସାଇତାଯାଇପାରିବ -pagenotsaved = ପୃଷ୍ଠା ସାଇତା ଯାଇନାହିଁ -pageremoved = ପୃଷ୍ଠାଟି ହଟାଗଲା -pagesaved = Pocketରେ ସାଇତାଗଲା -processingremove = ପୃଷ୍ଠା ହଟାଯାଉଛି… -processingtags = ଟ୍ୟାଗ ଯୋଡ଼ାଯାଉଛି… -removepage = ପୃଷ୍ଠା ହଟାନ୍ତୁ -save = ସାଇତିବେ -saving = ସାଇତୁଛି… -signupemail = ଇମେଲରେ ସାଇନ ଅପ -signuptosave = Pocket ପାଇଁ ସାଇନ ଅପ । ଏହା ମାଗଣା । -suggestedtags = ପ୍ରସ୍ତାବିତ ଟ୍ୟାଗ -tagline = ଯେତେବେଳେ ଲୋଡ଼ା କୌଣସି ଏକ ଡିଭାଇସରୁ Pocketରେ ଦେଖିବା ପାଇଁ Firefoxରୁ ପ୍ରସଙ୍ଗ ଓ ଭିଡ଼ିଓ ସାଇତିପାରିବେ । -taglinestory_one = କୌଣସି ପ୍ରସଙ୍ଗ, ଭିଡ଼ିଓ ବା ପୃଷ୍ଠା ସାଇତିବା ପାଇଁ Pocket Button ଟିପନ୍ତୁ । -taglinestory_two = ଯେତେବେଳେ ଲୋଡ଼ା ସବୁ ଡିଭାଇସରୁ Pocketରେ ଦେଖନ୍ତୁ । -tagssaved = ଟ୍ୟାଗ ଯୋଡ଼ାଗଲା -tos = ଆଗକୁ ବଢ଼ିବା ଯୋଗୁ ଆପଣ Pocketର <a href="%1$S" target="_blank">ନୀତି ନିୟମ</a> ଓ <a href="%2$S" target="_blank">ଗୋପନୀୟତା ନୀତିବଳୀ</a> ମାନୁଛନ୍ତି ବୋଲି ଜାଣିରଖିବେ -tryitnow = ଏବେ ଏହା ଚେଷ୍ଟାକରନ୍ତୁ -signinfirefox = Firefoxରେ ସାଇନ ଇନ କରନ୍ତୁ -signupfirefox = Firefoxରେ ସାଇନ ଅପ କରନ୍ତୁ -viewlist = ତାଲିକା ଦେଖନ୍ତୁ - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Pocketରେ ସାଇତନ୍ତୁ -saveToPocketCmd.label = Pocketରେ ପୃଷ୍ଠା ସାଇତନ୍ତୁ -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Pocketରେ ଲିଙ୍କ ସାଇତନ୍ତୁ -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Pocket ତାଲିକା ଦେଖନ୍ତୁ diff --git a/browser/extensions/pocket/locale/pl/pocket.properties b/browser/extensions/pocket/locale/pl/pocket.properties deleted file mode 100644 index 07b5866f1..000000000 --- a/browser/extensions/pocket/locale/pl/pocket.properties +++ /dev/null @@ -1,48 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -taglinestory_one=Kliknij przycisk Pocket, aby wysłać dowolny artykuł, film lub stronę z Firefoksa. -taglinestory_two=Czytaj z Pocket o dowolnej porze na dowolnym urządzeniu. -learnmore=Więcej informacji - -signuptosave=Utwórz konto w Pocket. Jest darmowe. -signupfirefox=Utwórz konto z Firefoksem -signupemail=Utwórz konto z adresem e-mail -alreadyhaveacct=Masz już konto Pocket? -loginnow=Zaloguj się - -tos=Kontynuując, wyrażasz zgodę na <a href="%1$S" target="_blank">warunki korzystania z usługi</a> i <a href="%2$S" target="_blank">politykę prywatności</a> -tryitnow=Wypróbuj teraz - -continueff=Kontynuuj z kontem Firefoksa -signinfirefox=Zaloguj się z Firefoksem -viewlist=Otwórz w Pocket - -removepage=Usuń stronę -processingremove=Usuwanie strony… -pageremoved=Usunięto stronę - -save=Wyślij -saving=Wysyłanie… -pagesaved=Wysłano do Pocket - -addtags=Etykiety -processingtags=Wysyłanie etykiet… -tagssaved=Wysłano etykiety -maxtaglength=Etykiety są ograniczone do 25 znaków -suggestedtags=Sugerowane etykiety -tagline=Wysyłaj artykuły i filmy z Firefoksa do Pocket, aby wyświetlić je o dowolnej porze na dowolnym urządzeniu. - -errorgeneric=Wystąpił błąd podczas wysyłania do Pocket. -mustbeconnected=Połączenie z Internetem jest konieczne do przesyłania do Pocket. Proszę sprawdzić połączenie i spróbować ponownie. -onlylinkssaved=Tylko odnośniki mogą być przesyłane -pagenotsaved=Nie przesłano strony - -pocket-button.label=Pocket -pocket-button.tooltiptext=Wyślij do Pocket -saveToPocketCmd.label=Wyślij stronę do Pocket -saveToPocketCmd.accesskey=s -saveLinkToPocketCmd.label=Wyślij odnośnik do Pocket -saveLinkToPocketCmd.accesskey=o -pocketMenuitem.label=Wysłane do Pocket diff --git a/browser/extensions/pocket/locale/pt-BR/pocket.properties b/browser/extensions/pocket/locale/pt-BR/pocket.properties deleted file mode 100644 index a637aea29..000000000 --- a/browser/extensions/pocket/locale/pt-BR/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Adicionar etiquetas -alreadyhaveacct = Já é um usuário do Pocket? -continueff = Continuar com o Firefox -errorgeneric = Houve um erro ao tentar salvar no Pocket. -learnmore = Saber mais -loginnow = Entrar -maxtaglength = As etiquetas estão limitadas a 25 caracteres -mustbeconnected = Você deve estar conectado à Internet para salvar no Pocket. Verifique a sua conexão e tente novamente. -onlylinkssaved = Somente links podem ser salvos -pagenotsaved = Página não salva -pageremoved = Página removida -pagesaved = Salva no Pocket -processingremove = Removendo página… -processingtags = Adicionando etiquetas… -removepage = Remover página -save = Salvar -saving = Salvando… -signupemail = Registrar com e-mail -signuptosave = Registre-se no Pocket. É gratuito. -suggestedtags = Etiquetas sugeridas -tagline = Salve os artigos e vídeos do Firefox no Pocket para vê-los mais tarde e em qualquer local. -taglinestory_one = Clique no botão Pocket para salvar um artigo, vídeo ou página do Firefox. -taglinestory_two = Ver no Pocket em qualquer dispositivo, a qualquer hora. -tagssaved = Etiquetas adicionadas -tos = Continuando, você concorda com os <a href="%1$S" target="_blank">Termos de serviço</a> e <a href="%2$S" target="_blank">Política de privacidade</a> do Pocket -tryitnow = Experimente-o agora -signinfirefox = Entrar com o Firefox -signupfirefox = Cadastre-se com o Firefox -viewlist = Ver lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Salvar no Pocket -saveToPocketCmd.label = Salvar página no Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Salvar link no Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Ver lista do Pocket diff --git a/browser/extensions/pocket/locale/pt-PT/pocket.properties b/browser/extensions/pocket/locale/pt-PT/pocket.properties deleted file mode 100644 index 90eafe77f..000000000 --- a/browser/extensions/pocket/locale/pt-PT/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Adicionar etiquetas -alreadyhaveacct = Já é um utilizador do Pocket? -continueff = Continuar com o Firefox -errorgeneric = Ocorreu um erro ao tentar guardar no Pocket. -learnmore = Saber mais -loginnow = Iniciar sessão -maxtaglength = As etiquetas estão limitadas a 25 caracteres -mustbeconnected = É necessária uma ligação à Internet para poder guardar no Pocket. Por favor, verifique a sua ligação à Internet e tente novamente. -onlylinkssaved = Só podem ser guardadas ligações -pagenotsaved = Página não guardada -pageremoved = Página removida -pagesaved = Guardado no Pocket -processingremove = A remover página… -processingtags = A adicionar etiquetas… -removepage = Remover página -save = Guardar -saving = A guardar… -signupemail = Registar com email -signuptosave = Registe-se no Pocket. É gratuito. -suggestedtags = Etiquetas sugeridas -tagline = Guardar artigos e vídeos do Firefox para os ver no Pocket em qualquer dispositivo, em qualquer altura. -taglinestory_one = Clique no botão Pocket para guardar qualquer artigo, vídeo ou página a partir Firefox. -taglinestory_two = Ver no Pocket em qualquer dispositivo, a qualquer altura. -tagssaved = Etiquetas adicionadas -tos = Ao continuar, concorda com os <a href="%1$S" target="_blank">termos do serviço</a> e <a href="%2$S" target="_blank">política de privacidade</a> do Pocket -tryitnow = Experimente-o agora -signinfirefox = Iniciar sessão com Firefox -signupfirefox = Registar com Firefox -viewlist = Ver lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Guardar no Pocket -saveToPocketCmd.label = Guardar página no Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Guardar ligação no Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Ver lista do Pocket diff --git a/browser/extensions/pocket/locale/rm/pocket.properties b/browser/extensions/pocket/locale/rm/pocket.properties deleted file mode 100644 index 803277b21..000000000 --- a/browser/extensions/pocket/locale/rm/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Agiuntar tags -alreadyhaveacct = Es ti gia in utilisader da Pocket? -continueff = Cuntinuar cun Firefox -errorgeneric = Ina errur è succedida durant empruvar da memorisar en Pocket. -learnmore = Ulteriuras infurmaziuns -loginnow = S'annunziar -maxtaglength = Tags èn limitads a 25 caracters -mustbeconnected = Ti stos esser connectà cun l'internet per pudair memorisar en Pocket. Controllescha p.pl. tia connexiun ed emprova anc ina giada. -onlylinkssaved = Mo colliaziuns pon vegnir memorisadas -pagenotsaved = Betg memorisà la pagina -pageremoved = Allontanà la pagina -pagesaved = Memorisà en Pocket -processingremove = Allontanar la pagina… -processingtags = Agiuntar tags… -removepage = Allontanar la pagina -save = Memorisar -saving = Memorisar… -signupemail = Sa registrar cun l'adressa dad e-mail -signuptosave = Ta registrescha tar Pocket. Gratuit. -suggestedtags = Tags proponids -tagline = Memorisescha artitgels e videos ord Firefox per als vesair en Pocket, sin mintga apparat, da tut temp. -taglinestory_one = Clicca sin il buttun da Pocket per memorisar directamain ord Firefox tge artitgel, video u pagina ch'i saja. -taglinestory_two = Vesair en Pocket sin mintga apparat, da tut temp. -tagssaved = Tags agiuntads -tos = Cun cuntinuar accepteschas ti il <a href="%1$S" target="_blank">Contract da licenza</a> e las <a href="%2$S" target="_blank">Directivas per la protecziun da datas</a> da Pocket -tryitnow = Emprova ussa -signinfirefox = S'annunziar cun Firefox -signupfirefox = Sa registrar cun Firefox -viewlist = Mussar la glista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Memorisar en Pocket -saveToPocketCmd.label = Memorisar la pagina en Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Memorisar la colliaziun en Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Mussar la glista da Pocket diff --git a/browser/extensions/pocket/locale/ro/pocket.properties b/browser/extensions/pocket/locale/ro/pocket.properties deleted file mode 100644 index eedb756f9..000000000 --- a/browser/extensions/pocket/locale/ro/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Adaugă etichete -alreadyhaveacct = Ești deja un utilizator Pocket? -continueff = Continuă cu Firefox -errorgeneric = A apărut o eroare la încercarea de salvare în Pocket. -learnmore = Află mai multe -loginnow = Autentificare -maxtaglength = Etichetele sunt limitate la 25 de caractere -mustbeconnected = Trebuie să fii conectat la internet pentru a salva în Pocket. Te rugăm să verifici conexiunea și să încerci din nou. -onlylinkssaved = Doar linkurile pot fi salvate -pagenotsaved = Pagină nesalvată -pageremoved = Pagină eliminată -pagesaved = Salvat în Pocket -processingremove = Se elimină pagina… -processingtags = Se adaugă etichete… -removepage = Elimină pagina -save = Salvează -saving = Se salvează... -signupemail = Înregistrare cu e-mail -signuptosave = Înregistrează-te pentru Pocket. Este gratuit. -suggestedtags = Etichete sugerate -tagline = Salvează articole și videoclipuri din Firefox pentru a le vedea în Pocket de pe orice dispozitiv, oricând. -taglinestory_one = Clic pe butonul Pocket pentru a salva orice articol, videoclip sau pagină din Firefox. -taglinestory_two = Vezi în Pocket de pe orice dispozitiv, oricând. -tagssaved = Etichete adăugate -tos = Continuând, ești de acord cu <a href="%1$S" target="_blank">termenii de utilizare a serviciului</a> și <a href="%2$S" target="_blank">politica de confidențialitate</a> a Pocket -tryitnow = Încearcă acum -signinfirefox = Autentificare în Firefox -signupfirefox = Înregistrare în Firefox -viewlist = Vezi lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Salvează în Pocket -saveToPocketCmd.label = Salvează pagina în Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Salvează linkul în Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Vezi lista Pocket diff --git a/browser/extensions/pocket/locale/ru/pocket.properties b/browser/extensions/pocket/locale/ru/pocket.properties deleted file mode 100644 index 0da716e8a..000000000 --- a/browser/extensions/pocket/locale/ru/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Добавить теги -alreadyhaveacct = Уже используете Pocket? -continueff = Продолжить через Firefox -errorgeneric = При попытке сохранить в Pocket произошла ошибка. -learnmore = Узнайте больше -loginnow = Войдите -maxtaglength = Длина тега не должна превышать 25 символов -mustbeconnected = Чтобы сохранять в Pocket, вы должны быть подключены к Интернету. Пожалуйста, проверьте ваше соединение и попробуйте снова. -onlylinkssaved = Можно сохранять только ссылки -pagenotsaved = Страница не сохранена -pageremoved = Страница удалена -pagesaved = Сохранено в Pocket -processingremove = Удаление страницы… -processingtags = Добавление тегов… -removepage = Удалить страницу -save = Сохранить -saving = Сохранение… -signupemail = Регистрация по эл. почте -signuptosave = Зарегистрируйтесь в Pocket. Это бесплатно. -suggestedtags = Рекомендуемые теги -tagline = Сохраняйте статьи и видео из Firefox для просмотра в Pocket на любом устройстве, в любой момент. -taglinestory_one = Щёлкните по кнопке Pocket, чтобы сохранить любую статью, видео или страницу из Firefox. -taglinestory_two = Просматривайте их в Pocket на любом устройстве, в любой момент. -tagssaved = Теги добавлены -tos = Продолжая, вы принимаете <a href="%1$S" target="_blank">Условия службы</a> и <a href="%2$S" target="_blank">Политику приватности</a> Pocket -tryitnow = Попробовать сейчас -signinfirefox = Войти через Firefox -signupfirefox = Регистрация через Firefox -viewlist = Просмотреть список - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Сохранить в Pocket -saveToPocketCmd.label = Сохранить страницу в Pocket -saveToPocketCmd.accesskey = х -saveLinkToPocketCmd.label = Сохранить ссылку в Pocket -saveLinkToPocketCmd.accesskey = о -pocketMenuitem.label = Показать список Pocket diff --git a/browser/extensions/pocket/locale/sk/pocket.properties b/browser/extensions/pocket/locale/sk/pocket.properties deleted file mode 100644 index 57327365c..000000000 --- a/browser/extensions/pocket/locale/sk/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Pridať značky -alreadyhaveacct = Už ste používateľom služby Pocket? -continueff = Pokračovať s Firefoxom -errorgeneric = Počas ukladania údajov do služby Pocket sa vyskytla chyba. -learnmore = Ďalšie informácie -loginnow = Prihlásiť sa -maxtaglength = Značky môžu obsahovať najviac 25 znakov -mustbeconnected = Ak chcete ukladať údaje do služby Pocket, musíte byť pripojený k sieti Internet. Skontrolujte svoje pripojenie a skúste to znova. -onlylinkssaved = Uložené môžu byť len odkazy -pagenotsaved = Stránka nebola uložená -pageremoved = Stránka bola odstránená -pagesaved = Uložená do služby Pocket -processingremove = Stránka sa odstraňuje… -processingtags = Pridávajú sa značky… -removepage = Odstrániť stránku -save = Uložiť -saving = Ukladá sa… -signupemail = Zaregistrovať sa pomocou e-mailu -signuptosave = Zaregistrujte sa v službe Pocket. Je zadarmo. -suggestedtags = Navrhované značky -tagline = Ukladajte si články a videá z Firefoxu a majte ich dostupné kdekoľvek a na akomkoľvek zariadení pomocou služby Pocket. -taglinestory_one = Kliknutím na tlačidlo Pocket vo Firefoxe uložíte akýkoľvek článok, video alebo stránku. -taglinestory_two = Tieto sú potom so službou Pocket dostupné kdekoľvek a na akomkoľvek zariadení. -tagssaved = Značky boli pridané -tos = Pokračovaním vyjadrujete súhlas s <a href="%1$S" target="_blank">podmienkami používania</a> služby Pocket a so <a href="%2$S" target="_blank">zásadami ochrany osobných údajov</a> -tryitnow = Vyskúšajte to hneď teraz -signinfirefox = Prihlásiť sa pomocou Firefoxu -signupfirefox = Zaregistrovať sa pomocou Firefoxu -viewlist = Zobraziť zoznam - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Služba Pocket -pocket-button.tooltiptext = Uložiť do služby Pocket -saveToPocketCmd.label = Uložiť stránku do služby Pocket -saveToPocketCmd.accesskey = P -saveLinkToPocketCmd.label = Uložiť odkaz do služby Pocket -saveLinkToPocketCmd.accesskey = d -pocketMenuitem.label = Zobraziť zoznam služby Pocket diff --git a/browser/extensions/pocket/locale/sl/pocket.properties b/browser/extensions/pocket/locale/sl/pocket.properties deleted file mode 100644 index e0451d72b..000000000 --- a/browser/extensions/pocket/locale/sl/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Dodaj oznake -alreadyhaveacct = Že uporabljate Pocket? -continueff = Nadaljuj s Firefoxom -errorgeneric = Med shranjevanjem na Pocket je prišlo do napake. -learnmore = Več o tem -loginnow = Prijava -maxtaglength = Oznake so omejene na 25 znakov -mustbeconnected = Za shranjevanje na Pocket morate biti povezani na internet. Preverite povezavo in poskusite znova. -onlylinkssaved = Shranite lahko samo povezave -pagenotsaved = Stran ni bila shranjena -pageremoved = Stran odstranjena -pagesaved = Shranjeno na Pocket -processingremove = Odstranjevanje strani … -processingtags = Dodajanje oznak … -removepage = Odstrani stran -save = Shrani -saving = Shranjevanje … -signupemail = Registrirajte se z e-pošto -signuptosave = Brezplačno se registrirajte na Pocketu. -suggestedtags = Predlagane oznake -tagline = Shranite članke in videe v Firefoxu in si jih oglejte na Pocketu iz katere koli naprave. -taglinestory_one = Kliknite gumb Pocket v Firefoxu in shranite članek, video ali stran. -taglinestory_two = Oglejte si v Pocketu na kateri koli napravi. -tagssaved = Oznake dodane -tos = Če nadaljujete, sprejemate <a href="%1$S" target="_blank">Pogoje uporabe</a> in <a href="%2$S" target="_blank">Politiko zasebnosti</a> storitve Pocket -tryitnow = Preizkusite ga zdaj -signinfirefox = Prijavite se s Firefoxom -signupfirefox = Registrirajte se s Firefoxom -viewlist = Ogled seznama - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Shrani v Pocket -saveToPocketCmd.label = Shrani stran v Pocket -saveToPocketCmd.accesskey = r -saveLinkToPocketCmd.label = Shrani povezavo v Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Pokaži seznam Pocket diff --git a/browser/extensions/pocket/locale/sq/pocket.properties b/browser/extensions/pocket/locale/sq/pocket.properties deleted file mode 100644 index b8b17ad22..000000000 --- a/browser/extensions/pocket/locale/sq/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Shtoni Etiketa -alreadyhaveacct = Jeni tashmë përdorues Pocket-i? -continueff = Vazhdoni me Firefox-in -errorgeneric = Pati një gabim teksa përpiqej të ruante te Pocket. -learnmore = Mësoni më tepër -loginnow = Hyni -maxtaglength = Etiketat kufizohen deri në 25 shenja -mustbeconnected = Që të ruani në Pocket, duhet të jeni i lidhur në Internet. Ju lutemi, kontrolloni lidhjen tuaj dhe riprovoni. -onlylinkssaved = Mund të ruhen vetëm lidhje -pagenotsaved = Faqja S’u Ruajt -pageremoved = Faqja u Hoq -pagesaved = U ruajt te Pocket -processingremove = Po hiqet Faqja… -processingtags = Po shtohen etiketa… -removepage = Hiqe Faqen -save = Ruaje -saving = Po ruhet… -signupemail = Regjistrohuni me email -signuptosave = Regjistrohuni në Pocket. Është falas. -suggestedtags = Etiketa të Këshilluara -tagline = Ruani që nga Firefoxc-i artikuj dhe video për t’i parë në Pocket në çfarëdo pajisje, kurdo. -taglinestory_one = Klikoni butonin Pocket që të ruani që nga Firefox-i çfarëdo artikulli, video ose faqe. -taglinestory_two = Shihini në Pocket, në çfarëdo pajisje, kurdo. -tagssaved = Etiketat u Shtuan -tos = Duke vazhduar, pajtoheni me <a href="%1$S" target="_blank">Kushtet e Shërbimit</a> dhe <a href="%2$S" target="_blank">Rregullat e Privatësisë</a> për Pocket-in -tryitnow = Provojeni Që Tani -signinfirefox = Hyni me Firefox -signupfirefox = Regjistrohuni me Firefox -viewlist = Shihni Listën - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Ruajeni te Pocket -saveToPocketCmd.label = Ruajeni Faqen te Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Ruajeni lidhjen te Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Shihni Listën te Pocket diff --git a/browser/extensions/pocket/locale/sr/pocket.properties b/browser/extensions/pocket/locale/sr/pocket.properties deleted file mode 100644 index c3dbf2ece..000000000 --- a/browser/extensions/pocket/locale/sr/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Додај ознаку -alreadyhaveacct = Већ сте Pocket корисник? -continueff = Настави са Firefox-ом -errorgeneric = Десила се грешка при покушају снимања у Pocket. -learnmore = Сазнајте више -loginnow = Пријава -maxtaglength = Ознаке су ограничене на 25 карактера -mustbeconnected = Морате бити повезани на интернет да бисте снимили у Pocket. Проверити везу и покушајте поново. -onlylinkssaved = Само се везе могу снимити -pagenotsaved = Страница није снимљена -pageremoved = Страница уклоњена -pagesaved = Снимљено у Pocket -processingremove = Уклањам страницу… -processingtags = Додајем ознаку… -removepage = Уклони страницу -save = Сними -saving = Снимам… -signupemail = Региструј се са е-поштом -signuptosave = Региструјте се да користите Pocket. Бесплатно је. -suggestedtags = Предложене ознаке -tagline = Снимите чланке и видео снимке из Firefox-а да бисте их погледали у Pocket-у на било ком уређају било када. -taglinestory_one = Кликните на Pocket дугме да бисте снимили чланак, видео или страницу из Firefox-а. -taglinestory_two = Погледајте садржај у Pocket-у на било ком уређају било када. -tagssaved = Ознаке додате -tos = Настављањем прихватате <a href="%1$S" target="_blank">услове коришћења</a> и <a href="%2$S" target="_blank">полису приватности</a> Pocket-а -tryitnow = Покушајте сада -signinfirefox = Пријави се -signupfirefox = Региструј се -viewlist = Прикажи листу - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Сними у Pocket -saveToPocketCmd.label = Сними страницу у Pocket -saveToPocketCmd.accesskey = С -saveLinkToPocketCmd.label = Сними везу у Pocket -saveLinkToPocketCmd.accesskey = в -pocketMenuitem.label = Прикажи Pocket листу diff --git a/browser/extensions/pocket/locale/sv-SE/pocket.properties b/browser/extensions/pocket/locale/sv-SE/pocket.properties deleted file mode 100644 index e01ac7373..000000000 --- a/browser/extensions/pocket/locale/sv-SE/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Lägg till etiketter -alreadyhaveacct = Redan en Pocket användare? -continueff = Fortsätt med Firefox\u0020 -errorgeneric = Ett fel upptäcktes då du försökte spara till Pocket. -learnmore = Läs mer -loginnow = Logga in -maxtaglength = Etiketter kan max vara 25 tecken -mustbeconnected = Du måste vara ansluten till internet för att kunna spara till Pocket. Kontrollera din anslutning och försök igen. -onlylinkssaved = Bara länkar kan sparas\u0020 -pagenotsaved = Sidan sparades inte\u0020 -pageremoved = Sidan borttagen -pagesaved = Spara till Pocket\u0020 -processingremove = Tar bort sida… -processingtags = Lägger till etiketter… -removepage = Ta bort sida -save = Spara -saving = Sparar… -signupemail = Registrera dig med din E-postadress -signuptosave = Registrera dig för Pocket. Det är gratis. -suggestedtags = Föreslagna etiketter -tagline = Spara artiklar och videor från Firefox för att visa i Pocket på vilken enhet som helst, när som helst. -taglinestory_one = Klicka på Pocket knappen för att spara vilken artikel, video eller sida som helst från Firefox.\u0020 -taglinestory_two = Visa i Pocket på vilken enhet som helst, när som helst.\u0020 -tagssaved = Etiketter Tillagda -tos = Genom att fortsätta godkänner du Pocket's <a href="%1$S" target="_blank">användarvillkor</a> och <a href="%2$S" target="_blank">sekretesspolicy</a> -tryitnow = Prova nu -signinfirefox = Logga in med Firefox\u0020 -signupfirefox = Registrera dig med Firefox\u0020 -viewlist = Visa lista - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Spara till Pocket -saveToPocketCmd.label = Spara sida till Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Spara Länk till Pocket -saveLinkToPocketCmd.accesskey = l -pocketMenuitem.label = Visa Pocket Lista\u0020 diff --git a/browser/extensions/pocket/locale/te/pocket.properties b/browser/extensions/pocket/locale/te/pocket.properties deleted file mode 100644 index 2e9552793..000000000 --- a/browser/extensions/pocket/locale/te/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = టాగ్లను జోడించు -alreadyhaveacct = ఇప్పటికే ఒక పాకెట్ యూజర్? -continueff = ఫైర్ఫాక్స్ తో కొనసాగించుము -errorgeneric = పాకెట్ కు సేవ్ చేయడానికి ప్రయత్నిస్తున్నప్పుడు లోపం ఉంది. -learnmore = మరింత తెలుసుకోండి -loginnow = లాగ్ ఇన్ -maxtaglength = టాగ్లు 25 అక్షరాలకు పరిమితం చేయబడ్డాయి -mustbeconnected = మీరు పాకెట్ కు సేవ్ చేయడానికి ఇంటర్నెట్ కనెక్ట్ చేయక తప్పదు. మీ కనెక్షన్ను తనిఖీ చేసి, మళ్ళీ ప్రయత్నించండి. -onlylinkssaved = కేవలం లింకులు సేవ్ చేయవచ్చు -pagenotsaved = పేజీ సేవ్ చేయబడలేదు -pageremoved = పేజీ తీసివేయబడెను -pagesaved = పాకెట్ కు సేవ్ చేయబడింది -processingremove = పేజీని తొలగించు… -processingtags = టాగ్లు జోడిస్తోంది... -removepage = పేజీని తొలగించు -save = సేవ్ చేయి -saving = సేవ్ చేస్తోంది... -signupemail = ఇమెయిల్ తో సైన్అప్ అవ్వండ్ -signuptosave = పాకెట్ కోసం సైన్ అప్ చేయండి. ఇది ఉచితం. -suggestedtags = సూచించిన టాగ్లు -tagline = ఏ పరికరం, ఏ సమయం లో పాకెట్ వీక్షించడానికి Firefox నుండి వ్యాసాలు మరియు వీడియోలను సేవ్ చేయవచ్చు. -taglinestory_one = ఫైర్ఫాక్సు నుండి ఒక వ్యాసం, వీడియో లేదా పేజీ సేవ్ పాకెట్ బటన్ క్లిక్ చేయండి. -taglinestory_two = ఏ పరికరంలో అయినా, ఏ సమయంలో అయినా పాకెట్ లో చూడండి. -tagssaved = టాగ్లు చేర్చబడింది -tos = కొనసాగించడం ద్వారా, మీరు పాకెట్ యొక్క <a href="%1$S" target="_blank"> సేవా నిబంధనలు</a> మరియు <a href="%2$S" target="_blank"> గోప్యతా విధానము</a> ను అంగీకరిచబడుతారు -tryitnow = దీన్ని ఇప్పుడు ప్రయత్నించండి -signinfirefox = ఫైర్ఫాక్సుకు ప్రవేశించండి -signupfirefox = ఫైర్ఫాక్సుకు ప్రవేశించండి -viewlist = జాబితాను చూడండి - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = పాకెట్ -pocket-button.tooltiptext = పాకెట్ కు సేవ్ చేయండి -saveToPocketCmd.label = పాకెట్ కు సేవ్ చేయండి -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = పాకెట్ కు లింక్ ను సేవ్ చేయండి -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = పాకెట్ జాబితా చూడండి diff --git a/browser/extensions/pocket/locale/th/pocket.properties b/browser/extensions/pocket/locale/th/pocket.properties deleted file mode 100644 index 6cdf1c9ec..000000000 --- a/browser/extensions/pocket/locale/th/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = เพิ่มป้ายกำกับ -alreadyhaveacct = เป็นผู้ใช้ Pocket อยู่แล้ว? -continueff = ดำเนินการต่อด้วย Firefox -errorgeneric = เกิดข้อผิดพลาดระหว่างการบันทึกไปยัง Pocket -learnmore = เรียนรู้เพิ่มเติม -loginnow = เข้าสู่ระบบ -maxtaglength = ป้ายกำกับถูกจำกัดไว้ที่ 25 ตัวอักษร -mustbeconnected = คุณต้องเชื่อมต่อกับอินเทอร์เน็ตก่อนที่จะบันทึก Pocket โปรดตรวจสอบการเชื่อมต่อของคุณและลองอีกครั้ง -onlylinkssaved = ลิงก์เท่านั้นที่สามารถถูกบันทึกได้ -pagenotsaved = หน้าไม่ถูกบันทึก -pageremoved = ลบหน้าแล้ว -pagesaved = บันทึกไปยัง Pocket -processingremove = กำลังลบหน้า… -processingtags = กำลังเพิ่มป้ายกำกับ… -removepage = ลบหน้า -save = บันทึก -saving = กำลังบันทึก… -signupemail = ลงทะเบียนด้วยอีเมล -signuptosave = ไม่มีค่าใช้จ่ายในการลงทะเบียน Pocket -suggestedtags = ป้ายกำกับที่ถูกแนะนำ -tagline = บันทึกบทความและวิดีโอจาก Firefox เพื่อดูใน Pocket บนอุปกรณ์ต่าง ๆ เวลาไหนก็ได้ -taglinestory_one = คลิกปุ่ม Pocket เพื่อบันทึกบทความ วิดีโอ หรือหน้าจาก Firefox -taglinestory_two = ดูใน Pocket บนอุปกรณ์ต่าง ๆ เวลาไหนก็ได้ -tagssaved = ป้ายกำกับถูกเพิ่มแล้ว -tos = หากตกลง หมายความว่า คุณยอมรับ<a href="%1$S" target="_blank">เงื่อนไขการให้บริการ</a> และ<a href="%2$S" target="_blank">นโยบายความเป็นส่วนตัว</a>ของ Pocket -tryitnow = ลองเลย -signinfirefox = ลงชื่อเข้าด้วย Firefox -signupfirefox = ลงทะเบียนกับ Firefox -viewlist = ดูรายการ - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = บันทึกไปยัง Pocket -saveToPocketCmd.label = บันทึกหน้าไปยัง Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = บันทึกลิงก์ไปยัง Pocket -saveLinkToPocketCmd.accesskey = ป -pocketMenuitem.label = ดูรายการ Pocket diff --git a/browser/extensions/pocket/locale/tr/pocket.properties b/browser/extensions/pocket/locale/tr/pocket.properties deleted file mode 100644 index ea1970a7d..000000000 --- a/browser/extensions/pocket/locale/tr/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Etiket ekle -alreadyhaveacct = Zaten Pocket kullanıcısı mısınız? -continueff = Firefox ile devam et -errorgeneric = Pocket’a kaydetmeye çalışırken bir hata oluştu. -learnmore = Daha fazla bilgi al -loginnow = Giriş yapın -maxtaglength = Etiketler en fazla 25 karakter olabilir -mustbeconnected = Pocket’a kaydetmek için internete bağlı olmalısınız. Lütfen bağlantınızı kontrol edip yeniden deneyin. -onlylinkssaved = Yalnızca bağlantılar kaydedilebilir -pagenotsaved = Sayfa kaydedilmedi -pageremoved = Sayfa silindi -pagesaved = Pocket’a kaydedildi -processingremove = Sayfa siliniyor… -processingtags = Etiketler ekleniyor… -removepage = Sayfayı sil -save = Kaydet -saving = Kaydediliyor… -signupemail = E-postayla kaydol -signuptosave = Pocket’a kaydolun. Ücretsiz! -suggestedtags = Önerilen etiketler -tagline = İstediğiniz cihazda, istediğiniz zaman görmek istediğiniz yazı ve videoları Firefox’tan Pocket’a kaydedin. -taglinestory_one = Firefox’ta istediğiniz yazıyı, videoyu veya sayfayı kaydetmek için Pocket düğmesine tıklayın. -taglinestory_two = İstediğiniz cihazda, istediğiniz zaman Pocket’tan bakın. -tagssaved = Etiketler eklendi -tos = Devam ederseniz Pocket'ın <a href="%1$S" target="_blank">Kullanım Koşullarını</a> ve <a href="%2$S" target="_blank">Gizlilik İlkelerini</a> kabul etmiş sayılırsınız -tryitnow = Hemen deneyin -signinfirefox = Firefox ile giriş yap -signupfirefox = Firefox ile kaydol -viewlist = Listeyi göster - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Pocket’a kaydet -saveToPocketCmd.label = Sayfayı Pocket’a kaydet -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = Bağlantıyı Pocket’a kaydet -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = Pocket listesini göster diff --git a/browser/extensions/pocket/locale/uk/pocket.properties b/browser/extensions/pocket/locale/uk/pocket.properties deleted file mode 100644 index d15049b2c..000000000 --- a/browser/extensions/pocket/locale/uk/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = Додати мітки -alreadyhaveacct = Вже використовуєте Pocket? -continueff = Продовжити з Firefox -errorgeneric = При спробі збереження в Pocket сталася помилка. -learnmore = Докладніше -loginnow = Увійти -maxtaglength = Мітки мають обмеження до 25 символів -mustbeconnected = Для можливості збереження в Pocket ви повинні бути підключені до Інтернету. Перевірте своє з'єднання і спробуйте знову. -onlylinkssaved = Можна зберігати лише посилання -pagenotsaved = Сторінку не збережено -pageremoved = Сторінку вилучено -pagesaved = Збережено в Pocket -processingremove = Вилучення сторінки… -processingtags = Додавання міток… -removepage = Вилучити сторінку -save = Зберегти -saving = Збереження… -signupemail = Реєстрація за адресою електронної пошти -signuptosave = Зареєструйтеся в Pocket. Це безплатно. -suggestedtags = Пропоновані мітки -tagline = Зберігайте статті та відео з Firefox, щоб переглядати їх в Pocket на будь-якому пристрої та в будь-який час. -taglinestory_one = Натисніть кнопку Pocket для збереження будь-якої статті, відео чи сторінки з Firefox. -taglinestory_two = Переглядайте в Pocket на будь-якому пристрої та в будь-який час. -tagssaved = Мітки додано -tos = Продовжуючи, ви погоджуєтесь з <a href="%1$S" target="_blank">Умовами використання</a> і <a href="%2$S" target="_blank">Політикою приватності</a> -tryitnow = Спробувати зараз -signinfirefox = Увійти через Firefox -signupfirefox = Реєстрація через Firefox -viewlist = Перегляд списку - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Зберегти в Pocket -saveToPocketCmd.label = Зберегти сторінку в Pocket -saveToPocketCmd.accesskey = З -saveLinkToPocketCmd.label = Зберегти посилання в Pocket -saveLinkToPocketCmd.accesskey = п -pocketMenuitem.label = Перегляд списку Pocket diff --git a/browser/extensions/pocket/locale/zh-CN/pocket.properties b/browser/extensions/pocket/locale/zh-CN/pocket.properties deleted file mode 100644 index e913887b8..000000000 --- a/browser/extensions/pocket/locale/zh-CN/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = 添加标签 -alreadyhaveacct = 已有 Pocket 账号? -continueff = 使用 Firefox 继续 -errorgeneric = 尝试保存到 Pocket 时出错。 -learnmore = 详细了解 -loginnow = 登录 -maxtaglength = 标签不能超过 25 个字符 -mustbeconnected = 您必须已连接互联网才能保存到 Pocket。请检查您的连接,然后再试。 -onlylinkssaved = 只有链接能被保存 -pagenotsaved = 页面未保存 -pageremoved = 页面已移除 -pagesaved = 已保存到 Pocket -processingremove = 正在移除页面… -processingtags = 正在添加标签… -removepage = 移除页面 -save = 保存 -saving = 正在保存… -signupemail = 通过电子邮件注册 -signuptosave = 免费注册 Pocket。 -suggestedtags = 推荐标签 -tagline = 在 Firefox 上保存文章和视频,以供在任何时间、任何设备上用 Pocket 访问。 -taglinestory_one = 点击 Pocket 按钮保存 Firefox 上的任何文章、视频或页面。 -taglinestory_two = 在任何时间、任何设备上的 Pocket 中查看。 -tagssaved = 标签已添加 -tos = 继续则表示您同意 Pocket 的<a href="%1$S" target="_blank">服务条款</a>和<a href="%2$S" target="_blank">隐私政策</a> -tryitnow = 立即尝试 -signinfirefox = 使用 Firefox 登录 -signupfirefox = 使用 Firefox 注册 -viewlist = 查看列表 - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = 保存到 Pocket -saveToPocketCmd.label = 保存页面到 Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = 保存链接到 Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = 查看 Pocket 列表 diff --git a/browser/extensions/pocket/locale/zh-TW/pocket.properties b/browser/extensions/pocket/locale/zh-TW/pocket.properties deleted file mode 100644 index 02cf5223b..000000000 --- a/browser/extensions/pocket/locale/zh-TW/pocket.properties +++ /dev/null @@ -1,43 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -addtags = 新增標籤 -alreadyhaveacct = 已經是 Pocket 使用者了嗎? -continueff = 使用 Firefox 繼續 -errorgeneric = 嘗試儲存至 Pocket 時發生錯誤。 -learnmore = 更多資訊 -loginnow = 登入 -maxtaglength = 標籤僅能有 25 字元 -mustbeconnected = 您必須連線至網際網路才能儲存至 Pocket。請檢查您的連線狀態後再試一次。 -onlylinkssaved = 僅能儲存鏈結 -pagenotsaved = 未儲存頁面 -pageremoved = 已移除頁面 -pagesaved = 已儲存至 Pocket -processingremove = 正在移除頁面… -processingtags = 正在新增標籤… -removepage = 移除頁面 -save = 儲存 -saving = 儲存中… -signupemail = 使用電子郵件地址註冊 -signuptosave = 免費註冊 Pocket 帳號。 -suggestedtags = 建議的標籤 -tagline = 隨時隨地在任何裝置上的 Firefox 來儲存文章與影片,稍後再用 Pocket 開啟。 -taglinestory_one = 在 Firefox 中點擊 Pocket 按鈕來儲存任何文章、影片或網頁。 -taglinestory_two = 隨時隨地在任何裝置上用 Pocket 檢視。 -tagssaved = 已新增標籤 -tos = 繼續使用就代表您同意 Pocket 的 <a href="%1$S" target="_blank">服務條款</a> 及 <a href="%2$S" target="_blank">隱私權保護政策</a> -tryitnow = 立刻試試 -signinfirefox = 使用 Firefox 登入 -signupfirefox = 使用 Firefox 註冊 -viewlist = 檢視清單 - -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): -# "Pocket" is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = 儲存至 Pocket -saveToPocketCmd.label = 將頁面儲存至 Pocket -saveToPocketCmd.accesskey = k -saveLinkToPocketCmd.label = 將鏈結儲存至 Pocket -saveLinkToPocketCmd.accesskey = o -pocketMenuitem.label = 檢視 Pocket 清單 diff --git a/browser/extensions/pocket/moz.build b/browser/extensions/pocket/moz.build deleted file mode 100644 index 52227bb8b..000000000 --- a/browser/extensions/pocket/moz.build +++ /dev/null @@ -1,20 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION'] - -DIRS += ['locale'] - -FINAL_TARGET_FILES.features['firefox@getpocket.com'] += [ - 'bootstrap.js' -] - -FINAL_TARGET_PP_FILES.features['firefox@getpocket.com'] += [ - 'install.rdf.in' -] - -JAR_MANIFESTS += ['jar.mn'] diff --git a/browser/extensions/pocket/skin/linux/Toolbar-inverted.png b/browser/extensions/pocket/skin/linux/Toolbar-inverted.png Binary files differdeleted file mode 100644 index 68f5125ea..000000000 --- a/browser/extensions/pocket/skin/linux/Toolbar-inverted.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/linux/Toolbar-inverted@2x.png b/browser/extensions/pocket/skin/linux/Toolbar-inverted@2x.png Binary files differdeleted file mode 100644 index 89056295c..000000000 --- a/browser/extensions/pocket/skin/linux/Toolbar-inverted@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/linux/Toolbar.png b/browser/extensions/pocket/skin/linux/Toolbar.png Binary files differdeleted file mode 100644 index be9b0e6d2..000000000 --- a/browser/extensions/pocket/skin/linux/Toolbar.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/linux/Toolbar@2x.png b/browser/extensions/pocket/skin/linux/Toolbar@2x.png Binary files differdeleted file mode 100644 index 5dc4e754a..000000000 --- a/browser/extensions/pocket/skin/linux/Toolbar@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/linux/menuPanel.png b/browser/extensions/pocket/skin/linux/menuPanel.png Binary files differdeleted file mode 100644 index 55bc46cc9..000000000 --- a/browser/extensions/pocket/skin/linux/menuPanel.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/linux/menuPanel@2x.png b/browser/extensions/pocket/skin/linux/menuPanel@2x.png Binary files differdeleted file mode 100644 index ad13ca4ce..000000000 --- a/browser/extensions/pocket/skin/linux/menuPanel@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/linux/pocket.css b/browser/extensions/pocket/skin/linux/pocket.css deleted file mode 100644 index 156964923..000000000 --- a/browser/extensions/pocket/skin/linux/pocket.css +++ /dev/null @@ -1,10 +0,0 @@ -@import url("chrome://pocket-shared/skin/pocket.css"); - -#nav-bar #pocket-button > .toolbarbutton-icon { - padding: 2px 6px; -} - -:-moz-any(#TabsToolbar, .widget-overflow-list) #pocket-button > .toolbarbutton-icon { - max-width: 18px; - padding: 0; -}
\ No newline at end of file diff --git a/browser/extensions/pocket/skin/osx/Toolbar-inverted.png b/browser/extensions/pocket/skin/osx/Toolbar-inverted.png Binary files differdeleted file mode 100644 index 0f4d57b4e..000000000 --- a/browser/extensions/pocket/skin/osx/Toolbar-inverted.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/Toolbar-inverted@2x.png b/browser/extensions/pocket/skin/osx/Toolbar-inverted@2x.png Binary files differdeleted file mode 100644 index 03c3b42d5..000000000 --- a/browser/extensions/pocket/skin/osx/Toolbar-inverted@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/Toolbar-yosemite.png b/browser/extensions/pocket/skin/osx/Toolbar-yosemite.png Binary files differdeleted file mode 100644 index 28602b186..000000000 --- a/browser/extensions/pocket/skin/osx/Toolbar-yosemite.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/Toolbar-yosemite@2x.png b/browser/extensions/pocket/skin/osx/Toolbar-yosemite@2x.png Binary files differdeleted file mode 100644 index 53040cb46..000000000 --- a/browser/extensions/pocket/skin/osx/Toolbar-yosemite@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/Toolbar.png b/browser/extensions/pocket/skin/osx/Toolbar.png Binary files differdeleted file mode 100644 index 1a8d7a51c..000000000 --- a/browser/extensions/pocket/skin/osx/Toolbar.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/Toolbar@2x.png b/browser/extensions/pocket/skin/osx/Toolbar@2x.png Binary files differdeleted file mode 100644 index 91bf3ef6f..000000000 --- a/browser/extensions/pocket/skin/osx/Toolbar@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/menuPanel-yosemite.png b/browser/extensions/pocket/skin/osx/menuPanel-yosemite.png Binary files differdeleted file mode 100644 index 30b475cc0..000000000 --- a/browser/extensions/pocket/skin/osx/menuPanel-yosemite.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/menuPanel-yosemite@2x.png b/browser/extensions/pocket/skin/osx/menuPanel-yosemite@2x.png Binary files differdeleted file mode 100644 index 389d96ec7..000000000 --- a/browser/extensions/pocket/skin/osx/menuPanel-yosemite@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/menuPanel.png b/browser/extensions/pocket/skin/osx/menuPanel.png Binary files differdeleted file mode 100644 index d2bf61888..000000000 --- a/browser/extensions/pocket/skin/osx/menuPanel.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/menuPanel@2x.png b/browser/extensions/pocket/skin/osx/menuPanel@2x.png Binary files differdeleted file mode 100644 index f58afbc4d..000000000 --- a/browser/extensions/pocket/skin/osx/menuPanel@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/osx/pocket.css b/browser/extensions/pocket/skin/osx/pocket.css deleted file mode 100644 index 534a881a5..000000000 --- a/browser/extensions/pocket/skin/osx/pocket.css +++ /dev/null @@ -1,42 +0,0 @@ -@import url("chrome://pocket-shared/skin/pocket.css"); - -#pocket-button[cui-areatype="toolbar"] > .toolbarbutton-icon { - max-width: 18px; - margin: 0; -} - -#pocket-button[cui-areatype="toolbar"][open] { - -moz-image-region: rect(36px, 18px, 54px, 0); -} - -@media (min-resolution: 2dppx) { - #panelMenu_pocket, - #menu_pocket, - #BMB_pocket { - list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16@2x.png"); - } - - #panelMenu_pocket > .toolbarbutton-icon { - width: 16px; - } -} - -@media not all and (min-resolution: 1.1dppx) { - #pocket-button:hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) { - -moz-image-region: rect(18px, 18px, 36px, 0); - } -} - -@media (min-resolution: 1.1dppx) { - #pocket-button[cui-areatype="toolbar"][open] { - -moz-image-region: rect(72px, 36px, 108px, 0); - } - - #pocket-button:hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) { - -moz-image-region: rect(36px, 36px, 72px, 0); - } -} - -#PanelUI-pocketView[mainview=true] > .panel-subview-body > #pocket-panel-iframe { - border-radius: var(--arrowpanel-border-radius); -} diff --git a/browser/extensions/pocket/skin/shared/pocket.css b/browser/extensions/pocket/skin/shared/pocket.css deleted file mode 100644 index ec46e1890..000000000 --- a/browser/extensions/pocket/skin/shared/pocket.css +++ /dev/null @@ -1,79 +0,0 @@ -/* Bug 1164419 - increase Pocket panel size to accomidate wider Russian text. */ -panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-viewstack > .panel-mainview:not([panelid="PanelUI-popup"]) { - max-width: 33em; /* standaloneSubviewWidth + 3 */ -} - -.cui-widget-panel[viewId="PanelUI-pocketView"] > .panel-arrowcontainer > .panel-arrowcontent { - padding-top: 0; - padding-bottom: 0; -} - -#PanelUI-pocketView > .panel-subview-body, -#PanelUI-pocketView { - overflow: visible; -} - -#pocket-button { - list-style-image: url("chrome://pocket/skin/Toolbar.png"); - -moz-image-region: rect(0, 18px, 18px, 0); -} - -toolbar[brighttext] #pocket-button { - list-style-image: url(chrome://pocket/skin/Toolbar-inverted.png); -} - -@media not all and (min-resolution: 1.1dppx) { - #pocket-button[cui-areatype="menu-panel"], - toolbarpaletteitem[place="palette"] > #pocket-button { - list-style-image: url(chrome://pocket/skin/menuPanel.png); - -moz-image-region: rect(0, 32px, 32px, 0); - } - - #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] { - -moz-image-region: rect(32px, 32px, 64px, 0); - } -} - -@media (min-resolution: 1.1dppx) { - #pocket-button[cui-areatype="menu-panel"], - toolbarpaletteitem[place="palette"] > #pocket-button { - list-style-image: url(chrome://pocket/skin/menuPanel@2x.png); - -moz-image-region: rect(0px, 64px, 64px, 0); - } - - #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] { - -moz-image-region: rect(64px, 64px, 128px, 0); - } -} - -#pocket-button[cui-areatype="toolbar"] { - -moz-image-region: rect(0, 18px, 18px, 0); -} - -#pocket-button[cui-areatype="toolbar"][open] { - -moz-image-region: rect(18px, 18px, 36px, 0); -} - -@media (min-resolution: 1.1dppx) { - #pocket-button { - list-style-image: url("chrome://pocket/skin/Toolbar@2x.png"); - } - - toolbar[brighttext] #pocket-button { - list-style-image: url("chrome://pocket/skin/Toolbar-inverted@2x.png"); - } - - #pocket-button[cui-areatype="toolbar"] { - -moz-image-region: rect(0, 36px, 36px, 0px); - } - - #pocket-button[cui-areatype="toolbar"][open] { - -moz-image-region: rect(36px, 36px, 72px, 0px); - } -} - -#panelMenu_pocket, -#menu_pocket, -#BMB_pocket { - list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16.png"); -} diff --git a/browser/extensions/pocket/skin/windows/Toolbar-XP.png b/browser/extensions/pocket/skin/windows/Toolbar-XP.png Binary files differdeleted file mode 100644 index 9220a207f..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar-XP.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar-aero.png b/browser/extensions/pocket/skin/windows/Toolbar-aero.png Binary files differdeleted file mode 100644 index 7b373acb9..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar-aero.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar-aero@2x.png b/browser/extensions/pocket/skin/windows/Toolbar-aero@2x.png Binary files differdeleted file mode 100644 index 6e83dcc60..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar-aero@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar-inverted.png b/browser/extensions/pocket/skin/windows/Toolbar-inverted.png Binary files differdeleted file mode 100644 index 70e95f464..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar-inverted.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar-inverted@2x.png b/browser/extensions/pocket/skin/windows/Toolbar-inverted@2x.png Binary files differdeleted file mode 100644 index ba0b7e2af..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar-inverted@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar-lunaSilver.png b/browser/extensions/pocket/skin/windows/Toolbar-lunaSilver.png Binary files differdeleted file mode 100644 index 5afe7ca44..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar-lunaSilver.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar-win8.png b/browser/extensions/pocket/skin/windows/Toolbar-win8.png Binary files differdeleted file mode 100644 index 208dc03ae..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar-win8.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar-win8@2x.png b/browser/extensions/pocket/skin/windows/Toolbar-win8@2x.png Binary files differdeleted file mode 100644 index 3704f0885..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar-win8@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar.png b/browser/extensions/pocket/skin/windows/Toolbar.png Binary files differdeleted file mode 100644 index 4801961f8..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/Toolbar@2x.png b/browser/extensions/pocket/skin/windows/Toolbar@2x.png Binary files differdeleted file mode 100644 index f3a1cc738..000000000 --- a/browser/extensions/pocket/skin/windows/Toolbar@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/menuPanel-aero.png b/browser/extensions/pocket/skin/windows/menuPanel-aero.png Binary files differdeleted file mode 100644 index 459e82634..000000000 --- a/browser/extensions/pocket/skin/windows/menuPanel-aero.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/menuPanel-aero@2x.png b/browser/extensions/pocket/skin/windows/menuPanel-aero@2x.png Binary files differdeleted file mode 100644 index eef525741..000000000 --- a/browser/extensions/pocket/skin/windows/menuPanel-aero@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/menuPanel.png b/browser/extensions/pocket/skin/windows/menuPanel.png Binary files differdeleted file mode 100644 index 55bc46cc9..000000000 --- a/browser/extensions/pocket/skin/windows/menuPanel.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/menuPanel@2x.png b/browser/extensions/pocket/skin/windows/menuPanel@2x.png Binary files differdeleted file mode 100644 index ad13ca4ce..000000000 --- a/browser/extensions/pocket/skin/windows/menuPanel@2x.png +++ /dev/null diff --git a/browser/extensions/pocket/skin/windows/pocket.css b/browser/extensions/pocket/skin/windows/pocket.css deleted file mode 100644 index 011b821a9..000000000 --- a/browser/extensions/pocket/skin/windows/pocket.css +++ /dev/null @@ -1,16 +0,0 @@ -@import url("chrome://pocket-shared/skin/pocket.css"); - -#nav-bar #pocket-button > .toolbarbutton-icon { - padding: calc(var(--toolbarbutton-vertical-inner-padding)) 6px; -} - -:-moz-any(#TabsToolbar, .widget-overflow-list) #pocket-button > .toolbarbutton-icon { - max-width: 18px; - padding: 0; -} - -@media (-moz-windows-theme: luna-silver) and (max-resolution: 1dppx) { - #pocket-button { - list-style-image: url(Toolbar-lunaSilver.png); - } -} diff --git a/browser/extensions/webcompat/install.rdf.in b/browser/extensions/webcompat/install.rdf.in deleted file mode 100644 index 2c4406f25..000000000 --- a/browser/extensions/webcompat/install.rdf.in +++ /dev/null @@ -1,32 +0,0 @@ -<?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/. --> - -#filter substitution - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>webcompat@mozilla.org</em:id> - <em:version>1.0</em:version> - <em:type>2</em:type> - <em:bootstrap>true</em:bootstrap> - <em:multiprocessCompatible>true</em:multiprocessCompatible> - - <!-- Target Application this extension can install into, - with minimum and maximum supported versions. --> - <em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>@MOZ_APP_VERSION@</em:minVersion> - <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion> - </Description> - </em:targetApplication> - - <!-- Front End MetaData --> - <em:name>Web Compat</em:name> - <em:description>Urgent post-release fixes for web compatibility.</em:description> - </Description> -</RDF> diff --git a/browser/extensions/webcompat/moz.build b/browser/extensions/webcompat/moz.build deleted file mode 100644 index 7d592013b..000000000 --- a/browser/extensions/webcompat/moz.build +++ /dev/null @@ -1,16 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION'] - -FINAL_TARGET_FILES.features['webcompat@mozilla.org'] += [ - 'bootstrap.js' -] - -FINAL_TARGET_PP_FILES.features['webcompat@mozilla.org'] += [ - 'install.rdf.in' -] diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index af200147f..b8aee0f14 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -61,10 +61,10 @@ STUB_HOOK = $(NSINSTALL) -D '$(ABS_DIST)/$(PKG_INST_PATH)'; \ $(NULL) endif -SEARCHPLUGINS_FILENAMES := $(shell $(call py_action,output_searchplugins_list,$(srcdir)/search/list.json $(AB_CD))) +SEARCHPLUGINS_FILENAMES := $(or $(shell $(call py_action,output_searchplugins_list,$(srcdir)/search/list.json $(AB_CD))), $(error Missing search plugins)) SEARCHPLUGINS_PATH := .deps/generated_$(AB_CD) SEARCHPLUGINS_TARGET := libs searchplugins -SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(srcdir)/searchplugins/$(plugin)),$(warning Missing searchplugin: $(plugin)))) +SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(srcdir)/searchplugins/$(plugin)),$(error Missing searchplugin: $(plugin)))) # Some locale-specific search plugins may have preprocessor directives, but the # default en-US ones do not. SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings diff --git a/browser/locales/en-US/firefox-l10n.js b/browser/locales/en-US/firefox-l10n.js index c1e5510f3..642ad6534 100644 --- a/browser/locales/en-US/firefox-l10n.js +++ b/browser/locales/en-US/firefox-l10n.js @@ -4,8 +4,4 @@ #filter substitution -# LOCALIZATION NOTE: this preference is set to true for en-US specifically, -# locales without this line have the setting set to false by default. -pref("browser.search.geoSpecificDefaults", true); - pref("general.useragent.locale", "@AB_CD@"); diff --git a/browser/locales/search/list.json b/browser/locales/search/list.json index 9f7d82b4e..722f3186f 100644 --- a/browser/locales/search/list.json +++ b/browser/locales/search/list.json @@ -5,36 +5,6 @@ ] }, "regionOverrides": { - "US": { - "google": "google-nocodes" - }, - "CA": { - "google": "google-nocodes" - }, - "KZ": { - "google": "google-nocodes" - }, - "BY": { - "google": "google-nocodes" - }, - "RU": { - "google": "google-nocodes" - }, - "TR": { - "google": "google-nocodes" - }, - "UA": { - "google": "google-nocodes" - }, - "CN": { - "google": "google-nocodes" - }, - "TW": { - "google": "google-nocodes" - }, - "HK": { - "google": "google-nocodes" - } }, "locales": { "en-US": { diff --git a/build/application.ini b/build/application.ini index e60f86b69..8f65421ed 100644 --- a/build/application.ini +++ b/build/application.ini @@ -19,11 +19,17 @@ #include @TOPOBJDIR@/source-repo.h [App] #ifdef MC_OFFICIAL +#if defined(MC_PALEMOON) || defined(MC_BASILISK) Vendor=Moonchild Productions +#elif defined(BINOC_BOREALIS) +Vendor=Binary Outcast #else Vendor=@MOZ_APP_VENDOR@ #endif -#if defined(MOZ_PHOENIX) && defined(MC_PALEMOON) +#else +Vendor=@MOZ_APP_VENDOR@ +#endif +#ifdef MC_PALEMOON Name=Pale Moon #else Name=@MOZ_APP_BASENAME@ diff --git a/build/autoconf/compiler-opts.m4 b/build/autoconf/compiler-opts.m4 index 57a974435..c47d792f4 100644 --- a/build/autoconf/compiler-opts.m4 +++ b/build/autoconf/compiler-opts.m4 @@ -181,18 +181,15 @@ if test "$GNU_CC"; then if test -z "$CLANG_CC"; then case "$CC_VERSION" in - 4.*) + 4.* | 5.*) ;; *) # Lifetime Dead Store Elimination level 2 (default in GCC6+) breaks Gecko. - # Ideally, we'd use -flifetime-dse=1, but that means we'd forcefully - # enable it on optimization levels where it would otherwise not be enabled. - # So we disable it entirely. But since that would mean inconsistency with - # GCC5, which has level 1 depending on optimization level, disable it on - # GCC5 as well, because better safe than sorry. + # Instead of completely disabling this optimization on newer GCC's, + # we'll force them to use level 1 optimization with -flifetime-dse=1. # Add it first so that a mozconfig can override by setting CFLAGS/CXXFLAGS. - CFLAGS="-fno-lifetime-dse $CFLAGS" - CXXFLAGS="-fno-lifetime-dse $CXXFLAGS" + CFLAGS="-flifetime-dse=1 $CFLAGS" + CXXFLAGS="-flifetime-dse=1 $CXXFLAGS" ;; esac fi diff --git a/build/moz.build b/build/moz.build index f25e5cfa5..d96724cad 100644 --- a/build/moz.build +++ b/build/moz.build @@ -30,8 +30,8 @@ if CONFIG['MOZ_PHOENIX']: DEFINES['MOZ_PHOENIX'] = CONFIG['MOZ_PHOENIX'] DEFINES['MOZ_BUILD_APP_IS_BROWSER'] = True -if CONFIG['MC_OFFICAL']: - DEFINES['MC_OFFICAL'] = CONFIG['MC_OFFICAL'] +if CONFIG['MC_OFFICIAL']: + DEFINES['MC_OFFICIAL'] = CONFIG['MC_OFFICIAL'] if CONFIG['MC_BASILISK']: DEFINES['MC_BASILISK'] = CONFIG['MC_BASILISK'] @@ -39,6 +39,9 @@ if CONFIG['MC_BASILISK']: if CONFIG['MC_PALEMOON']: DEFINES['MC_PALEMOON'] = CONFIG['MC_PALEMOON'] +if CONFIG['BINOC_BOREALIS']: + DEFINES['BINOC_BOREALIS'] = CONFIG['BINOC_BOREALIS'] + if CONFIG['MOZ_APP_PROFILE']: DEFINES['MOZ_APP_PROFILE'] = CONFIG['MOZ_APP_PROFILE'] diff --git a/caps/nsNullPrincipalURI.cpp b/caps/nsNullPrincipalURI.cpp index 891a29bd8..f8b867160 100644 --- a/caps/nsNullPrincipalURI.cpp +++ b/caps/nsNullPrincipalURI.cpp @@ -168,6 +168,32 @@ nsNullPrincipalURI::SetPath(const nsACString &aPath) } NS_IMETHODIMP +nsNullPrincipalURI::GetFilePath(nsACString &aFilePath) +{ + aFilePath.Truncate(); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsNullPrincipalURI::SetFilePath(const nsACString &aFilePath) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsNullPrincipalURI::GetQuery(nsACString &aQuery) +{ + aQuery.Truncate(); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsNullPrincipalURI::SetQuery(const nsACString &aQuery) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsNullPrincipalURI::GetRef(nsACString &_ref) { _ref.Truncate(); diff --git a/config/external/icu/data/icudt58l.dat b/config/external/icu/data/icudt58l.dat Binary files differindex d981febb1..946a2c868 100644 --- a/config/external/icu/data/icudt58l.dat +++ b/config/external/icu/data/icudt58l.dat diff --git a/config/external/nss/Makefile.in b/config/external/nss/Makefile.in index 4b95a32bd..861b7d07d 100644 --- a/config/external/nss/Makefile.in +++ b/config/external/nss/Makefile.in @@ -43,17 +43,6 @@ endif # Default HAVE_FREEBL_LIBS = 1 -# 32-bit HP-UX PA-RISC -ifeq ($(OS_ARCH), HP-UX) -ifneq ($(OS_TEST), ia64) -ifndef HAVE_64BIT_BUILD -HAVE_FREEBL_LIBS = -HAVE_FREEBL_LIBS_32INT32 = 1 -HAVE_FREEBL_LIBS_32FPU = 1 -endif -endif -endif - # SunOS SPARC ifeq ($(OS_ARCH), SunOS) ifneq (86,$(findstring 86,$(OS_TEST))) diff --git a/config/milestone.txt b/config/milestone.txt index 27f2d007f..b617f64b7 100644 --- a/config/milestone.txt +++ b/config/milestone.txt @@ -10,4 +10,4 @@ # hardcoded milestones in the tree from these two files. #-------------------------------------------------------- -4.1.1 +4.1.2 diff --git a/config/rules.mk b/config/rules.mk index a6bd45d11..9a8f61c2d 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -386,26 +386,6 @@ endif endif endif -# -# HP-UXBeOS specific section: for COMPONENTS only, add -Bsymbolic flag -# which uses internal symbols first -# -ifeq ($(OS_ARCH),HP-UX) -ifdef IS_COMPONENT -ifeq ($(GNU_CC)$(GNU_CXX),) -EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic -ifneq ($(HAS_EXTRAEXPORTS),1) -MKSHLIB += -Wl,+eNSGetModule -Wl,+eerrno -MKCSHLIB += +eNSGetModule +eerrno -ifneq ($(OS_TEST),ia64) -MKSHLIB += -Wl,+e_shlInit -MKCSHLIB += +e_shlInit -endif # !ia64 -endif # !HAS_EXTRAEXPORTS -endif # non-gnu compilers -endif # IS_COMPONENT -endif # HP-UX - ifeq ($(OS_ARCH),AIX) ifdef IS_COMPONENT ifneq ($(HAS_EXTRAEXPORTS),1) diff --git a/devtools/client/framework/test/browser_toolbox_textbox_context_menu.js b/devtools/client/framework/test/browser_toolbox_textbox_context_menu.js index 2e5f3210e..e2e961255 100644 --- a/devtools/client/framework/test/browser_toolbox_textbox_context_menu.js +++ b/devtools/client/framework/test/browser_toolbox_textbox_context_menu.js @@ -36,15 +36,12 @@ add_task(function* () { is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled"); is(cmdSelectAll.getAttribute("disabled"), "true", "cmdSelectAll is disabled"); - // Cut/Copy items are enabled in context menu even if there - // is no selection. See also Bug 1303033 + // Cut/Copy/Paste items are enabled in context menu even if there + // is no selection. See also Bug 1303033, and 1317322 is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled"); is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled"); - if (isWindows()) { - // emptyClipboard only works on Windows (666254), assert paste only for this OS. - is(cmdPaste.getAttribute("disabled"), "true", "cmdPaste is disabled"); - } + is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); yield cleanup(toolbox); }); diff --git a/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js b/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js index b5dbe4475..b04a247f5 100644 --- a/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js +++ b/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js @@ -45,15 +45,12 @@ add_task(function* () { is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled"); is(cmdSelectAll.getAttribute("disabled"), "true", "cmdSelectAll is disabled"); - // Cut/Copy items are enabled in context menu even if there - // is no selection. See also Bug 1303033 + // Cut/Copy/Paste items are enabled in context menu even if there is no + // selection. See also Bug 1303033, and 1317322 is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled"); is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled"); - if (isWindows()) { - // emptyClipboard only works on Windows (666254), assert paste only for this OS. - is(cmdPaste.getAttribute("disabled"), "true", "cmdPaste is disabled"); - } + is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); info("Closing context menu"); let onContextMenuHidden = once(searchContextMenu, "popuphidden"); diff --git a/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js b/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js index 349f1b9b3..d66df91ab 100644 --- a/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js +++ b/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js @@ -44,15 +44,12 @@ add_task(function* () { is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled"); is(cmdSelectAll.getAttribute("disabled"), "true", "cmdSelectAll is disabled"); - // Cut/Copy items are enabled in context menu even if there - // is no selection. See also Bug 1303033 + // Cut/Copy/Paste items are enabled in context menu even if there is no + // selection. See also Bug 1303033, and 1317322 is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled"); is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled"); - if (isWindows()) { - // emptyClipboard only works on Windows (666254), assert paste only for this OS. - is(cmdPaste.getAttribute("disabled"), "true", "cmdPaste is disabled"); - } + is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); info("Closing context menu"); let onContextMenuHidden = once(searchContextMenu, "popuphidden"); diff --git a/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js b/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js index 137456468..7bd4b5e6f 100644 --- a/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js +++ b/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js @@ -43,14 +43,11 @@ add_task(function* () { is(cmdSelectAll.getAttribute("disabled"), "true", "cmdSelectAll is disabled"); // Cut/Copy items are enabled in context menu even if there - // is no selection. See also Bug 1303033 + // is no selection. See also Bug 1303033, and 1317322 is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled"); is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled"); - if (isWindows()) { - // emptyClipboard only works on Windows (666254), assert paste only for this OS. - is(cmdPaste.getAttribute("disabled"), "true", "cmdPaste is disabled"); - } + is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); info("Closing context menu"); let onContextMenuHidden = once(searchContextMenu, "popuphidden"); diff --git a/devtools/client/webconsole/webconsole.xul b/devtools/client/webconsole/webconsole.xul index cd3e44d82..1310fb57d 100644 --- a/devtools/client/webconsole/webconsole.xul +++ b/devtools/client/webconsole/webconsole.xul @@ -7,6 +7,8 @@ %webConsoleDTD; ]> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="resource://devtools/client/themes/common.css" + type="text/css"?> <?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?> <?xml-stylesheet href="chrome://devtools/skin/webconsole.css" diff --git a/docshell/base/nsDSURIContentListener.cpp b/docshell/base/nsDSURIContentListener.cpp index 93ce3cb26..ee6a4dd62 100644 --- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -17,6 +17,7 @@ #include "nsIHttpChannel.h" #include "nsIScriptSecurityManager.h" #include "nsError.h" +#include "nsContentSecurityManager.h" #include "nsCharSeparatedTokenizer.h" #include "nsIConsoleService.h" #include "nsIScriptError.h" @@ -93,6 +94,14 @@ nsDSURIContentListener::DoContent(const nsACString& aContentType, if (aOpenedChannel) { aOpenedChannel->GetLoadFlags(&loadFlags); + + // block top-level data URI navigations if triggered by the web + if (!nsContentSecurityManager::AllowTopLevelNavigationToDataURI(aOpenedChannel)) { + // logging to console happens within AllowTopLevelNavigationToDataURI + aRequest->Cancel(NS_ERROR_DOM_BAD_URI); + *aAbortProcess = true; + return NS_OK; + } } if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) { diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 58c182cbb..bd2a8a433 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -42,6 +42,7 @@ #include "nsArray.h" #include "nsArrayUtils.h" +#include "nsContentSecurityManager.h" #include "nsICaptivePortalService.h" #include "nsIDOMStorage.h" #include "nsIContentViewer.h" @@ -138,6 +139,7 @@ #include "nsISiteSecurityService.h" #include "nsStructuredCloneContainer.h" #include "nsIStructuredCloneContainer.h" +#include "nsISupportsPrimitives.h" #ifdef MOZ_PLACES #include "nsIFaviconService.h" #include "mozIPlacesPendingOperation.h" @@ -1272,6 +1274,7 @@ nsDocShell::LoadURI(nsIURI* aURI, nsCOMPtr<nsISHEntry> shEntry; nsXPIDLString target; nsAutoString srcdoc; + bool forceAllowDataURI = false; nsCOMPtr<nsIDocShell> sourceDocShell; nsCOMPtr<nsIURI> baseURI; @@ -1307,6 +1310,7 @@ nsDocShell::LoadURI(nsIURI* aURI, aLoadInfo->GetSrcdocData(srcdoc); aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell)); aLoadInfo->GetBaseURI(getter_AddRefs(baseURI)); + aLoadInfo->GetForceAllowDataURI(&forceAllowDataURI); } #if defined(DEBUG) @@ -1560,6 +1564,10 @@ nsDocShell::LoadURI(nsIURI* aURI, flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC; } + if (forceAllowDataURI) { + flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI; + } + return InternalLoad(aURI, originalURI, loadReplace, @@ -4821,6 +4829,9 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI, } nsAutoPopupStatePusher statePusher(popupState); + bool forceAllowDataURI = + aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_DATA_URI; + // Don't pass certain flags that aren't needed and end up confusing // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are // passed to LoadURI though, since it uses them. @@ -4850,6 +4861,7 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI, loadInfo->SetReferrerPolicy(aReferrerPolicy); loadInfo->SetHeadersStream(aHeaderStream); loadInfo->SetBaseURI(aBaseURI); + loadInfo->SetForceAllowDataURI(forceAllowDataURI); if (fixupInfo) { nsAutoString searchProvider, keyword; @@ -9884,49 +9896,49 @@ nsDocShell::InternalLoad(nsIURI* aURI, contentType = nsIContentPolicy::TYPE_DOCUMENT; } - // If there's no targetDocShell, that means we are about to create a new window, - // perform a content policy check before creating the window. - if (!targetDocShell) { - nsCOMPtr<Element> requestingElement; + // If there's no targetDocShell, that means we are about to create a new + // window (or aWindowTarget is empty). Perform a content policy check before + // creating the window. Please note for all other docshell loads + // content policy checks are performed within the contentSecurityManager + // when the channel is about to be openend. + if (!targetDocShell && !aWindowTarget.IsEmpty()) { + MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT, + "opening a new window requires type to be TYPE_DOCUMENT"); + nsISupports* requestingContext = nullptr; - if (contentType == nsIContentPolicy::TYPE_DOCUMENT) { - if (XRE_IsContentProcess()) { - // In e10s the child process doesn't have access to the element that - // contains the browsing context (because that element is in the chrome - // process). So we just pass mScriptGlobal. - requestingContext = ToSupports(mScriptGlobal); - } else { - // This is for loading non-e10s tabs and toplevel windows of various - // sorts. - // For the toplevel window cases, requestingElement will be null. - requestingElement = mScriptGlobal->AsOuter()->GetFrameElementInternal(); - requestingContext = requestingElement; - } + if (XRE_IsContentProcess()) { + // In e10s the child process doesn't have access to the element that + // contains the browsing context (because that element is in the chrome + // process). So we just pass mScriptGlobal. + requestingContext = ToSupports(mScriptGlobal); } else { - requestingElement = mScriptGlobal->AsOuter()->GetFrameElementInternal(); + // This is for loading non-e10s tabs and toplevel windows of various + // sorts. + // For the toplevel window cases, requestingElement will be null. + nsCOMPtr<Element> requestingElement = + mScriptGlobal->AsOuter()->GetFrameElementInternal(); requestingContext = requestingElement; - -#ifdef DEBUG - if (requestingElement) { - // Get the docshell type for requestingElement. - nsCOMPtr<nsIDocument> requestingDoc = requestingElement->OwnerDoc(); - nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell(); - - // requestingElement docshell type = current docshell type. - MOZ_ASSERT(mItemType == elementDocShell->ItemType(), - "subframes should have the same docshell type as their parent"); - } -#endif } + // Since Content Policy checks are performed within docShell as well as + // the ContentSecurityManager we need a reliable way to let certain + // nsIContentPolicy consumers ignore duplicate calls. Let's use the 'extra' + // argument to pass a specific identifier. + nsCOMPtr<nsISupportsString> extraStr = + do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + NS_NAMED_LITERAL_STRING(msg, "conPolCheckFromDocShell"); + rv = extraStr->SetData(msg); + NS_ENSURE_SUCCESS(rv, rv); + int16_t shouldLoad = nsIContentPolicy::ACCEPT; rv = NS_CheckContentLoadPolicy(contentType, aURI, aTriggeringPrincipal, requestingContext, EmptyCString(), // mime guess - nullptr, // extra + extraStr, // extra &shouldLoad); if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { @@ -10082,6 +10094,7 @@ nsDocShell::InternalLoad(nsIURI* aURI, // principal to inherit is: it should be aTriggeringPrincipal. loadInfo->SetPrincipalIsExplicit(true); loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(LOAD_LINK)); + loadInfo->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI); rv = win->Open(NS_ConvertUTF8toUTF16(spec), aWindowTarget, // window name @@ -10232,8 +10245,11 @@ nsDocShell::InternalLoad(nsIURI* aURI, } } + bool loadFromExternal = false; + // Before going any further vet loads initiated by external programs. if (aLoadType == LOAD_NORMAL_EXTERNAL) { + loadFromExternal = true; // Disallow external chrome: loads targetted at content windows bool isChrome = false; if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) { @@ -10724,7 +10740,9 @@ nsDocShell::InternalLoad(nsIURI* aURI, nsINetworkPredictor::PREDICT_LOAD, this, nullptr); nsCOMPtr<nsIRequest> req; - rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, aReferrer, + rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, loadFromExternal, + (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI), + aReferrer, !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), aReferrerPolicy, aTriggeringPrincipal, principalToInherit, aTypeHint, @@ -10804,6 +10822,8 @@ nsresult nsDocShell::DoURILoad(nsIURI* aURI, nsIURI* aOriginalURI, bool aLoadReplace, + bool aLoadFromExternal, + bool aForceAllowDataURI, nsIURI* aReferrerURI, bool aSendReferrer, uint32_t aReferrerPolicy, @@ -10880,17 +10900,40 @@ nsDocShell::DoURILoad(nsIURI* aURI, nsCOMPtr<nsINode> loadingNode; nsCOMPtr<nsPIDOMWindowOuter> loadingWindow; nsCOMPtr<nsIPrincipal> loadingPrincipal; + nsCOMPtr<nsISupports> topLevelLoadingContext; if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) { loadingNode = nullptr; loadingPrincipal = nullptr; loadingWindow = mScriptGlobal->AsOuter(); + if (XRE_IsContentProcess()) { + // In e10s the child process doesn't have access to the element that + // contains the browsing context (because that element is in the chrome + // process). + nsCOMPtr<nsITabChild> tabChild = GetTabChild(); + topLevelLoadingContext = ToSupports(tabChild); + } else { + // This is for loading non-e10s tabs and toplevel windows of various + // sorts. + // For the toplevel window cases, requestingElement will be null. + nsCOMPtr<Element> requestingElement = + loadingWindow->GetFrameElementInternal(); + topLevelLoadingContext = requestingElement; + } } else { loadingWindow = nullptr; loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal(); if (loadingNode) { // If we have a loading node, then use that as our loadingPrincipal. loadingPrincipal = loadingNode->NodePrincipal(); +#ifdef DEBUG + // Get the docshell type for requestingElement. + nsCOMPtr<nsIDocument> requestingDoc = loadingNode->OwnerDoc(); + nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell(); + // requestingElement docshell type = current docshell type. + MOZ_ASSERT(mItemType == elementDocShell->ItemType(), + "subframes should have the same docshell type as their parent"); +#endif } else { // If this isn't a top-level load and mScriptGlobal's frame element is // null, then the element got removed from the DOM while we were trying @@ -10940,7 +10983,7 @@ nsDocShell::DoURILoad(nsIURI* aURI, nsCOMPtr<nsILoadInfo> loadInfo = (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ? - new LoadInfo(loadingWindow, aTriggeringPrincipal, + new LoadInfo(loadingWindow, aTriggeringPrincipal, topLevelLoadingContext, securityFlags) : new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode, securityFlags, aContentPolicyType); @@ -10948,6 +10991,8 @@ nsDocShell::DoURILoad(nsIURI* aURI, if (aPrincipalToInherit) { loadInfo->SetPrincipalToInherit(aPrincipalToInherit); } + loadInfo->SetLoadTriggeredFromExternal(aLoadFromExternal); + loadInfo->SetForceAllowDataURI(aForceAllowDataURI); // We have to do this in case our OriginAttributes are different from the // OriginAttributes of the parent document. Or in case there isn't a diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 3ca9e0b34..63a4e3358 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -369,6 +369,8 @@ protected: nsresult DoURILoad(nsIURI* aURI, nsIURI* aOriginalURI, bool aLoadReplace, + bool aLoadFromExternal, + bool aForceAllowDataURI, nsIURI* aReferrer, bool aSendReferrer, uint32_t aReferrerPolicy, diff --git a/docshell/base/nsDocShellLoadInfo.cpp b/docshell/base/nsDocShellLoadInfo.cpp index 7d0034b04..b00e8e360 100644 --- a/docshell/base/nsDocShellLoadInfo.cpp +++ b/docshell/base/nsDocShellLoadInfo.cpp @@ -15,6 +15,7 @@ nsDocShellLoadInfo::nsDocShellLoadInfo() : mLoadReplace(false) , mInheritPrincipal(false) , mPrincipalIsExplicit(false) + , mForceAllowDataURI(false) , mSendReferrer(true) , mReferrerPolicy(mozilla::net::RP_Default) , mLoadType(nsIDocShellLoadInfo::loadNormal) @@ -127,6 +128,20 @@ nsDocShellLoadInfo::SetPrincipalIsExplicit(bool aPrincipalIsExplicit) } NS_IMETHODIMP +nsDocShellLoadInfo::GetForceAllowDataURI(bool* aForceAllowDataURI) +{ + *aForceAllowDataURI = mForceAllowDataURI; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellLoadInfo::SetForceAllowDataURI(bool aForceAllowDataURI) +{ + mForceAllowDataURI = aForceAllowDataURI; + return NS_OK; +} + +NS_IMETHODIMP nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType* aLoadType) { NS_ENSURE_ARG_POINTER(aLoadType); diff --git a/docshell/base/nsDocShellLoadInfo.h b/docshell/base/nsDocShellLoadInfo.h index b7eaed832..f3ddcca1e 100644 --- a/docshell/base/nsDocShellLoadInfo.h +++ b/docshell/base/nsDocShellLoadInfo.h @@ -37,6 +37,7 @@ protected: bool mLoadReplace; bool mInheritPrincipal; bool mPrincipalIsExplicit; + bool mForceAllowDataURI; bool mSendReferrer; nsDocShellInfoReferrerPolicy mReferrerPolicy; nsDocShellInfoLoadType mLoadType; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 8261c45dc..e34e6adfd 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -116,6 +116,9 @@ interface nsIDocShell : nsIDocShellTreeItem const long INTERNAL_LOAD_FLAGS_NO_OPENER = 0x100; + // Whether a top-level data URI navigation is allowed for that load + const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI = 0x200; + // NB: 0x80 is available. /** diff --git a/docshell/base/nsIDocShellLoadInfo.idl b/docshell/base/nsIDocShellLoadInfo.idl index 113c0a4c1..8804f63a3 100644 --- a/docshell/base/nsIDocShellLoadInfo.idl +++ b/docshell/base/nsIDocShellLoadInfo.idl @@ -55,6 +55,12 @@ interface nsIDocShellLoadInfo : nsISupports */ attribute boolean principalIsExplicit; + /** + * If this attribute is true, then a top-level navigation + * to a data URI will be allowed. + */ + attribute boolean forceAllowDataURI; + /* these are load type enums... */ const long loadNormal = 0; // Normal Load const long loadNormalReplace = 1; // Normal Load but replaces current history slot diff --git a/docshell/base/nsIWebNavigation.idl b/docshell/base/nsIWebNavigation.idl index 042b1c547..241d0731c 100644 --- a/docshell/base/nsIWebNavigation.idl +++ b/docshell/base/nsIWebNavigation.idl @@ -206,6 +206,12 @@ interface nsIWebNavigation : nsISupports const unsigned long LOAD_FLAGS_FIXUP_SCHEME_TYPOS = 0x200000; /** + * Allows a top-level data: navigation to occur. E.g. view-image + * is an explicit user action which should be allowed. + */ + const unsigned long LOAD_FLAGS_FORCE_ALLOW_DATA_URI = 0x400000; + + /** * Loads a given URI. This will give priority to loading the requested URI * in the object implementing this interface. If it can't be loaded here * however, the URI dispatcher will go through its normal process of content diff --git a/docshell/test/navigation/file_contentpolicy_block_window.html b/docshell/test/navigation/file_contentpolicy_block_window.html new file mode 100644 index 000000000..c51e574e5 --- /dev/null +++ b/docshell/test/navigation/file_contentpolicy_block_window.html @@ -0,0 +1,5 @@ +<html> +<body> +This window should never be openend! +</body> +</html> diff --git a/docshell/test/navigation/mochitest.ini b/docshell/test/navigation/mochitest.ini index 0c35cf352..764e400a8 100644 --- a/docshell/test/navigation/mochitest.ini +++ b/docshell/test/navigation/mochitest.ini @@ -36,6 +36,7 @@ support-files = file_bug1300461_redirect.html file_bug1300461_redirect.html^headers^ file_bug1300461_back.html + file_contentpolicy_block_window.html [test_bug13871.html] [test_bug270414.html] @@ -62,3 +63,4 @@ skip-if = toolkit == 'android' #RANDOM [test_triggeringprincipal_window_open.html] [test_triggeringprincipal_parent_iframe_window_open.html] [test_triggeringprincipal_iframe_iframe_window_open.html] +[test_contentpolicy_block_window.html] diff --git a/docshell/test/navigation/test_contentpolicy_block_window.html b/docshell/test/navigation/test_contentpolicy_block_window.html new file mode 100644 index 000000000..651be825c --- /dev/null +++ b/docshell/test/navigation/test_contentpolicy_block_window.html @@ -0,0 +1,96 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1329288 +--> +<head> + <title>Test for Bug 1329288</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1329288">Mozilla Bug 1329288</a> + + +<!-- have a testlink which we can use for the test to open a new window --> +<a href="http://test1.example.org/tests/docshell/test/navigation/file_contentpolicy_block_window.html" + target="_blank" + id="testlink">This is a link</a> + +<script class="testbody" type="text/javascript"> +/* + * Description of the test: + * The test tries to open a new window and makes sure that a registered contentPolicy + * gets called with the right (a non null) 'context' for the TYPE_DOCUMENT load. + */ + +const Cc = SpecialPowers.Cc; +const Ci = SpecialPowers.Ci; + +var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager); +var componentManager = SpecialPowers.wrap(SpecialPowers.Components).manager + .QueryInterface(Ci.nsIComponentRegistrar); + +// Content policy / factory implementation for the test +var policyID = SpecialPowers.wrap(SpecialPowers.Components).ID("{b80e19d0-878f-d41b-2654-194714a4115c}"); +var policyName = "@mozilla.org/testpolicy;1"; +var policy = { + // nsISupports implementation + QueryInterface: function(iid) { + iid = SpecialPowers.wrap(iid); + if (iid.equals(Ci.nsISupports) || + iid.equals(Ci.nsIFactory) || + iid.equals(Ci.nsIContentPolicy)) + return this; + throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE; + }, + + // nsIFactory implementation + createInstance: function(outer, iid) { + return this.QueryInterface(iid); + }, + + // nsIContentPolicy implementation + shouldLoad: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) { + + if (SpecialPowers.wrap(contentLocation).spec !== document.getElementById("testlink").href) { + // not the URI we are looking for, allow the load + return Ci.nsIContentPolicy.ACCEPT; + } + + is(contentType, Ci.nsIContentPolicy.TYPE_DOCUMENT, + "needs to be type document load"); + ok(context, "context is not allowed to be null"); + ok(context.name.endsWith("test_contentpolicy_block_window.html"), + "context should be the current window"); + + // remove the policy and finish test. + categoryManager.deleteCategoryEntry("content-policy", policyName, false); + + setTimeout(function() { + // Component must be unregistered delayed, otherwise other content + // policy will not be removed from the category correctly + componentManager.unregisterFactory(policyID, policy); + }, 0); + + SimpleTest.finish(); + return Ci.nsIContentPolicy.REJECT_REQUEST; + }, + + shouldProcess: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) { + return Ci.nsIContentPolicy.ACCEPT; + } +} + +policy = SpecialPowers.wrapCallbackObject(policy); +componentManager.registerFactory(policyID, "Test content policy", policyName, policy); +categoryManager.addCategoryEntry("content-policy", policyName, policyName, false, true); + +SimpleTest.waitForExplicitFinish(); + +// now everything is set up, let's start the test +document.getElementById("testlink").click() + +</script> +</body> +</html> diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 9ced64c0d..092755590 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -183,6 +183,12 @@ Element::DoGetClasses() const NS_IMETHODIMP Element::QueryInterface(REFNSIID aIID, void** aInstancePtr) { + if (aIID.Equals(NS_GET_IID(Element))) { + NS_ADDREF_THIS(); + *aInstancePtr = this; + return NS_OK; + } + NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!"); nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr); @@ -1838,6 +1844,24 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) SetParentIsContent(false); } +#ifdef DEBUG + // If we can get access to the PresContext, then we sanity-check that + // we're not leaving behind a pointer to ourselves as the PresContext's + // cached provider of the viewport's scrollbar styles. + if (document) { + nsIPresShell* presShell = document->GetShell(); + if (presShell) { + nsPresContext* presContext = presShell->GetPresContext(); + if (presContext) { + MOZ_ASSERT(this != + presContext->GetViewportScrollbarStylesOverrideNode(), + "Leaving behind a raw pointer to this node (as having " + "propagated scrollbar styles) - that's dangerous..."); + } + } + } +#endif + // Ensure that CSS transitions don't continue on an element at a // different place in the tree (even if reinserted before next // animation refresh). diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 79f6cff51..b22a0d4ff 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -1937,7 +1937,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN(FragmentOrElement) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(FragmentOrElement) - NS_INTERFACE_MAP_ENTRY(Element) NS_INTERFACE_MAP_ENTRY(nsIContent) NS_INTERFACE_MAP_ENTRY(nsINode) NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) diff --git a/dom/base/IdleRequest.cpp b/dom/base/IdleRequest.cpp index 26190f98b..fb3983d37 100644 --- a/dom/base/IdleRequest.cpp +++ b/dom/base/IdleRequest.cpp @@ -9,7 +9,6 @@ #include "mozilla/Function.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/IdleDeadline.h" -#include "mozilla/dom/Performance.h" #include "mozilla/dom/PerformanceTiming.h" #include "mozilla/dom/WindowBinding.h" #include "nsComponentManagerUtils.h" @@ -20,138 +19,56 @@ namespace mozilla { namespace dom { -IdleRequest::IdleRequest(JSContext* aCx, nsPIDOMWindowInner* aWindow, - IdleRequestCallback& aCallback, uint32_t aHandle) - : mWindow(aWindow) - , mCallback(&aCallback) +IdleRequest::IdleRequest(IdleRequestCallback* aCallback, uint32_t aHandle) + : mCallback(aCallback) , mHandle(aHandle) , mTimeoutHandle(Nothing()) { - MOZ_ASSERT(aWindow); - - // Get the calling location. - nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn); + MOZ_DIAGNOSTIC_ASSERT(mCallback); } IdleRequest::~IdleRequest() { } -NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequest) +NS_IMPL_CYCLE_COLLECTION(IdleRequest, mCallback) NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequest) NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequest) -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequest) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback) -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequest) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequest) - NS_INTERFACE_MAP_ENTRY(nsIRunnable) - NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable) - NS_INTERFACE_MAP_ENTRY(nsIIncrementalRunnable) - NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimeoutHandler) NS_INTERFACE_MAP_END -nsresult -IdleRequest::SetTimeout(uint32_t aTimeout) -{ - int32_t handle; - nsresult rv = nsGlobalWindow::Cast(mWindow)->SetTimeoutOrInterval( - this, aTimeout, false, Timeout::Reason::eIdleCallbackTimeout, &handle); - mTimeoutHandle = Some(handle); - - return rv; -} - -nsresult -IdleRequest::Run() -{ - if (mCallback) { - RunIdleRequestCallback(false); - } - - return NS_OK; -} - -nsresult -IdleRequest::Cancel() +void +IdleRequest::SetTimeoutHandle(int32_t aHandle) { - mCallback = nullptr; - CancelTimeout(); - if (isInList()) { - remove(); - } - Release(); - - return NS_OK; + mTimeoutHandle = Some(aHandle); } -void -IdleRequest::SetDeadline(TimeStamp aDeadline) +uint32_t +IdleRequest::GetTimeoutHandle() const { - mozilla::dom::Performance* perf = mWindow->GetPerformance(); - mDeadline = - perf ? perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline) : 0.0; + MOZ_DIAGNOSTIC_ASSERT(mTimeoutHandle.isSome()); + return mTimeoutHandle.value(); } nsresult -IdleRequest::RunIdleRequestCallback(bool aDidTimeout) +IdleRequest::IdleRun(nsPIDOMWindowInner* aWindow, + DOMHighResTimeStamp aDeadline, + bool aDidTimeout) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_DIAGNOSTIC_ASSERT(mCallback); - if (!aDidTimeout) { - CancelTimeout(); - } - - remove(); ErrorResult error; RefPtr<IdleDeadline> deadline = - new IdleDeadline(mWindow, aDidTimeout, mDeadline); + new IdleDeadline(aWindow, aDidTimeout, aDeadline); mCallback->Call(*deadline, error, "requestIdleCallback handler"); - mCallback = nullptr; - Release(); + mCallback = nullptr; + error.SuppressException(); return error.StealNSResult(); } -void -IdleRequest::CancelTimeout() -{ - if (mTimeoutHandle.isSome()) { - nsGlobalWindow::Cast(mWindow)->ClearTimeoutOrInterval( - mTimeoutHandle.value(), Timeout::Reason::eIdleCallbackTimeout); - } -} - -nsresult -IdleRequest::Call() -{ - SetDeadline(TimeStamp::Now()); - return RunIdleRequestCallback(true); -} - -void -IdleRequest::GetLocation(const char** aFileName, uint32_t* aLineNo, - uint32_t* aColumn) -{ - *aFileName = mFileName.get(); - *aLineNo = mLineNo; - *aColumn = mColumn; -} - -void -IdleRequest::MarkForCC() -{ - mCallback->MarkForCC(); -} - } // namespace dom } // namespace mozilla diff --git a/dom/base/IdleRequest.h b/dom/base/IdleRequest.h index cb234430a..acf56f852 100644 --- a/dom/base/IdleRequest.h +++ b/dom/base/IdleRequest.h @@ -12,7 +12,6 @@ #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsDOMNavigationTiming.h" -#include "nsITimeoutHandler.h" class nsPIDOMWindowInner; @@ -21,28 +20,19 @@ namespace dom { class IdleRequestCallback; -class IdleRequest final : public nsITimeoutHandler - , public nsIRunnable - , public nsICancelableRunnable - , public nsIIncrementalRunnable - , public LinkedListElement<IdleRequest> +class IdleRequest final : public nsISupports, + public LinkedListElement<IdleRequest> { public: - IdleRequest(JSContext* aCx, nsPIDOMWindowInner* aWindow, - IdleRequestCallback& aCallback, uint32_t aHandle); + IdleRequest(IdleRequestCallback* aCallback, uint32_t aHandle); - virtual nsresult Call() override; - virtual void GetLocation(const char** aFileName, uint32_t* aLineNo, - uint32_t* aColumn) override; - virtual void MarkForCC() override; + nsresult IdleRun(nsPIDOMWindowInner* aWindow, + DOMHighResTimeStamp aDeadline, + bool aDidTimeout); - nsresult SetTimeout(uint32_t aTimout); - nsresult RunIdleRequestCallback(bool aDidTimeout); - void CancelTimeout(); - - NS_DECL_NSIRUNNABLE; - virtual nsresult Cancel() override; - virtual void SetDeadline(mozilla::TimeStamp aDeadline) override; + void SetTimeoutHandle(int32_t aHandle); + bool HasTimeout() const { return mTimeoutHandle.isSome(); } + uint32_t GetTimeoutHandle() const; uint32_t Handle() const { @@ -50,22 +40,14 @@ public: } NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequest, nsITimeoutHandler) + NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequest) private: ~IdleRequest(); - // filename, line number and JS language version string of the - // caller of setTimeout() - nsCString mFileName; - uint32_t mLineNo; - uint32_t mColumn; - - nsCOMPtr<nsPIDOMWindowInner> mWindow; RefPtr<IdleRequestCallback> mCallback; - uint32_t mHandle; + const uint32_t mHandle; mozilla::Maybe<int32_t> mTimeoutHandle; - DOMHighResTimeStamp mDeadline; }; } // namespace dom diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp index e3b614931..b6b95aaa6 100644 --- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -577,19 +577,17 @@ Location::GetPathname(nsAString& aPathname) aPathname.Truncate(); nsCOMPtr<nsIURI> uri; - nsresult result = NS_OK; + nsresult result = GetURI(getter_AddRefs(uri)); + if (NS_FAILED(result) || !uri) { + return result; + } - result = GetURI(getter_AddRefs(uri)); + nsAutoCString file; - nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(uri)); - if (url) { - nsAutoCString file; + result = uri->GetFilePath(file); - result = url->GetFilePath(file); - - if (NS_SUCCEEDED(result)) { - AppendUTF8toUTF16(file, aPathname); - } + if (NS_SUCCEEDED(result)) { + AppendUTF8toUTF16(file, aPathname); } return result; @@ -604,8 +602,7 @@ Location::SetPathname(const nsAString& aPathname) return rv; } - nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(uri)); - if (url && NS_SUCCEEDED(url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)))) { + if (NS_SUCCEEDED(uri->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)))) { return SetURI(uri); } diff --git a/dom/base/Timeout.h b/dom/base/Timeout.h index e929f3dd1..42e2f57f5 100644 --- a/dom/base/Timeout.h +++ b/dom/base/Timeout.h @@ -41,7 +41,11 @@ public: // default main thread being used. nsresult InitTimer(nsIEventTarget* aTarget, uint32_t aDelay); - enum class Reason { eTimeoutOrInterval, eIdleCallbackTimeout }; + enum class Reason + { + eTimeoutOrInterval, + eIdleCallbackTimeout, + }; #ifdef DEBUG bool HasRefCntOne() const; @@ -62,6 +66,8 @@ public: // True if this is a repeating/interval timer bool mIsInterval; + // Used to allow several reasons for setting a timeout, where each + // 'Reason' value is using a possibly overlapping set of id:s. Reason mReason; // Returned as value of setTimeout() diff --git a/dom/base/TimeoutHandler.cpp b/dom/base/TimeoutHandler.cpp new file mode 100644 index 000000000..78c3f16dd --- /dev/null +++ b/dom/base/TimeoutHandler.cpp @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "TimeoutHandler.h" + +namespace mozilla { +namespace dom { + +TimeoutHandler::TimeoutHandler(JSContext* aCx) + : TimeoutHandler() +{ + nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn); +} + +nsresult +TimeoutHandler::Call() +{ + return NS_OK; +} + +void +TimeoutHandler::GetLocation(const char** aFileName, uint32_t* aLineNo, + uint32_t* aColumn) +{ + *aFileName = mFileName.get(); + *aLineNo = mLineNo; + *aColumn = mColumn; +} + +NS_IMPL_CYCLE_COLLECTION_0(TimeoutHandler) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(TimeoutHandler) +NS_IMPL_CYCLE_COLLECTING_RELEASE(TimeoutHandler) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TimeoutHandler) + NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler) +NS_INTERFACE_MAP_END + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/TimeoutHandler.h b/dom/base/TimeoutHandler.h new file mode 100644 index 000000000..cb0a0ce94 --- /dev/null +++ b/dom/base/TimeoutHandler.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#ifndef mozilla_dom_timeout_handler_h +#define mozilla_dom_timeout_handler_h + +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsITimeoutHandler.h" + +namespace mozilla { +namespace dom { + +/** + * Utility class for implementing nsITimeoutHandlers, designed to be subclassed. + */ +class TimeoutHandler : public nsITimeoutHandler +{ +public: + // TimeoutHandler doesn't actually contain cycles, but subclasses + // probably will. + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(TimeoutHandler) + + virtual nsresult Call() override; + virtual void GetLocation(const char** aFileName, uint32_t* aLineNo, + uint32_t* aColumn) override; + virtual void MarkForCC() override {} +protected: + TimeoutHandler() : mFileName(""), mLineNo(0), mColumn(0) {} + explicit TimeoutHandler(JSContext *aCx); + + virtual ~TimeoutHandler() {} +private: + TimeoutHandler(const TimeoutHandler&) = delete; + TimeoutHandler& operator=(const TimeoutHandler&) = delete; + TimeoutHandler& operator=(const TimeoutHandler&&) = delete; + + nsCString mFileName; + uint32_t mLineNo; + uint32_t mColumn; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_timeout_handler_h diff --git a/dom/base/moz.build b/dom/base/moz.build index 0fb345d22..76c765b1c 100755 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -217,6 +217,7 @@ EXPORTS.mozilla.dom += [ 'TabGroup.h', 'Text.h', 'Timeout.h', + 'TimeoutHandler.h', 'TreeWalker.h', 'WebKitCSSMatrix.h', 'WebSocket.h', @@ -364,6 +365,7 @@ UNIFIED_SOURCES += [ 'TextInputProcessor.cpp', 'ThirdPartyUtil.cpp', 'Timeout.cpp', + 'TimeoutHandler.cpp', 'TimerClamping.cpp', 'TreeWalker.cpp', 'WebKitCSSMatrix.cpp', diff --git a/dom/base/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp index 337debcea..5511b9086 100644 --- a/dom/base/nsContentPolicy.cpp +++ b/dom/base/nsContentPolicy.cpp @@ -20,6 +20,7 @@ #include "nsIDOMElement.h" #include "nsIDOMNode.h" #include "nsIDOMWindow.h" +#include "nsITabChild.h" #include "nsIContent.h" #include "nsILoadContext.h" #include "nsCOMArray.h" @@ -89,8 +90,9 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, { nsCOMPtr<nsIDOMNode> node(do_QueryInterface(requestingContext)); nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(requestingContext)); - NS_ASSERTION(!requestingContext || node || window, - "Context should be a DOM node or a DOM window!"); + nsCOMPtr<nsITabChild> tabChild(do_QueryInterface(requestingContext)); + NS_ASSERTION(!requestingContext || node || window || tabChild, + "Context should be a DOM node, DOM window or a tabChild!"); } #endif diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index eaea49b02..fd3b52948 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -2054,10 +2054,17 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup, mFirstChild = content->GetNextSibling(); } mChildren.RemoveChildAt(i); + if (content == mCachedRootElement) { + // Immediately clear mCachedRootElement, now that it's been removed + // from mChildren, so that GetRootElement() will stop returning this + // now-stale value. + mCachedRootElement = nullptr; + } nsNodeUtils::ContentRemoved(this, content, i, previousSibling); content->UnbindFromTree(); } - mCachedRootElement = nullptr; + MOZ_ASSERT(!mCachedRootElement, + "After removing all children, there should be no root elem"); } mInUnlinkOrDeletion = oldVal; @@ -3913,8 +3920,18 @@ nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify) DestroyElementMaps(); } - doRemoveChildAt(aIndex, aNotify, oldKid, mChildren); + // Preemptively clear mCachedRootElement, since we may be about to remove it + // from our child list, and we don't want to return this maybe-obsolete value + // from any GetRootElement() calls that happen inside of doRemoveChildAt(). + // (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any + // GetRootElement() calls until after it's removed the child from mChildren. + // Any call before that point would restore this soon-to-be-obsolete cached + // answer, and our clearing here would be fruitless.) mCachedRootElement = nullptr; + doRemoveChildAt(aIndex, aNotify, oldKid, mChildren); + MOZ_ASSERT(mCachedRootElement != oldKid, + "Stale pointer in mCachedRootElement, after we tried to clear it " + "(maybe somebody called GetRootElement() too early?)"); } void @@ -12846,3 +12863,19 @@ nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions, return is; } + +Selection* +nsIDocument::GetSelection(ErrorResult& aRv) +{ + nsCOMPtr<nsPIDOMWindowInner> window = GetInnerWindow(); + if (!window) { + return nullptr; + } + + NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!"); + if (!window->IsCurrentInnerWindow()) { + return nullptr; + } + + return nsGlobalWindow::Cast(window)->GetSelection(aRv); +} diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index f784031f6..3d5c44a78 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -23,6 +23,7 @@ #include "mozilla/dom/StorageEvent.h" #include "mozilla/dom/StorageEventBinding.h" #include "mozilla/dom/Timeout.h" +#include "mozilla/dom/TimeoutHandler.h" #include "mozilla/IntegerPrintfMacros.h" #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) #include "mozilla/dom/WindowOrientationObserver.h" @@ -552,29 +553,284 @@ DialogValueHolder::Get(JSContext* aCx, JS::Handle<JSObject*> aScope, } } +class IdleRequestExecutor final : public nsIRunnable + , public nsICancelableRunnable + , public nsIIncrementalRunnable +{ +public: + explicit IdleRequestExecutor(nsGlobalWindow* aWindow) + : mDispatched(false) + , mDeadline(TimeStamp::Now()) + , mWindow(aWindow) + { + MOZ_DIAGNOSTIC_ASSERT(mWindow); + MOZ_DIAGNOSTIC_ASSERT(mWindow->IsInnerWindow()); + } + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable) + + NS_DECL_NSIRUNNABLE + nsresult Cancel() override; + void SetDeadline(TimeStamp aDeadline) override; + + void MaybeDispatch(); +private: + ~IdleRequestExecutor() {} + + bool mDispatched; + TimeStamp mDeadline; + RefPtr<nsGlobalWindow> mWindow; +}; + +NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequestExecutor) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor) +NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequestExecutor) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequestExecutor) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor) + NS_INTERFACE_MAP_ENTRY(nsIRunnable) + NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable) + NS_INTERFACE_MAP_ENTRY(nsIIncrementalRunnable) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable) +NS_INTERFACE_MAP_END + +NS_IMETHODIMP +IdleRequestExecutor::Run() +{ + MOZ_ASSERT(NS_IsMainThread()); + + mDispatched = false; + if (mWindow) { + return mWindow->ExecuteIdleRequest(mDeadline); + } + + return NS_OK; +} + +nsresult +IdleRequestExecutor::Cancel() +{ + MOZ_ASSERT(NS_IsMainThread()); + + mWindow = nullptr; + return NS_OK; +} + void -nsGlobalWindow::PostThrottledIdleCallback() +IdleRequestExecutor::SetDeadline(TimeStamp aDeadline) { - AssertIsOnMainThread(); + MOZ_ASSERT(NS_IsMainThread()); - if (mThrottledIdleRequestCallbacks.isEmpty()) + if (!mWindow) { return; + } + + mDeadline = aDeadline; +} - RefPtr<IdleRequest> request(mThrottledIdleRequestCallbacks.popFirst()); - // ownership transferred from mThrottledIdleRequestCallbacks to - // mIdleRequestCallbacks - mIdleRequestCallbacks.insertBack(request); +void +IdleRequestExecutor::MaybeDispatch() +{ + // If we've already dispatched the executor we don't want to do it + // again. Also, if we've called IdleRequestExecutor::Cancel mWindow + // will be null, which indicates that we shouldn't dispatch this + // executor either. + if (mDispatched || !mWindow) { + return; + } + + mDispatched = true; + RefPtr<IdleRequestExecutor> request = this; NS_IdleDispatchToCurrentThread(request.forget()); } -/* static */ void -nsGlobalWindow::InsertIdleCallbackIntoList(IdleRequest* aRequest, - IdleRequests& aList) +class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler +{ +public: + explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor) + : mExecutor(aExecutor) + { + } + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestExecutorTimeoutHandler, + TimeoutHandler) + + nsresult Call() override + { + mExecutor->MaybeDispatch(); + return NS_OK; + } +private: + ~IdleRequestExecutorTimeoutHandler() {} + RefPtr<IdleRequestExecutor> mExecutor; +}; + +NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler, mExecutor) + +NS_IMPL_ADDREF_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler) +NS_IMPL_RELEASE_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler) + NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler) +NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler) + +void +nsGlobalWindow::ScheduleIdleRequestDispatch() +{ + AssertIsOnMainThread(); + + if (mIdleRequestCallbacks.isEmpty()) { + if (mIdleRequestExecutor) { + mIdleRequestExecutor->Cancel(); + mIdleRequestExecutor = nullptr; + } + + return; + } + + if (!mIdleRequestExecutor) { + mIdleRequestExecutor = new IdleRequestExecutor(this); + } + + nsPIDOMWindowOuter* outer = GetOuterWindow(); + if (outer && outer->AsOuter()->IsBackground()) { + nsCOMPtr<nsITimeoutHandler> handler = new IdleRequestExecutorTimeoutHandler(mIdleRequestExecutor); + int32_t dummy; + // Set a timeout handler with a timeout of 0 ms to throttle idle + // callback requests coming from a backround window using + // background timeout throttling. + SetTimeoutOrInterval(handler, 0, false, + Timeout::Reason::eIdleCallbackTimeout, &dummy); + return; + } + + mIdleRequestExecutor->MaybeDispatch(); +} + +void +nsGlobalWindow::SuspendIdleRequests() +{ + if (mIdleRequestExecutor) { + mIdleRequestExecutor->Cancel(); + mIdleRequestExecutor = nullptr; + } +} + +void +nsGlobalWindow::ResumeIdleRequests() { - aList.insertBack(aRequest); + MOZ_ASSERT(!mIdleRequestExecutor); + + ScheduleIdleRequestDispatch(); +} + +void +nsGlobalWindow::InsertIdleCallback(IdleRequest* aRequest) +{ + AssertIsOnMainThread(); + mIdleRequestCallbacks.insertBack(aRequest); aRequest->AddRef(); } +void +nsGlobalWindow::RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest) +{ + AssertIsOnMainThread(); + + if (aRequest->HasTimeout()) { + ClearTimeoutOrInterval(aRequest->GetTimeoutHandle(), + Timeout::Reason::eIdleCallbackTimeout); + } + + aRequest->removeFrom(mIdleRequestCallbacks); + aRequest->Release(); +} + +nsresult +nsGlobalWindow::RunIdleRequest(IdleRequest* aRequest, + DOMHighResTimeStamp aDeadline, + bool aDidTimeout) +{ + AssertIsOnMainThread(); + RefPtr<IdleRequest> request(aRequest); + RemoveIdleCallback(request); + return request->IdleRun(AsInner(), aDeadline, aDidTimeout); +} + +nsresult +nsGlobalWindow::ExecuteIdleRequest(TimeStamp aDeadline) +{ + AssertIsOnMainThread(); + RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst(); + + if (!request) { + // There are no more idle requests, so stop scheduling idle + // request callbacks. + return NS_OK; + } + + DOMHighResTimeStamp deadline = 0.0; + + if (Performance* perf = GetPerformance()) { + deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline); + } + + nsresult result = RunIdleRequest(request, deadline, false); + + ScheduleIdleRequestDispatch(); + return result; +} + +class IdleRequestTimeoutHandler final : public TimeoutHandler +{ +public: + IdleRequestTimeoutHandler(JSContext* aCx, + IdleRequest* aIdleRequest, + nsPIDOMWindowInner* aWindow) + : TimeoutHandler(aCx) + , mIdleRequest(aIdleRequest) + , mWindow(aWindow) + { + } + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestTimeoutHandler, + TimeoutHandler) + + nsresult Call() override + { + return nsGlobalWindow::Cast(mWindow)->RunIdleRequest(mIdleRequest, 0.0, true); + } + +private: + ~IdleRequestTimeoutHandler() {} + + RefPtr<IdleRequest> mIdleRequest; + nsCOMPtr<nsPIDOMWindowInner> mWindow; +}; + +NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestTimeoutHandler, + TimeoutHandler, + mIdleRequest, + mWindow) + +NS_IMPL_ADDREF_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler) +NS_IMPL_RELEASE_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler) + NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler) +NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler) + uint32_t nsGlobalWindow::RequestIdleCallback(JSContext* aCx, IdleRequestCallback& aCallback, @@ -584,33 +840,36 @@ nsGlobalWindow::RequestIdleCallback(JSContext* aCx, MOZ_RELEASE_ASSERT(IsInnerWindow()); AssertIsOnMainThread(); - uint32_t handle = ++mIdleRequestCallbackCounter; + uint32_t handle = mIdleRequestCallbackCounter++; RefPtr<IdleRequest> request = - new IdleRequest(aCx, AsInner(), aCallback, handle); + new IdleRequest(&aCallback, handle); if (aOptions.mTimeout.WasPassed()) { - aError = request->SetTimeout(aOptions.mTimeout.Value()); - if (NS_WARN_IF(aError.Failed())) { + int32_t timeoutHandle; + nsCOMPtr<nsITimeoutHandler> handler(new IdleRequestTimeoutHandler(aCx, request, AsInner())); + + nsresult rv = SetTimeoutOrInterval( + handler, aOptions.mTimeout.Value(), false, + Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle); + + if (NS_WARN_IF(NS_FAILED(rv))) { return 0; } - } - nsGlobalWindow* outer = GetOuterWindowInternal(); - if (outer && outer->AsOuter()->IsBackground()) { - // mThrottledIdleRequestCallbacks now owns request - InsertIdleCallbackIntoList(request, mThrottledIdleRequestCallbacks); - - NS_DelayedDispatchToCurrentThread( - NewRunnableMethod(this, &nsGlobalWindow::PostThrottledIdleCallback), - 10000); - } else { - MOZ_ASSERT(mThrottledIdleRequestCallbacks.isEmpty()); + request->SetTimeoutHandle(timeoutHandle); + } - // mIdleRequestCallbacks now owns request - InsertIdleCallbackIntoList(request, mIdleRequestCallbacks); + // If the list of idle callback requests is not empty it means that + // we've already dispatched the first idle request. If we're + // suspended we should only queue the idle callback and not schedule + // it to run, that will be done in ResumeIdleRequest. + bool needsScheduling = !IsSuspended() && mIdleRequestCallbacks.isEmpty(); + // mIdleRequestCallbacks now owns request + InsertIdleCallback(request); - NS_IdleDispatchToCurrentThread(request.forget()); + if (needsScheduling) { + ScheduleIdleRequestDispatch(); } return handle; @@ -623,7 +882,7 @@ nsGlobalWindow::CancelIdleCallback(uint32_t aHandle) for (IdleRequest* r : mIdleRequestCallbacks) { if (r->Handle() == aHandle) { - r->Cancel(); + RemoveIdleCallback(r); break; } } @@ -632,29 +891,17 @@ nsGlobalWindow::CancelIdleCallback(uint32_t aHandle) void nsGlobalWindow::DisableIdleCallbackRequests() { - while (!mIdleRequestCallbacks.isEmpty()) { - RefPtr<IdleRequest> request = mIdleRequestCallbacks.popFirst(); - request->Cancel(); + if (mIdleRequestExecutor) { + mIdleRequestExecutor->Cancel(); + mIdleRequestExecutor = nullptr; } - while (!mThrottledIdleRequestCallbacks.isEmpty()) { - RefPtr<IdleRequest> request = mThrottledIdleRequestCallbacks.popFirst(); - request->Cancel(); - } -} - -void nsGlobalWindow::UnthrottleIdleCallbackRequests() -{ - AssertIsOnMainThread(); - - while (!mThrottledIdleRequestCallbacks.isEmpty()) { - RefPtr<IdleRequest> request(mThrottledIdleRequestCallbacks.popFirst()); - mIdleRequestCallbacks.insertBack(request); - NS_IdleDispatchToCurrentThread(request.forget()); + while (!mIdleRequestCallbacks.isEmpty()) { + RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst(); + RemoveIdleCallback(request); } } - namespace mozilla { namespace dom { extern uint64_t @@ -1306,6 +1553,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mSerial(0), mIdleCallbackTimeoutCounter(1), mIdleRequestCallbackCounter(1), + mIdleRequestExecutor(nullptr), #ifdef DEBUG mSetOpenerWindowCalled(false), #endif @@ -2033,14 +2281,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor) for (IdleRequest* request : tmp->mIdleRequestCallbacks) { cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest)); } - for (IdleRequest* request : tmp->mThrottledIdleRequestCallbacks) { - cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest)); - } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers) #ifdef MOZ_GAMEPAD @@ -2147,6 +2392,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow) tmp->UnlinkHostObjectURIs(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor) tmp->DisableIdleCallbackRequests(); NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER @@ -10237,12 +10483,6 @@ void nsGlobalWindow::SetIsBackground(bool aIsBackground) ResetTimersForThrottleReduction(gMinBackgroundTimeoutValue); } - if (!aIsBackground) { - nsGlobalWindow* inner = GetCurrentInnerWindowInternal(); - if (inner) { - inner->UnthrottleIdleCallbackRequests(); - } - } #ifdef MOZ_GAMEPAD if (!aIsBackground) { nsGlobalWindow* inner = GetCurrentInnerWindowInternal(); @@ -12036,6 +12276,8 @@ nsGlobalWindow::Suspend() mozilla::dom::workers::SuspendWorkersForWindow(AsInner()); + SuspendIdleRequests(); + for (Timeout* t = mTimeouts.getFirst(); t; t = t->getNext()) { // Leave the timers with the current time remaining. This will // cause the timers to potentially fire when the window is @@ -12146,6 +12388,8 @@ nsGlobalWindow::Resume() t->AddRef(); } + ResumeIdleRequests(); + // Resume all of the workers for this window. We must do this // after timeouts since workers may have queued events that can trigger // a setTimeout(). diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index dbceeab74..78bee63a1 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -102,6 +102,8 @@ struct nsRect; class nsWindowSizes; +class IdleRequestExecutor; + namespace mozilla { class DOMEventTargetHelper; class ThrottledEventQueue; @@ -118,6 +120,7 @@ class Gamepad; enum class ImageBitmapFormat : uint32_t; class IdleRequest; class IdleRequestCallback; +class IncrementalRunnable; class Location; class MediaQueryList; class MozSelfSupport; @@ -1097,7 +1100,6 @@ public: mozilla::ErrorResult& aError); void CancelIdleCallback(uint32_t aHandle); - #ifdef MOZ_WEBSPEECH mozilla::dom::SpeechSynthesis* GetSpeechSynthesis(mozilla::ErrorResult& aError); @@ -1762,6 +1764,21 @@ private: mozilla::dom::TabGroup* TabGroupInner(); mozilla::dom::TabGroup* TabGroupOuter(); +public: + void DisableIdleCallbackRequests(); + uint32_t IdleRequestHandle() const { return mIdleRequestCallbackCounter; } + nsresult RunIdleRequest(mozilla::dom::IdleRequest* aRequest, + DOMHighResTimeStamp aDeadline, bool aDidTimeout); + nsresult ExecuteIdleRequest(TimeStamp aDeadline); + void ScheduleIdleRequestDispatch(); + void SuspendIdleRequests(); + void ResumeIdleRequests(); + + typedef mozilla::LinkedList<mozilla::dom::IdleRequest> IdleRequests; + void InsertIdleCallback(mozilla::dom::IdleRequest* aRequest); + + void RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest); + protected: // These members are only used on outer window objects. Make sure // you never set any of these on an inner object! @@ -1912,21 +1929,12 @@ protected: uint32_t mSerial; - void DisableIdleCallbackRequests(); - void UnthrottleIdleCallbackRequests(); - - void PostThrottledIdleCallback(); - - typedef mozilla::LinkedList<mozilla::dom::IdleRequest> IdleRequests; - static void InsertIdleCallbackIntoList(mozilla::dom::IdleRequest* aRequest, - IdleRequests& aList); - // The current idle request callback timeout handle uint32_t mIdleCallbackTimeoutCounter; // The current idle request callback handle uint32_t mIdleRequestCallbackCounter; IdleRequests mIdleRequestCallbacks; - IdleRequests mThrottledIdleRequestCallbacks; + RefPtr<IdleRequestExecutor> mIdleRequestExecutor; #ifdef DEBUG bool mSetOpenerWindowCalled; @@ -2002,6 +2010,7 @@ protected: friend class nsDOMWindowUtils; friend class mozilla::dom::PostMessageEvent; friend class DesktopNotification; + friend class IdleRequestExecutor; static WindowByIdTable* sWindowsById; static bool sWarnedAboutWindowInternal; diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 8f35e9ba5..1e0c9562e 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -151,6 +151,7 @@ class NodeIterator; enum class OrientationType : uint32_t; class ProcessingInstruction; class Promise; +class Selection; class StyleSheetList; class SVGDocument; class SVGSVGElement; @@ -898,6 +899,8 @@ public: */ Element* GetRootElement() const; + mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv); + /** * Retrieve information about the viewport as a data structure. * This will return information in the viewport META data section diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 3a649a61d..715ca93ea 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -1907,6 +1907,10 @@ void nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify, nsIContent* aKid, nsAttrAndChildArray& aChildArray) { + // NOTE: This function must not trigger any calls to + // nsIDocument::GetRootElement() calls until *after* it has removed aKid from + // aChildArray. Any calls before then could potentially restore a stale + // value for our cached root element, per note in nsDocument::RemoveChildAt(). NS_PRECONDITION(aKid && aKid->GetParentNode() == this && aKid == GetChildAt(aIndex) && IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid"); diff --git a/dom/cache/Cache.cpp b/dom/cache/Cache.cpp index 0d5815edb..b183bf387 100644 --- a/dom/cache/Cache.cpp +++ b/dom/cache/Cache.cpp @@ -618,7 +618,7 @@ Cache::AddAll(const GlobalObject& aGlobal, new FetchHandler(mActor->GetWorkerHolder(), this, Move(aRequestList), promise); - RefPtr<Promise> fetchPromise = Promise::All(aGlobal, fetchList, aRv); + RefPtr<Promise> fetchPromise = Promise::All(aGlobal.Context(), fetchList, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index 2546a81ad..7e19cd74d 100755 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -855,6 +855,25 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) } } break; + case ePointerEventClass: + if (aEvent->IsTrusted() && + aEvent->AsPointerEvent()->button == WidgetMouseEvent::eLeftButton) { + switch(aEvent->mMessage) { + case ePointerUp: + if (PopupAllowedForEvent("pointerup")) { + abuse = openControlled; + } + break; + case ePointerDown: + if (PopupAllowedForEvent("pointerdown")) { + abuse = openControlled; + } + break; + default: + break; + } + } + break; case eFormEventClass: // For these following events only allow popups if they're // triggered while handling user input. See diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp index a1d0675ae..65f01844b 100644 --- a/dom/events/EventDispatcher.cpp +++ b/dom/events/EventDispatcher.cpp @@ -1056,6 +1056,11 @@ EventDispatcher::CreateEvent(EventTarget* aOwner, LOG_EVENT_CREATION(STORAGEEVENT); return NS_NewDOMStorageEvent(aOwner); } + if (aEventType.LowerCaseEqualsLiteral("focusevent")) { + RefPtr<Event> event = NS_NewDOMFocusEvent(aOwner, aPresContext, nullptr); + event->MarkUninitialized(); + return event.forget(); + } #undef LOG_EVENT_CREATION diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index c23cdb575..c6b304183 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -731,6 +731,9 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, FlushPendingEvents(aPresContext); break; } + case ePointerGotCapture: + GenerateMouseEnterExit(mouseEvent); + break; case eDragStart: if (Prefs::ClickHoldContextMenu()) { // an external drag gesture event came in, not generated internally @@ -3890,10 +3893,7 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent, newPointerEvent->mWidth = sourcePointer->mWidth; newPointerEvent->mHeight = sourcePointer->mHeight; newPointerEvent->inputSource = sourcePointer->inputSource; - newPointerEvent->relatedTarget = - nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId) - ? nullptr - : aRelatedContent; + newPointerEvent->relatedTarget = aRelatedContent; aNewEvent = newPointerEvent.forget(); } else { aNewEvent = @@ -4034,7 +4034,7 @@ public: } } - ~EnterLeaveDispatcher() + void Dispatch() { if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) { for (int32_t i = mTargets.Count() - 1; i >= 0; --i) { @@ -4106,19 +4106,14 @@ EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent, SetContentState(nullptr, NS_EVENT_STATE_HOVER); } - // In case we go out from capturing element (retargetedByPointerCapture is true) - // we should dispatch ePointerLeave event and only for capturing element. - RefPtr<nsIContent> movingInto = aMouseEvent->retargetedByPointerCapture - ? wrapper->mLastOverElement->GetParent() - : aMovingInto; - EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement, - movingInto, aMouseEvent, + aMovingInto, aMouseEvent, isPointer ? ePointerLeave : eMouseLeave); // Fire mouseout DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? ePointerOut : eMouseOut, wrapper->mLastOverElement, aMovingInto); + leaveDispatcher.Dispatch(); wrapper->mLastOverFrame = nullptr; wrapper->mLastOverElement = nullptr; @@ -4133,13 +4128,9 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent, { NS_ASSERTION(aContent, "Mouse must be over something"); - // If pointer capture is set, we should suppress pointerover/pointerenter events - // for all elements except element which have pointer capture. - bool dispatch = !aMouseEvent->retargetedByPointerCapture; - OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent); - if (wrapper->mLastOverElement == aContent && dispatch) + if (wrapper->mLastOverElement == aContent) return; // Before firing mouseover, check for recursion @@ -4162,7 +4153,7 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent, } // Firing the DOM event in the parent document could cause all kinds // of havoc. Reverify and take care. - if (wrapper->mLastOverElement == aContent && dispatch) + if (wrapper->mLastOverElement == aContent) return; // Remember mLastOverElement as the related content for the @@ -4171,11 +4162,9 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent, bool isPointer = aMouseEvent->mClass == ePointerEventClass; - Maybe<EnterLeaveDispatcher> enterDispatcher; - if (dispatch) { - enterDispatcher.emplace(this, aContent, lastOverElement, aMouseEvent, - isPointer ? ePointerEnter : eMouseEnter); - } + EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement, + aMouseEvent, + isPointer ? ePointerEnter : eMouseEnter); NotifyMouseOut(aMouseEvent, aContent); @@ -4187,17 +4176,13 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent, SetContentState(aContent, NS_EVENT_STATE_HOVER); } - if (dispatch) { - // Fire mouseover - wrapper->mLastOverFrame = - DispatchMouseOrPointerEvent(aMouseEvent, - isPointer ? ePointerOver : eMouseOver, - aContent, lastOverElement); - wrapper->mLastOverElement = aContent; - } else { - wrapper->mLastOverFrame = nullptr; - wrapper->mLastOverElement = nullptr; - } + // Fire mouseover + wrapper->mLastOverFrame = + DispatchMouseOrPointerEvent(aMouseEvent, + isPointer ? ePointerOver : eMouseOver, + aContent, lastOverElement); + enterDispatcher.Dispatch(); + wrapper->mLastOverElement = aContent; // Turn recursion protection back off wrapper->mFirstOverEventElement = nullptr; @@ -4290,6 +4275,7 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) MOZ_FALLTHROUGH; case ePointerMove: case ePointerDown: + case ePointerGotCapture: { // Get the target content target (mousemove target == mouseover target) nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent); diff --git a/dom/events/PointerEvent.cpp b/dom/events/PointerEvent.cpp index f53739863..fbaa0f737 100644 --- a/dom/events/PointerEvent.cpp +++ b/dom/events/PointerEvent.cpp @@ -93,8 +93,10 @@ PointerEvent::Constructor(EventTarget* aOwner, widgetEvent->mWidth = aParam.mWidth; widgetEvent->mHeight = aParam.mHeight; widgetEvent->pressure = aParam.mPressure; + widgetEvent->tangentialPressure = aParam.mTangentialPressure; widgetEvent->tiltX = aParam.mTiltX; widgetEvent->tiltY = aParam.mTiltY; + widgetEvent->twist = aParam.mTwist; widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType); widgetEvent->mIsPrimary = aParam.mIsPrimary; widgetEvent->buttons = aParam.mButtons; @@ -145,6 +147,12 @@ PointerEvent::Pressure() return mEvent->AsPointerEvent()->pressure; } +float +PointerEvent::TangentialPressure() +{ + return mEvent->AsPointerEvent()->tangentialPressure; +} + int32_t PointerEvent::TiltX() { @@ -157,6 +165,12 @@ PointerEvent::TiltY() return mEvent->AsPointerEvent()->tiltY; } +int32_t +PointerEvent::Twist() +{ + return mEvent->AsPointerEvent()->twist; +} + bool PointerEvent::IsPrimary() { diff --git a/dom/events/PointerEvent.h b/dom/events/PointerEvent.h index 62c5a0c36..12d4941dc 100644 --- a/dom/events/PointerEvent.h +++ b/dom/events/PointerEvent.h @@ -44,8 +44,10 @@ public: int32_t Width(); int32_t Height(); float Pressure(); + float TangentialPressure(); int32_t TiltX(); int32_t TiltY(); + int32_t Twist(); bool IsPrimary(); void GetPointerType(nsAString& aPointerType); }; diff --git a/dom/events/test/pointerevents/mochitest.ini b/dom/events/test/pointerevents/mochitest.ini index 58eae12fe..af762feb2 100644 --- a/dom/events/test/pointerevents/mochitest.ini +++ b/dom/events/test/pointerevents/mochitest.ini @@ -6,6 +6,14 @@ support-files = pointerevent_styles.css pointerevent_support.js +[test_bug1285128.html] +[test_bug1293174_implicit_pointer_capture_for_touch_1.html] + support-files = bug1293174_implicit_pointer_capture_for_touch_1.html +[test_bug1293174_implicit_pointer_capture_for_touch_2.html] + support-files = bug1293174_implicit_pointer_capture_for_touch_2.html +[test_bug1323158.html] +[test_empty_file.html] + disabled = disabled # Bug 1150091 - Issue with support-files [test_pointerevent_attributes_mouse-manual.html] support-files = pointerevent_attributes_mouse-manual.html [test_pointerevent_capture_mouse-manual.html] @@ -143,10 +151,5 @@ support-files = pointerevent_touch-action-span-test_touch-manual.html pointerevent_touch-action-svg-test_touch-manual.html pointerevent_touch-action-table-test_touch-manual.html -[test_bug1285128.html] -[test_bug1293174_implicit_pointer_capture_for_touch_1.html] - support-files = bug1293174_implicit_pointer_capture_for_touch_1.html -[test_bug1293174_implicit_pointer_capture_for_touch_2.html] - support-files = bug1293174_implicit_pointer_capture_for_touch_2.html -[test_empty_file.html] - disabled = disabled # Bug 1150091 - Issue with support-files +[test_trigger_fullscreen_by_pointer_events.html] +[test_trigger_popup_by_pointer_events.html] diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html index f4d5573ed..2614790f3 100644 --- a/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html +++ b/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html @@ -1,4 +1,4 @@ -<!doctype html> +<!doctype html> <html> <head> <title>Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms</title> @@ -12,19 +12,27 @@ <script type="text/javascript" src="pointerevent_support.js"></script> <script type="text/javascript" src="mochitest_support_internal.js"></script> <script type="text/javascript"> + var test_pointerEvent; var detected_pointertypes = {}; - var test_pointerEvent = async_test("lostpointercapture: subsequent events to target."); // set up test harness - var suppressedEventsFail = false; - // showPointerTypes is defined in pointerevent_support.js - // Requirements: the callback function will reference the test_pointerEvent object and - // will fail unless the async_test is created with the var name "test_pointerEvent". - add_completion_callback(showPointerTypes); - - var captured_event; + var captured_event = null; + var test_done = false; + var overEnterEventsFail = false; + var outLeaveEventsFail = false; var f_gotPointerCapture = false; var f_lostPointerCapture = false; + function resetTestState() { + captured_event = null; + test_done = false; + overEnterEventsFail = false; + outLeaveEventsFail = false; + f_gotPointerCapture = false; + f_lostPointerCapture = false; + } + function listenerEventHandler(event) { + if (test_done) + return; detected_pointertypes[event.pointerType] = true; if (event.type == "gotpointercapture") { f_gotPointerCapture = true; @@ -35,12 +43,20 @@ f_gotPointerCapture = false; check_PointerEvent(event); } - else if(event.type == "pointerover" || event.type == "pointerenter" || event.type == "pointerout" || event.type == "pointerleave") { - if(!suppressedEventsFail) { + else if(event.type == "pointerover" || event.type == "pointerenter") { + if(captured_event && !overEnterEventsFail) { + test(function() { + assert_false(f_gotPointerCapture, "pointerover/enter should be received before the target receives gotpointercapture even when the pointer is not over it."); + }, expectedPointerType + " pointerover/enter should be received before the target receives gotpointercapture even when the pointer is not over it."); + overEnterEventsFail = true; + } + } + else if(event.type == "pointerout" || event.type == "pointerleave") { + if(!outLeaveEventsFail) { test(function() { - assert_true(false, "Suppressed events were received"); - }, "Suppressed events were received"); - suppressedEventsFail = true; + assert_true(f_lostPointerCapture, "pointerout/leave should not be received unless the target just lost the capture."); + }, expectedPointerType + " pointerout/leave should not be received unless the target just lost the capture."); + outLeaveEventsFail = true; } } else if (event.pointerId == captured_event.pointerId) { @@ -50,19 +66,21 @@ } else { // if any other events are received after releaseCapture, then the test fails - test_pointerEvent.step(function () { - assert_true(false, event.target.id + "-" + event.type + " should be handled by target element handler"); - }); + test(function () { + assert_unreached(event.target.id + "-" + event.type + " should be handled by target element handler"); + }, expectedPointerType + " No other events should be recieved by capturing node after release"); } } } function targetEventHandler(event) { + if (test_done) + return; if (f_gotPointerCapture) { if(event.type != "pointerout" && event.type != "pointerleave") { - test_pointerEvent.step(function () { - assert_true(false, "The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". "); - }); + test(function () { + assert_unreached("The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". "); + }, expectedPointerType + " The target element should not receive any events while capture is active"); } } @@ -77,12 +95,14 @@ assert_equals(event.pointerId, captured_event.pointerId, "pointerID is same for event captured and after release"); }); if (event.type == "pointerup") { + test_done = true; test_pointerEvent.done(); // complete test } } } function run() { + test_pointerEvent = setup_pointerevent_test("got/lost pointercapture: subsequent events to target", ALL_POINTERS); // set up test harness var listener = document.getElementById("listener"); var target0 = document.getElementById("target0"); target0.style["touchAction"] = "none"; @@ -96,18 +116,19 @@ </script> </head> <body onload="run()"> + <h2 id="pointerTypeDescription"></h2> <div id="listener"></div> <h1>Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms</h1> <!-- <h4> Test Description: + Use your pointer and press down in the black box. Then move around in the box and release your pointer. After invoking the releasePointerCapture method on an element, subsequent events for the specified - pointer must follow normal hit testing mechanisms for determining the event target + pointer must follow normal hit testing mechanisms for determining the event target. </h4> <br /> --> <div id="target0"> - Use mouse, touch or pen to contact here and move around. </div> <div id="complete-notice"> <p>Test complete: Scroll to Summary to view Pass/Fail Results.</p> diff --git a/dom/events/test/pointerevents/test_bug1285128.html b/dom/events/test/pointerevents/test_bug1285128.html index f7f1eb698..9577940c1 100644 --- a/dom/events/test/pointerevents/test_bug1285128.html +++ b/dom/events/test/pointerevents/test_bug1285128.html @@ -13,7 +13,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1285128 <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1285128">Mozilla Bug 1285128</a> <p id="display"></p> -<div id="target0" style="width: 200px; height: 200px; background: green"></div> +<div id="target0" style="width: 50px; height: 50px; background: green"></div> +<div id="target1" style="width: 50px; height: 50px; background: red"></div> <script type="text/javascript"> /** Test for Bug 1285128 **/ @@ -31,7 +32,7 @@ function runTests() { }, false); }); - target0.addEventListener("mouseenter", () => { + target1.addEventListener("mouseup", () => { ok(!receivedPointerEvents, "synthesized mousemove should not trigger any pointer events"); SimpleTest.finish(); }); @@ -39,6 +40,8 @@ function runTests() { synthesizeMouseAtCenter(target0, { type: "mousemove", inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE, isWidgetEventSynthesized: true }); + synthesizeMouseAtCenter(target1, { type: "mousedown" }); + synthesizeMouseAtCenter(target1, { type: "mouseup" }); } SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests); diff --git a/dom/events/test/pointerevents/test_bug1323158.html b/dom/events/test/pointerevents/test_bug1323158.html new file mode 100644 index 000000000..fac96c97a --- /dev/null +++ b/dom/events/test/pointerevents/test_bug1323158.html @@ -0,0 +1,93 @@ +<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1323158
+-->
+<head>
+ <meta charset="utf-8">
+ <title>This is a test to check if target and relatedTarget of mouse events are the same as pointer events</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="content"></p>
+<script type="text/javascript">
+
+/** Test for Bug 1323158 **/
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ let content = document.getElementById('content');
+ let iframe = document.createElement('iframe');
+ iframe.width = 500;
+ iframe.height = 500;
+ content.appendChild(iframe);
+ iframe.contentDocument.body.innerHTML =
+ "<br><div id='target0' style='width: 30px; height: 30px; background: black;'></div>" +
+ "<br><div id='target1' style='width: 30px; height: 30px; background: red;'></div>" +
+ "<br><div id='done' style='width: 30px; height: 30px; background: green;'></div>";
+
+ let target0 = iframe.contentDocument.getElementById("target0");
+ let target1 = iframe.contentDocument.getElementById("target1");
+ let done = iframe.contentDocument.getElementById("done");
+ let pointerBoundaryEvents = ["pointerover", "pointerenter", "pointerleave", "pointerout"];
+ let mouseBoundaryEvents = ["mouseover", "mouseenter", "mouseleave", "mouseout"];
+ let receivedPointerBoundaryEvents = {};
+ let mouseEvent2pointerEvent = {"mouseover": "pointerover",
+ "mouseenter": "pointerenter",
+ "mouseleave": "pointerleave",
+ "mouseout": "pointerout"
+ };
+
+ pointerBoundaryEvents.forEach((event) => {
+ target1.addEventListener(event, (e) => {
+ receivedPointerBoundaryEvents[event] = e;
+ });
+ });
+
+ let attributes = ["target", "relatedTarget"];
+ mouseBoundaryEvents.forEach((event) => {
+ target1.addEventListener(event, (e) => {
+ let correspondingPointerEv = receivedPointerBoundaryEvents[mouseEvent2pointerEvent[event]];
+ ok(correspondingPointerEv, "Should receive " + mouseEvent2pointerEvent[event] + " before " + e.type);
+ if (correspondingPointerEv) {
+ attributes.forEach((attr) => {
+ ok(correspondingPointerEv[attr] == e[attr],
+ attr + " of " + e.type + " should be the same as the correcponding pointer event expect " +
+ correspondingPointerEv[attr] + " got " + e[attr]);
+ });
+ }
+ receivedPointerBoundaryEvents[mouseEvent2pointerEvent[event]] = null;
+ });
+ });
+ target0.addEventListener("pointerdown", (e) => {
+ target1.setPointerCapture(e.pointerId);
+ });
+ done.addEventListener("mouseup", () => {
+ SimpleTest.finish();
+ });
+ let source = SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE;
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(done, 5, 5, { type: "mousedown", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(done, 5, 5, { type: "mouseup", inputSource: source },
+ iframe.contentWindow);
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html b/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html index dc3903592..2b08e2bb8 100644 --- a/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html +++ b/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html @@ -19,7 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870 function executeTest(int_win) { sendMouseEvent(int_win, "target0", "mousemove"); sendMouseEvent(int_win, "target1", "mousemove"); - sendMouseEvent(int_win, "btnCapture", "mousedown", {button:1}); + sendMouseEvent(int_win, "btnCapture", "mousemove"); + sendMouseEvent(int_win, "btnCapture", "mousedown"); sendMouseEvent(int_win, "target1", "mousemove"); sendMouseEvent(int_win, "target0", "mousemove"); sendMouseEvent(int_win, "target1", "mousemove"); diff --git a/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html b/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html index cbf91df74..35350e016 100644 --- a/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html +++ b/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html @@ -17,9 +17,30 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870 runTestInNewWindow("pointerevent_releasepointercapture_events_to_original_target-manual.html"); } function executeTest(int_win) { - sendTouchEvent(int_win, "target0", "touchstart"); - sendTouchEvent(int_win, "target0", "touchmove"); - sendTouchEvent(int_win, "target0", "touchend"); + // Synthesize mouse events to run this test. + sendMouseEvent(int_win, "target0", "mousemove"); + sendMouseEvent(int_win, "target0", "mousedown"); + sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1}); + sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1}); + sendMouseEvent(int_win, "target0", "mouseup"); + + window.addEventListener("message", function(aEvent) { + if (aEvent.data == "Test Touch") { + // Synthesize touch events to run this test. + sendTouchEvent(int_win, "target0", "touchstart"); + sendTouchEvent(int_win, "target0", "touchmove"); + sendTouchEvent(int_win, "target0", "touchend"); + window.postMessage("Test Pen", "*"); + } else if (aEvent.data == "Test Pen") { + // Synthesize pen events to run this test. + sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN}); + sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN}); + sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1}); + sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1}); + sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN}); + } + }); + window.postMessage("Test Touch", "*"); } </script> </head> diff --git a/dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html b/dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html index 0883d616b..09e97ec97 100644 --- a/dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html +++ b/dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html @@ -19,8 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870 function executeTest(int_win) { sendMouseEvent(int_win, "target1", "mousemove"); sendMouseEvent(int_win, "btnCapture", "mousedown"); - sendMouseEvent(int_win, "target1", "mousemove"); - sendMouseEvent(int_win, "target1", "mouseup"); + sendMouseEvent(int_win, "btnCapture", "mousemove"); + sendMouseEvent(int_win, "btnCapture", "mouseup"); } </script> </head> diff --git a/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html b/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html new file mode 100644 index 000000000..53d390996 --- /dev/null +++ b/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Test for triggering Fullscreen by pointer events</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<script> + +SimpleTest.waitForExplicitFinish(); + +function startTest() { + let win = window.open("data:text/html,<body><div id='target' style='width: 50px; height: 50px; background: green'></div></body>", "_blank"); + win.addEventListener("load", () => { + let target = win.document.getElementById("target"); + target.addEventListener("pointerdown", () => { + target.requestFullscreen(); + target.addEventListener("pointerdown", () => { + win.document.exitFullscreen(); + }, {once: true}); + }, {once: true}); + + win.document.addEventListener("fullscreenchange", () => { + if (win.document.fullscreenElement) { + ok(win.document.fullscreenElement, target, "fullscreenElement should be the div element"); + // synthesize mouse events to generate pointer events and leave full screen. + synthesizeMouseAtCenter(target, { type: "mousedown" }, win); + synthesizeMouseAtCenter(target, { type: "mouseup" }, win); + } else { + win.close(); + SimpleTest.finish(); + } + }); + // Make sure our window is focused before starting the test + SimpleTest.waitForFocus(() => { + // synthesize mouse events to generate pointer events and enter full screen. + synthesizeMouseAtCenter(target, { type: "mousedown" }, win); + synthesizeMouseAtCenter(target, { type: "mouseup" }, win); + }, win); + }); +} + +SimpleTest.waitForFocus(() => { + SpecialPowers.pushPrefEnv({ + "set": [ + ["full-screen-api.unprefix.enabled", true], + ["full-screen-api.allow-trusted-requests-only", false], + ["dom.w3c_pointer_events.enabled", true] + ] + }, startTest); +}); +</script> +</body> +</html> diff --git a/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html b/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html new file mode 100644 index 000000000..cda279e26 --- /dev/null +++ b/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html @@ -0,0 +1,76 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Test for triggering popup by pointer events</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<div id="target" style="width: 50px; height: 50px; background: green"></div> +<script> + +SimpleTest.waitForExplicitFinish(); + +function sendMouseEvent(element, eventName, listenEventName, handler) { + element.addEventListener(listenEventName, handler, {once: true}); + synthesizeMouseAtCenter(element, {type: eventName}); +} + +function checkAllowOpenPopup(e) { + let w = window.open("about:blank"); + ok(w, "Should allow popup in the " + e.type + " listener"); + if (w) { + w.close(); + } +} + +function checkBlockOpenPopup(e) { + let w = window.open("about:blank"); + ok(!w, "Should block popup in the " + e.type + " listener"); + if (w) { + w.close(); + } +} + +function startTest() { + let target = document.getElementById("target"); + // By default, only allow opening popup in the pointerup listener. + sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup); + sendMouseEvent(target, "mousedown", "pointerdown", checkBlockOpenPopup); + sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup); + sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup); + SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events", + "pointerdown pointerup"]]}, () => { + // Adding pointerdown to preference should work + sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup); + sendMouseEvent(target, "mousedown", "pointerdown", checkAllowOpenPopup); + sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup); + sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup); + SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events", + "pointerdown pointerup pointermove"]]}, () => { + // Adding pointermove to preference should be no effect. + sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup); + sendMouseEvent(target, "mousedown", "pointerdown", checkAllowOpenPopup); + sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup); + sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup); + SimpleTest.finish(); + }); + }); +} + +const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION; + +SimpleTest.waitForFocus(() => { + SpecialPowers.pushPermissions([{'type': 'popup', 'allow': DENY_ACTION, + 'context': document}], () => { + SpecialPowers.pushPrefEnv({ + "set": [["dom.w3c_pointer_events.enabled", true]] + }, startTest); + }); +}); + +</script> +</body> +</html> diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp index a76071bf8..3b3ada6d3 100644 --- a/dom/fetch/Response.cpp +++ b/dom/fetch/Response.cpp @@ -104,7 +104,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl, return nullptr; } - Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams> body; + Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>> body; ResponseInit init; init.mStatus = aStatus; RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv); @@ -125,7 +125,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl, /*static*/ already_AddRefed<Response> Response::Constructor(const GlobalObject& aGlobal, - const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody, + const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody, const ResponseInit& aInit, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); @@ -191,7 +191,7 @@ Response::Constructor(const GlobalObject& aGlobal, } } - if (aBody.WasPassed()) { + if (aBody.WasPassed() && !aBody.Value().IsNull()) { if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) { aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>(); return nullptr; @@ -200,7 +200,7 @@ Response::Constructor(const GlobalObject& aGlobal, nsCOMPtr<nsIInputStream> bodyStream; nsCString contentType; uint64_t bodySize = 0; - aRv = ExtractByteStreamFromBody(aBody.Value(), + aRv = ExtractByteStreamFromBody(aBody.Value().Value(), getter_AddRefs(bodyStream), contentType, bodySize); diff --git a/dom/fetch/Response.h b/dom/fetch/Response.h index 64b3c5f45..de367bef6 100644 --- a/dom/fetch/Response.h +++ b/dom/fetch/Response.h @@ -114,7 +114,7 @@ public: static already_AddRefed<Response> Constructor(const GlobalObject& aGlobal, - const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody, + const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody, const ResponseInit& aInit, ErrorResult& rv); nsIGlobalObject* GetParentObject() const diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index be5a34d41..69e710242 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -2149,26 +2149,10 @@ NS_IMETHODIMP nsHTMLDocument::GetSelection(nsISelection** aReturn) { ErrorResult rv; - NS_IF_ADDREF(*aReturn = GetSelection(rv)); + NS_IF_ADDREF(*aReturn = nsDocument::GetSelection(rv)); return rv.StealNSResult(); } -Selection* -nsHTMLDocument::GetSelection(ErrorResult& aRv) -{ - nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject()); - if (!window) { - return nullptr; - } - - NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!"); - if (!window->IsCurrentInnerWindow()) { - return nullptr; - } - - return nsGlobalWindow::Cast(window)->GetSelection(aRv); -} - NS_IMETHODIMP nsHTMLDocument::CaptureEvents() { diff --git a/dom/html/nsHTMLDocument.h b/dom/html/nsHTMLDocument.h index 426ebddc5..1fa81f6cd 100644 --- a/dom/html/nsHTMLDocument.h +++ b/dom/html/nsHTMLDocument.h @@ -242,7 +242,6 @@ public: { // Deprecated } - mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv); // The XPCOM CaptureEvents works fine for us. // The XPCOM ReleaseEvents works fine for us. // We're picking up GetLocation from Document diff --git a/dom/indexedDB/test/browser_forgetThisSite.js b/dom/indexedDB/test/browser_forgetThisSite.js index c1177908f..02674922f 100644 --- a/dom/indexedDB/test/browser_forgetThisSite.js +++ b/dom/indexedDB/test/browser_forgetThisSite.js @@ -67,9 +67,10 @@ function test2() function test3() { // Remove database from domain 2 - ForgetAboutSite.removeDataFromDomain(domains[1]); - setPermission(testPageURL4, "indexedDB"); - executeSoon(test4); + ForgetAboutSite.removeDataFromDomain(domains[1]).then(() => { + setPermission(testPageURL4, "indexedDB"); + executeSoon(test4); + }); } function test4() diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 73621df22..286f1d851 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3224,11 +3224,15 @@ PPrintingParent* ContentParent::AllocPPrintingParent() { #ifdef NS_PRINTING - MOZ_ASSERT(!mPrintingParent, - "Only one PrintingParent should be created per process."); + MOZ_RELEASE_ASSERT(!mPrintingParent, + "Only one PrintingParent should be created per process."); // Create the printing singleton for this process. mPrintingParent = new PrintingParent(); + + // Take another reference for IPDL code. + mPrintingParent.get()->AddRef(); + return mPrintingParent.get(); #else MOZ_ASSERT_UNREACHABLE("Should never be created if no printing."); @@ -3240,8 +3244,11 @@ bool ContentParent::DeallocPPrintingParent(PPrintingParent* printing) { #ifdef NS_PRINTING - MOZ_ASSERT(mPrintingParent == printing, - "Only one PrintingParent should have been created per process."); + MOZ_RELEASE_ASSERT(mPrintingParent == printing, + "Only one PrintingParent should have been created per process."); + + // Release reference taken for IPDL code. + static_cast<PrintingParent*>(printing)->Release(); mPrintingParent = nullptr; #else diff --git a/dom/locales/en-US/chrome/plugins.properties b/dom/locales/en-US/chrome/plugins.properties index ee8d25c88..fe03be59e 100644 --- a/dom/locales/en-US/chrome/plugins.properties +++ b/dom/locales/en-US/chrome/plugins.properties @@ -21,9 +21,6 @@ description_label=Description suffixes_label=Suffixes learn_more_label=Learn More -deprecation_description=Missing something? Some plugins are no longer supported. -deprecation_learn_more=Learn More. - # GMP Plugins gmp_license_info=License information gmp_privacy_info=Privacy Information diff --git a/dom/locales/en-US/chrome/security/security.properties b/dom/locales/en-US/chrome/security/security.properties index 8b66cc265..c0b80996c 100644 --- a/dom/locales/en-US/chrome/security/security.properties +++ b/dom/locales/en-US/chrome/security/security.properties @@ -81,3 +81,6 @@ MimeTypeMismatch=The resource from “%1$S” was blocked due to MIME type misma XCTOHeaderValueMissing=X-Content-Type-Options header warning: value was “%1$S”; did you mean to send “nosniff”? BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a disallowed MIME type. + +# LOCALIZATION NOTE: Do not translate "data: URI". +BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”) diff --git a/dom/media/AudioConverter.cpp b/dom/media/AudioConverter.cpp index 77ad46ec6..25b981f43 100644 --- a/dom/media/AudioConverter.cpp +++ b/dom/media/AudioConverter.cpp @@ -362,15 +362,13 @@ size_t AudioConverter::ResampleRecipientFrames(size_t aFrames) const { if (!aFrames && mIn.Rate() != mOut.Rate()) { - // The resampler will be drained, account for frames currently buffered - // in the resampler. if (!mResampler) { return 0; } - return speex_resampler_get_output_latency(mResampler); - } else { - return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1; + // We drain by pushing in get_input_latency() samples of 0 + aFrames = speex_resampler_get_input_latency(mResampler); } + return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1; } size_t diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index 94cafa029..e2934cbb2 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -1715,6 +1715,10 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG) RefPtr<GraphDriver> driver = CurrentDriver(); MonitorAutoUnlock unlock(mMonitor); driver->Start(); + // It's not safe to Shutdown() a thread from StableState, and + // releasing this may shutdown a SystemClockDriver thread. + // Proxy the release to outside of StableState. + NS_ReleaseOnMainThread(driver.forget(), true); // always proxy } } diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 00b78143e..557f3a1f9 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -561,37 +561,40 @@ Promise::Reject(nsIGlobalObject* aGlobal, JSContext* aCx, // static already_AddRefed<Promise> -Promise::All(const GlobalObject& aGlobal, +Promise::All(JSContext* aCx, const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv) { - nsCOMPtr<nsIGlobalObject> global; - global = do_QueryInterface(aGlobal.GetAsSupports()); - if (!global) { + JS::Rooted<JSObject*> globalObj(aCx, JS::CurrentGlobalOrNull(aCx)); + if (!globalObj) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } - JSContext* cx = aGlobal.Context(); + nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(globalObj); + if (!global) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } - JS::AutoObjectVector promises(cx); + JS::AutoObjectVector promises(aCx); if (!promises.reserve(aPromiseList.Length())) { - aRv.NoteJSContextException(cx); + aRv.NoteJSContextException(aCx); return nullptr; } for (auto& promise : aPromiseList) { - JS::Rooted<JSObject*> promiseObj(cx, promise->PromiseObj()); + JS::Rooted<JSObject*> promiseObj(aCx, promise->PromiseObj()); // Just in case, make sure these are all in the context compartment. - if (!JS_WrapObject(cx, &promiseObj)) { - aRv.NoteJSContextException(cx); + if (!JS_WrapObject(aCx, &promiseObj)) { + aRv.NoteJSContextException(aCx); return nullptr; } promises.infallibleAppend(promiseObj); } - JS::Rooted<JSObject*> result(cx, JS::GetWaitForAllPromise(cx, promises)); + JS::Rooted<JSObject*> result(aCx, JS::GetWaitForAllPromise(aCx, promises)); if (!result) { - aRv.NoteJSContextException(cx); + aRv.NoteJSContextException(aCx); return nullptr; } diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h index f2ad3bd6c..642603a11 100644 --- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -188,23 +188,26 @@ public: WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aWrapper); - // Do the equivalent of Promise.resolve in the current compartment of aCx. - // Errorrs are reported on the ErrorResult; if aRv comes back !Failed(), this - // function MUST return a non-null value. + // Do the equivalent of Promise.resolve in the compartment of aGlobal. The + // compartment of aCx is ignored. Errors are reported on the ErrorResult; if + // aRv comes back !Failed(), this function MUST return a non-null value. static already_AddRefed<Promise> Resolve(nsIGlobalObject* aGlobal, JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv); - // Do the equivalent of Promise.reject in the current compartment of aCx. - // Errorrs are reported on the ErrorResult; if aRv comes back !Failed(), this - // function MUST return a non-null value. + // Do the equivalent of Promise.reject in the compartment of aGlobal. The + // compartment of aCx is ignored. Errors are reported on the ErrorResult; if + // aRv comes back !Failed(), this function MUST return a non-null value. static already_AddRefed<Promise> Reject(nsIGlobalObject* aGlobal, JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv); + // Do the equivalent of Promise.all in the current compartment of aCx. Errors + // are reported on the ErrorResult; if aRv comes back !Failed(), this function + // MUST return a non-null value. static already_AddRefed<Promise> - All(const GlobalObject& aGlobal, - const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv); + All(JSContext* aCx, const nsTArray<RefPtr<Promise>>& aPromiseList, + ErrorResult& aRv); void Then(JSContext* aCx, diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index a7517f65e..979bd915f 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -171,9 +171,10 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType, } } - // aExtra is only non-null if the channel got redirected. - bool wasRedirected = (aExtra != nullptr); + // aExtra holds the original URI of the channel if the + // channel got redirected (until we fix Bug 1332422). nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra); + bool wasRedirected = originalURI; bool permitted = permitsInternal(dir, aContentLocation, diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index c4e1ed8e1..0cc4933fe 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -1,8 +1,10 @@ #include "nsContentSecurityManager.h" +#include "nsEscape.h" #include "nsIChannel.h" #include "nsIHttpChannelInternal.h" #include "nsIStreamListener.h" #include "nsILoadInfo.h" +#include "nsIOService.h" #include "nsContentUtils.h" #include "nsCORSListenerProxy.h" #include "nsIStreamListener.h" @@ -10,11 +12,86 @@ #include "nsMixedContentBlocker.h" #include "mozilla/dom/Element.h" +#include "mozilla/dom/TabChild.h" NS_IMPL_ISUPPORTS(nsContentSecurityManager, nsIContentSecurityManager, nsIChannelEventSink) +/* static */ bool +nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel) +{ + // Let's block all toplevel document navigations to a data: URI. + // In all cases where the toplevel document is navigated to a + // data: URI the triggeringPrincipal is a codeBasePrincipal, or + // a NullPrincipal. In other cases, e.g. typing a data: URL into + // the URL-Bar, the triggeringPrincipal is a SystemPrincipal; + // we don't want to block those loads. Only exception, loads coming + // from an external applicaton (e.g. Thunderbird) don't load + // using a codeBasePrincipal, but we want to block those loads. + if (!mozilla::net::nsIOService::BlockToplevelDataUriNavigations()) { + return true; + } + nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); + if (!loadInfo) { + return true; + } + if (loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) { + return true; + } + if (loadInfo->GetForceAllowDataURI()) { + // if the loadinfo explicitly allows the data URI navigation, let's allow it now + return true; + } + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, true); + bool isDataURI = + (NS_SUCCEEDED(uri->SchemeIs("data", &isDataURI)) && isDataURI); + if (!isDataURI) { + return true; + } + // Whitelist data: images as long as they are not SVGs + nsAutoCString filePath; + uri->GetFilePath(filePath); + if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/")) && + !StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/svg+xml"))) { + return true; + } + // Whitelist data: PDFs and JSON + if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/pdf")) || + StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/json"))) { + return true; + } + // Redirecting to a toplevel data: URI is not allowed, hence we make + // sure the RedirectChain is empty. + if (!loadInfo->GetLoadTriggeredFromExternal() && + nsContentUtils::IsSystemPrincipal(loadInfo->TriggeringPrincipal()) && + loadInfo->RedirectChain().IsEmpty()) { + return true; + } + nsAutoCString dataSpec; + uri->GetSpec(dataSpec); + if (dataSpec.Length() > 50) { + dataSpec.Truncate(50); + dataSpec.AppendLiteral("..."); + } + nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(loadInfo->ContextForTopLevelLoad()); + nsCOMPtr<nsIDocument> doc; + if (tabChild) { + doc = static_cast<mozilla::dom::TabChild*>(tabChild.get())->GetDocument(); + } + NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec)); + const char16_t* params[] = { specUTF16.get() }; + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("DATA_URI_BLOCKED"), + doc, + nsContentUtils::eSECURITY_PROPERTIES, + "BlockTopLevelDataURINavigation", + params, ArrayLength(params)); + return false; +} + static nsresult ValidateSecurityFlags(nsILoadInfo* aLoadInfo) { @@ -176,7 +253,7 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) nsContentPolicyType internalContentPolicyType = aLoadInfo->InternalContentPolicyType(); nsCString mimeTypeGuess; - nsCOMPtr<nsINode> requestingContext = nullptr; + nsCOMPtr<nsISupports> requestingContext = nullptr; #ifdef DEBUG // Don't enforce TYPE_DOCUMENT assertions for loads @@ -250,10 +327,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) case nsIContentPolicy::TYPE_XMLHTTPREQUEST: { // alias nsIContentPolicy::TYPE_DATAREQUEST: requestingContext = aLoadInfo->LoadingNode(); - MOZ_ASSERT(!requestingContext || - requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE, - "type_xml requires requestingContext of type Document"); - +#ifdef DEBUG + { + nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext); + MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE, + "type_xml requires requestingContext of type Document"); + } +#endif // We're checking for the external TYPE_XMLHTTPREQUEST here in case // an addon creates a request with that type. if (internalContentPolicyType == @@ -274,18 +354,26 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST: { mimeTypeGuess = EmptyCString(); requestingContext = aLoadInfo->LoadingNode(); - MOZ_ASSERT(!requestingContext || - requestingContext->NodeType() == nsIDOMNode::ELEMENT_NODE, - "type_subrequest requires requestingContext of type Element"); +#ifdef DEBUG + { + nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext); + MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::ELEMENT_NODE, + "type_subrequest requires requestingContext of type Element"); + } +#endif break; } case nsIContentPolicy::TYPE_DTD: { mimeTypeGuess = EmptyCString(); requestingContext = aLoadInfo->LoadingNode(); - MOZ_ASSERT(!requestingContext || - requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE, - "type_dtd requires requestingContext of type Document"); +#ifdef DEBUG + { + nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext); + MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE, + "type_dtd requires requestingContext of type Document"); + } +#endif break; } @@ -303,9 +391,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) mimeTypeGuess = EmptyCString(); } requestingContext = aLoadInfo->LoadingNode(); - MOZ_ASSERT(!requestingContext || - requestingContext->NodeType() == nsIDOMNode::ELEMENT_NODE, - "type_media requires requestingContext of type Element"); +#ifdef DEBUG + { + nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext); + MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::ELEMENT_NODE, + "type_media requires requestingContext of type Element"); + } +#endif break; } @@ -332,18 +424,26 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo) case nsIContentPolicy::TYPE_XSLT: { mimeTypeGuess = NS_LITERAL_CSTRING("application/xml"); requestingContext = aLoadInfo->LoadingNode(); - MOZ_ASSERT(!requestingContext || - requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE, - "type_xslt requires requestingContext of type Document"); +#ifdef DEBUG + { + nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext); + MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE, + "type_xslt requires requestingContext of type Document"); + } +#endif break; } case nsIContentPolicy::TYPE_BEACON: { mimeTypeGuess = EmptyCString(); requestingContext = aLoadInfo->LoadingNode(); - MOZ_ASSERT(!requestingContext || - requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE, - "type_beacon requires requestingContext of type Document"); +#ifdef DEBUG + { + nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext); + MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE, + "type_beacon requires requestingContext of type Document"); + } +#endif break; } diff --git a/dom/security/nsContentSecurityManager.h b/dom/security/nsContentSecurityManager.h index 912c0e89f..bab847743 100644 --- a/dom/security/nsContentSecurityManager.h +++ b/dom/security/nsContentSecurityManager.h @@ -32,6 +32,8 @@ public: static nsresult doContentSecurityCheck(nsIChannel* aChannel, nsCOMPtr<nsIStreamListener>& aInAndOutListener); + static bool AllowTopLevelNavigationToDataURI(nsIChannel* aChannel); + private: static nsresult CheckChannel(nsIChannel* aChannel); diff --git a/dom/security/test/general/browser.ini b/dom/security/test/general/browser.ini new file mode 100644 index 000000000..b00baa95d --- /dev/null +++ b/dom/security/test/general/browser.ini @@ -0,0 +1,14 @@ +[DEFAULT] +[browser_test_toplevel_data_navigations.js] +support-files = + file_toplevel_data_navigations.sjs + file_toplevel_data_meta_redirect.html +[browser_test_data_download.js] +support-files = + file_data_download.html +[browser_test_data_text_csv.js] +support-files = + file_data_text_csv.html +[browser_test_view_image_data_navigation.js] +support-files = + file_view_image_data_navigation.html diff --git a/dom/security/test/general/browser_test_data_download.js b/dom/security/test/general/browser_test_data_download.js new file mode 100644 index 000000000..1ee8d5844 --- /dev/null +++ b/dom/security/test/general/browser_test_data_download.js @@ -0,0 +1,37 @@ +"use strict"; + +const kTestPath = getRootDirectory(gTestPath) + .replace("chrome://mochitests/content", "http://example.com") +const kTestURI = kTestPath + "file_data_download.html"; + +function addWindowListener(aURL, aCallback) { + Services.wm.addListener({ + onOpenWindow(aXULWindow) { + info("window opened, waiting for focus"); + Services.wm.removeListener(this); + var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + waitForFocus(function() { + is(domwindow.document.location.href, aURL, "should have seen the right window open"); + aCallback(domwindow); + }, domwindow); + }, + onCloseWindow(aXULWindow) { }, + onWindowTitleChange(aXULWindow, aNewTitle) { } + }); +} + +function test() { + waitForExplicitFinish(); + Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true); + registerCleanupFunction(function() { + Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations"); + }); + addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) { + is(win.document.getElementById("location").value, "data-foo.html", + "file name of download should match"); + win.close(); + finish(); + }); + gBrowser.loadURI(kTestURI); +} diff --git a/dom/security/test/general/browser_test_data_text_csv.js b/dom/security/test/general/browser_test_data_text_csv.js new file mode 100644 index 000000000..c45e40cc2 --- /dev/null +++ b/dom/security/test/general/browser_test_data_text_csv.js @@ -0,0 +1,37 @@ +"use strict"; + +const kTestPath = getRootDirectory(gTestPath) + .replace("chrome://mochitests/content", "http://example.com") +const kTestURI = kTestPath + "file_data_text_csv.html"; + +function addWindowListener(aURL, aCallback) { + Services.wm.addListener({ + onOpenWindow(aXULWindow) { + info("window opened, waiting for focus"); + Services.wm.removeListener(this); + var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + waitForFocus(function() { + is(domwindow.document.location.href, aURL, "should have seen the right window open"); + aCallback(domwindow); + }, domwindow); + }, + onCloseWindow(aXULWindow) { }, + onWindowTitleChange(aXULWindow, aNewTitle) { } + }); +} + +function test() { + waitForExplicitFinish(); + Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true); + registerCleanupFunction(function() { + Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations"); + }); + addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) { + is(win.document.getElementById("location").value, "text/csv;foo,bar,foobar", + "file name of download should match"); + win.close(); + finish(); + }); + gBrowser.loadURI(kTestURI); +} diff --git a/dom/security/test/general/browser_test_toplevel_data_navigations.js b/dom/security/test/general/browser_test_toplevel_data_navigations.js new file mode 100644 index 000000000..a13a6350e --- /dev/null +++ b/dom/security/test/general/browser_test_toplevel_data_navigations.js @@ -0,0 +1,54 @@ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ + +"use strict"; + +const kDataBody = "toplevel navigation to data: URI allowed"; +const kDataURI = "data:text/html,<body>" + kDataBody + "</body>"; +const kTestPath = getRootDirectory(gTestPath) + .replace("chrome://mochitests/content", "http://example.com") +const kRedirectURI = kTestPath + "file_toplevel_data_navigations.sjs"; +const kMetaRedirectURI = kTestPath + "file_toplevel_data_meta_redirect.html"; + +add_task(async function test_nav_data_uri() { + await SpecialPowers.pushPrefEnv({ + "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]], + }); + await BrowserTestUtils.withNewTab(kDataURI, async function(browser) { + await ContentTask.spawn(gBrowser.selectedBrowser, {kDataBody}, async function({kDataBody}) { // eslint-disable-line + is(content.document.body.innerHTML, kDataBody, + "data: URI navigation from system should be allowed"); + }); + }); +}); + +add_task(async function test_nav_data_uri_redirect() { + await SpecialPowers.pushPrefEnv({ + "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]], + }); + let tab = BrowserTestUtils.addTab(gBrowser, kRedirectURI); + registerCleanupFunction(async function() { + await BrowserTestUtils.removeTab(tab); + }); + // wait to make sure data: URI did not load before checking that it got blocked + await new Promise(resolve => setTimeout(resolve, 500)); + await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() { + is(content.document.body.innerHTML, "", + "data: URI navigation after server redirect should be blocked"); + }); +}); + +add_task(async function test_nav_data_uri_meta_redirect() { + await SpecialPowers.pushPrefEnv({ + "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]], + }); + let tab = BrowserTestUtils.addTab(gBrowser, kMetaRedirectURI); + registerCleanupFunction(async function() { + await BrowserTestUtils.removeTab(tab); + }); + // wait to make sure data: URI did not load before checking that it got blocked + await new Promise(resolve => setTimeout(resolve, 500)); + await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() { + is(content.document.body.innerHTML, "", + "data: URI navigation after meta redirect should be blocked"); + }); +}); diff --git a/dom/security/test/general/browser_test_view_image_data_navigation.js b/dom/security/test/general/browser_test_view_image_data_navigation.js new file mode 100644 index 000000000..22de35894 --- /dev/null +++ b/dom/security/test/general/browser_test_view_image_data_navigation.js @@ -0,0 +1,30 @@ +"use strict"; + +const TEST_PAGE = getRootDirectory(gTestPath) + "file_view_image_data_navigation.html"; + +add_task(async function test_principal_right_click_open_link_in_new_tab() { + await SpecialPowers.pushPrefEnv({ + "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]], + }); + + await BrowserTestUtils.withNewTab(TEST_PAGE, async function(browser) { + let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, true); + + // simulate right-click->view-image + BrowserTestUtils.waitForEvent(document, "popupshown", false, event => { + // These are operations that must be executed synchronously with the event. + document.getElementById("context-viewimage").doCommand(); + event.target.hidePopup(); + return true; + }); + BrowserTestUtils.synthesizeMouseAtCenter("#testimage", + { type: "contextmenu", button: 2 }, + gBrowser.selectedBrowser); + await loadPromise; + + await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() { + ok(content.document.location.toString().startsWith("data:image/svg+xml;"), + "data:image/svg navigation allowed through right-click view-image") + }); + }); +}); diff --git a/dom/security/test/general/file_block_toplevel_data_navigation.html b/dom/security/test/general/file_block_toplevel_data_navigation.html new file mode 100644 index 000000000..5fbfdfdef --- /dev/null +++ b/dom/security/test/general/file_block_toplevel_data_navigation.html @@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Toplevel data navigation</title> +</head> +<body> +test1: clicking data: URI tries to navigate window<br/> +<a id="testlink" href="data:text/html,<body>toplevel data: URI navigations should be blocked</body>">click me</a> +<script> + document.getElementById('testlink').click(); +</script> +</body> +</html> diff --git a/dom/security/test/general/file_block_toplevel_data_navigation2.html b/dom/security/test/general/file_block_toplevel_data_navigation2.html new file mode 100644 index 000000000..e0308e1ae --- /dev/null +++ b/dom/security/test/general/file_block_toplevel_data_navigation2.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Toplevel data navigation</title> +</head> +<body> +test2: data: URI in iframe tries to window.open(data:, _blank);<br/> +<iframe id="testFrame" src=""></iframe> +<script> + let DATA_URI = `data:text/html,<body><script> + var win = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>", "_blank"); + setTimeout(function () { + var result = win.document.body.innerHTML === "" ? "blocked" : "navigated"; + parent.postMessage(result, "*"); + win.close(); + }, 1000); + <\/script></body>`; + + window.addEventListener("message", receiveMessage); + function receiveMessage(event) { + window.removeEventListener("message", receiveMessage); + // propagate the information back to the caller + window.opener.postMessage(event.data, "*"); + } + document.getElementById('testFrame').src = DATA_URI; +</script> +</body> +</html> diff --git a/dom/security/test/general/file_block_toplevel_data_navigation3.html b/dom/security/test/general/file_block_toplevel_data_navigation3.html new file mode 100644 index 000000000..34aeddab3 --- /dev/null +++ b/dom/security/test/general/file_block_toplevel_data_navigation3.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Toplevel data navigation</title> +</head> +<body> +test3: performing data: URI navigation through win.loc.href<br/> +<script> + window.location.href = "data:text/html,<body>toplevel data: URI navigations should be blocked</body>"; +</script> +</body> +</html> diff --git a/dom/security/test/general/file_block_toplevel_data_redirect.sjs b/dom/security/test/general/file_block_toplevel_data_redirect.sjs new file mode 100644 index 000000000..64e294cab --- /dev/null +++ b/dom/security/test/general/file_block_toplevel_data_redirect.sjs @@ -0,0 +1,14 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 1394554 - Block toplevel data: URI navigations after redirect + +var DATA_URI = + "<body>toplevel data: URI navigations after redirect should be blocked</body>"; + +function handleRequest(request, response) +{ + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", "data:text/html," + escape(DATA_URI), false); +} diff --git a/dom/security/test/general/file_data_download.html b/dom/security/test/general/file_data_download.html new file mode 100644 index 000000000..4cc92fe8f --- /dev/null +++ b/dom/security/test/general/file_data_download.html @@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test download attribute for data: URI</title> +</head> +<body> + <a href="data:text/html,<body>data download</body>" download="data-foo.html" id="testlink">download data</a> + <script> + // click the link to have the downoad panel appear + let testlink = document.getElementById("testlink"); + testlink.click(); + </script> + </body> +</html> diff --git a/dom/security/test/general/file_data_text_csv.html b/dom/security/test/general/file_data_text_csv.html new file mode 100644 index 000000000..a9ac369d1 --- /dev/null +++ b/dom/security/test/general/file_data_text_csv.html @@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test open data:text/csv</title> +</head> +<body> + <a href="data:text/csv;foo,bar,foobar" id="testlink">test text/csv</a> + <script> + // click the link to have the downoad panel appear + let testlink = document.getElementById("testlink"); + testlink.click(); + </script> + </body> +</html> diff --git a/dom/security/test/general/file_toplevel_data_meta_redirect.html b/dom/security/test/general/file_toplevel_data_meta_redirect.html new file mode 100644 index 000000000..f4f5deb52 --- /dev/null +++ b/dom/security/test/general/file_toplevel_data_meta_redirect.html @@ -0,0 +1,10 @@ +<html>
+<body>
+<head>
+ <meta http-equiv="refresh"
+ content="0; url='data:text/html,<body>toplevel meta redirect to data: URI should be blocked</body>'">
+</head>
+<body>
+Meta Redirect to data: URI
+</body>
+</html>
diff --git a/dom/security/test/general/file_toplevel_data_navigations.sjs b/dom/security/test/general/file_toplevel_data_navigations.sjs new file mode 100644 index 000000000..501b833e5 --- /dev/null +++ b/dom/security/test/general/file_toplevel_data_navigations.sjs @@ -0,0 +1,14 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 1394554 - Block toplevel data: URI navigations after redirect + +var DATA_URI = + "data:text/html,<body>toplevel data: URI navigations after redirect should be blocked</body>"; + +function handleRequest(request, response) +{ + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", DATA_URI, false); +} diff --git a/dom/security/test/general/file_view_image_data_navigation.html b/dom/security/test/general/file_view_image_data_navigation.html new file mode 100644 index 000000000..a3f9acfb4 --- /dev/null +++ b/dom/security/test/general/file_view_image_data_navigation.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1407891: Test navigation for right-click view-image on data:image/svg</title> +</head> +<body> + +<img id="testimage" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg=="></img> + +</body> +</html> diff --git a/dom/security/test/general/mochitest.ini b/dom/security/test/general/mochitest.ini index 70c0c9fb6..f3bcca072 100644 --- a/dom/security/test/general/mochitest.ini +++ b/dom/security/test/general/mochitest.ini @@ -3,7 +3,19 @@ support-files = file_contentpolicytype_targeted_link_iframe.sjs file_nosniff_testserver.sjs file_block_script_wrong_mime_server.sjs + file_block_toplevel_data_navigation.html + file_block_toplevel_data_navigation2.html + file_block_toplevel_data_navigation3.html + file_block_toplevel_data_redirect.sjs [test_contentpolicytype_targeted_link_iframe.html] [test_nosniff.html] [test_block_script_wrong_mime.html] +[test_block_toplevel_data_navigation.html] +skip-if = toolkit == 'android' # intermittent failure +[test_block_toplevel_data_img_navigation.html] +skip-if = toolkit == 'android' # intermittent failure +[test_allow_opening_data_pdf.html] +skip-if = toolkit == 'android' +[test_allow_opening_data_json.html] +skip-if = toolkit == 'android' diff --git a/dom/security/test/general/test_allow_opening_data_json.html b/dom/security/test/general/test_allow_opening_data_json.html new file mode 100644 index 000000000..1530a24e8 --- /dev/null +++ b/dom/security/test/general/test_allow_opening_data_json.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1403814: Allow toplevel data URI navigation data:application/json</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +function test_toplevel_data_json() { + const DATA_JSON = "data:application/json,{'my_json_key':'my_json_value'}"; + + let win = window.open(DATA_JSON); + let wrappedWin = SpecialPowers.wrap(win); + + // Unfortunately we can't detect whether the JSON has loaded or not using some + // event, hence we are constantly polling location.href till we see that + // the data: URI appears. Test times out on failure. + var jsonLoaded = setInterval(function() { + if (wrappedWin.document.location.href.startsWith("data:application/json")) { + clearInterval(jsonLoaded); + ok(true, "navigating to data:application/json allowed"); + wrappedWin.close(); + SimpleTest.finish(); + } + }, 200); +} + +SpecialPowers.pushPrefEnv({ + set: [["security.data_uri.block_toplevel_data_uri_navigations", true]] +}, test_toplevel_data_json); + +</script> +</body> +</html> diff --git a/dom/security/test/general/test_allow_opening_data_pdf.html b/dom/security/test/general/test_allow_opening_data_pdf.html new file mode 100644 index 000000000..6b51fe57b --- /dev/null +++ b/dom/security/test/general/test_allow_opening_data_pdf.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1398692: Allow toplevel navigation to a data:application/pdf</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +function test_toplevel_data_pdf() { + // The PDF contains one page and it is a 3/72" square, the minimum allowed by the spec + const DATA_PDF = + "data:application/pdf;base64,JVBERi0xLjANCjEgMCBvYmo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PmVuZG9iaiAyIDAgb2JqPDwvVHlwZS9QYWdlcy9LaWRzWzMgMCBSXS9Db3VudCAxPj5lbmRvYmogMyAwIG9iajw8L1R5cGUvUGFnZS9NZWRpYUJveFswIDAgMyAzXT4+ZW5kb2JqDQp4cmVmDQowIDQNCjAwMDAwMDAwMDAgNjU1MzUgZg0KMDAwMDAwMDAxMCAwMDAwMCBuDQowMDAwMDAwMDUzIDAwMDAwIG4NCjAwMDAwMDAxMDIgMDAwMDAgbg0KdHJhaWxlcjw8L1NpemUgNC9Sb290IDEgMCBSPj4NCnN0YXJ0eHJlZg0KMTQ5DQolRU9G"; + + let win = window.open(DATA_PDF); + let wrappedWin = SpecialPowers.wrap(win); + + // Unfortunately we can't detect whether the PDF has loaded or not using some + // event, hence we are constantly polling location.href till we see that + // the data: URI appears. Test times out on failure. + var pdfLoaded = setInterval(function() { + if (wrappedWin.document.location.href.startsWith("data:application/pdf")) { + clearInterval(pdfLoaded); + ok(true, "navigating to data:application/pdf allowed"); + wrappedWin.close(); + SimpleTest.finish(); + } + }, 200); +} + +SpecialPowers.pushPrefEnv({ + set: [["security.data_uri.block_toplevel_data_uri_navigations", true]] +}, test_toplevel_data_pdf); + +</script> +</body> +</html> diff --git a/dom/security/test/general/test_block_toplevel_data_img_navigation.html b/dom/security/test/general/test_block_toplevel_data_img_navigation.html new file mode 100644 index 000000000..7f8dfc748 --- /dev/null +++ b/dom/security/test/general/test_block_toplevel_data_img_navigation.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1396798: Do not block toplevel data: navigation to image (except svgs)</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script class="testbody" type="text/javascript"> +SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true); +SimpleTest.registerCleanupFunction(() => { + SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations"); +}); + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("have to test that top level data:image loading is blocked/allowed"); + +function test_toplevel_data_image() { + const DATA_PNG = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; + let win1 = window.open(DATA_PNG); + let wrappedWin1 = SpecialPowers.wrap(win1); + setTimeout(function () { + let images = wrappedWin1.document.getElementsByTagName('img'); + is(images.length, 1, "Loading data:image/png should be allowed"); + is(images[0].src, DATA_PNG, "Sanity: img src matches"); + wrappedWin1.close(); + test_toplevel_data_image_svg(); + }, 1000); +} + +function test_toplevel_data_image_svg() { + const DATA_SVG = + "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg=="; + let win2 = window.open(DATA_SVG); + // Unfortunately we can't detect whether the window was closed using some event, + // hence we are constantly polling till we see that win == null. + // Test times out on failure. + var win2Closed = setInterval(function() { + if (win2 == null || win2.closed) { + clearInterval(win2Closed); + ok(true, "Loading data:image/svg+xml should be blocked"); + SimpleTest.finish(); + } + }, 200); +} +// fire up the tests +test_toplevel_data_image(); + +</script> +</body> +</html> diff --git a/dom/security/test/general/test_block_toplevel_data_navigation.html b/dom/security/test/general/test_block_toplevel_data_navigation.html new file mode 100644 index 000000000..cef232b65 --- /dev/null +++ b/dom/security/test/general/test_block_toplevel_data_navigation.html @@ -0,0 +1,86 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1331351 - Block top level window data: URI navigations</title> + <!-- Including SimpleTest.js so we can use waitForExplicitFinish !--> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script class="testbody" type="text/javascript"> +SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true); +SimpleTest.registerCleanupFunction(() => { + SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations"); +}); + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("have to test that top level data: URI navgiation is blocked"); + +function test1() { + // simple data: URI click navigation should be prevented + let TEST_FILE = "file_block_toplevel_data_navigation.html"; + let win1 = window.open(TEST_FILE); + setTimeout(function () { + ok(SpecialPowers.wrap(win1).document.body.innerHTML.indexOf("test1:") !== -1, + "toplevel data: URI navigation through click() should be blocked"); + win1.close(); + test2(); + }, 1000); +} + +function test2() { + // data: URI in iframe which opens data: URI in _blank should be blocked + let win2 = window.open("file_block_toplevel_data_navigation2.html"); + window.addEventListener("message", receiveMessage); + function receiveMessage(event) { + window.removeEventListener("message", receiveMessage); + is(event.data, "blocked", + "data: URI navigation using _blank from data: URI should be blocked"); + win2.close(); + test3(); + } +} + +function test3() { + // navigating to a data: URI using window.location.href should be blocked + let win3 = window.open("file_block_toplevel_data_navigation3.html"); + setTimeout(function () { + ok(win3.document.body.innerHTML.indexOf("test3:") !== -1, + "data: URI navigation through win.loc.href should be blocked"); + win3.close(); + test4(); + }, 1000); +} + +function test4() { + // navigating to a data: URI using window.open() should be blocked + let win4 = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>"); + setTimeout(function () { + // Please note that the data: URI will be displayed in the URL-Bar but not + // loaded, hence we rather rely on document.body than document.location + is(win4.document.body.innerHTML, "", + "navigating to a data: URI using window.open() should be blocked"); + test5(); + }, 1000); +} + +function test5() { + // navigating to a URI which redirects to a data: URI using window.open() should be blocked + let win5 = window.open("file_block_toplevel_data_redirect.sjs"); + setTimeout(function () { + // Please note that the data: URI will be displayed in the URL-Bar but not + // loaded, hence we rather rely on document.body than document.location + is(SpecialPowers.wrap(win5).document.body.innerHTML, "", + "navigating to URI which redirects to a data: URI using window.open() should be blocked"); + win5.close(); + SimpleTest.finish(); + }, 1000); +} + +// fire up the tests +test1(); + +</script> +</body> +</html> diff --git a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html index 7b1ab72dc..3ef243824 100644 --- a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html +++ b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html @@ -61,6 +61,7 @@ var policy = { "content policy type should TYPESUBDOCUMENT"); categoryManager.deleteCategoryEntry("content-policy", POLICYNAME, false); SimpleTest.finish(); + return Ci.nsIContentPolicy.REJECT_REQUEST; } return Ci.nsIContentPolicy.ACCEPT; }, diff --git a/dom/security/test/moz.build b/dom/security/test/moz.build index ddb4e9b89..946959dee 100644 --- a/dom/security/test/moz.build +++ b/dom/security/test/moz.build @@ -27,5 +27,6 @@ MOCHITEST_CHROME_MANIFESTS += [ BROWSER_CHROME_MANIFESTS += [ 'contentverifier/browser.ini', 'csp/browser.ini', + 'general/browser.ini', 'hsts/browser.ini', ] diff --git a/dom/svg/SVGClipPathElement.cpp b/dom/svg/SVGClipPathElement.cpp index 60d72fdf0..682d1271e 100644 --- a/dom/svg/SVGClipPathElement.cpp +++ b/dom/svg/SVGClipPathElement.cpp @@ -50,6 +50,13 @@ SVGClipPathElement::GetEnumInfo() ArrayLength(sEnumInfo)); } +bool +SVGClipPathElement::IsUnitsObjectBoundingBox() const +{ + return mEnumAttributes[CLIPPATHUNITS].GetAnimValue() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; +} + + //---------------------------------------------------------------------- // nsIDOMNode methods diff --git a/dom/svg/SVGClipPathElement.h b/dom/svg/SVGClipPathElement.h index d84f5b30f..2d9f4c15e 100644 --- a/dom/svg/SVGClipPathElement.h +++ b/dom/svg/SVGClipPathElement.h @@ -36,6 +36,10 @@ public: // WebIDL already_AddRefed<SVGAnimatedEnumeration> ClipPathUnits(); + // This is an internal method that does not flush style, and thus + // the answer may be out of date if there's a pending style flush. + bool IsUnitsObjectBoundingBox() const; + protected: enum { CLIPPATHUNITS }; diff --git a/dom/svg/SVGTextContentElement.h b/dom/svg/SVGTextContentElement.h index 905468228..5f126c811 100644 --- a/dom/svg/SVGTextContentElement.h +++ b/dom/svg/SVGTextContentElement.h @@ -29,6 +29,7 @@ typedef SVGGraphicsElement SVGTextContentElementBase; class SVGTextContentElement : public SVGTextContentElementBase { + friend class ::SVGTextFrame; public: using FragmentOrElement::TextLength; diff --git a/dom/url/URL.cpp b/dom/url/URL.cpp index 1f15e1151..c8724c359 100644 --- a/dom/url/URL.cpp +++ b/dom/url/URL.cpp @@ -17,7 +17,6 @@ #include "nsEscape.h" #include "nsHostObjectProtocolHandler.h" #include "nsIIOService.h" -#include "nsIURIWithQuery.h" #include "nsIURL.h" #include "nsNetCID.h" #include "nsNetUtil.h" @@ -525,21 +524,10 @@ URLMainThread::GetPathname(nsAString& aPathname, ErrorResult& aRv) const // Do not throw! Not having a valid URI or URL should result in an empty // string. - nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI)); - if (url) { - nsAutoCString file; - nsresult rv = url->GetFilePath(file); - if (NS_SUCCEEDED(rv)) { - CopyUTF8toUTF16(file, aPathname); - } - - return; - } - - nsAutoCString path; - nsresult rv = mURI->GetPath(path); + nsAutoCString file; + nsresult rv = mURI->GetFilePath(file); if (NS_SUCCEEDED(rv)) { - CopyUTF8toUTF16(path, aPathname); + CopyUTF8toUTF16(file, aPathname); } } @@ -548,11 +536,7 @@ URLMainThread::SetPathname(const nsAString& aPathname, ErrorResult& aRv) { // Do not throw! - nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI)); - if (url) { - url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)); - return; - } + mURI->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)); } void @@ -566,13 +550,9 @@ URLMainThread::GetSearch(nsAString& aSearch, ErrorResult& aRv) const nsAutoCString search; nsresult rv; - nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI)); - if (url) { - rv = url->GetQuery(search); - if (NS_SUCCEEDED(rv) && !search.IsEmpty()) { - CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch); - } - return; + rv = mURI->GetQuery(search); + if (NS_SUCCEEDED(rv) && !search.IsEmpty()) { + CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch); } } @@ -603,11 +583,7 @@ URLMainThread::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) { // Ignore failures to be compatible with NS4. - nsCOMPtr<nsIURIWithQuery> uriWithQuery(do_QueryInterface(mURI)); - if (uriWithQuery) { - uriWithQuery->SetQuery(NS_ConvertUTF16toUTF8(aSearch)); - return; - } + mURI->SetQuery(NS_ConvertUTF16toUTF8(aSearch)); } } // anonymous namespace diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index f05656e84..0b8c278fe 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -430,6 +430,12 @@ partial interface Document { void removeAnonymousContent(AnonymousContent aContent); }; +// http://w3c.github.io/selection-api/#extensions-to-document-interface +partial interface Document { + [Throws] + Selection? getSelection(); +}; + // Extension to give chrome JS the ability to determine whether // the user has interacted with the document or not. partial interface Document { diff --git a/dom/webidl/HTMLDocument.webidl b/dom/webidl/HTMLDocument.webidl index 61b466ff0..42f6d98f7 100644 --- a/dom/webidl/HTMLDocument.webidl +++ b/dom/webidl/HTMLDocument.webidl @@ -73,10 +73,6 @@ interface HTMLDocument : Document { readonly attribute HTMLAllCollection all; - // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections - [Throws] - Selection? getSelection(); - // @deprecated These are old Netscape 4 methods. Do not use, // the implementation is no-op. // XXXbz do we actually need these anymore? diff --git a/dom/webidl/PointerEvent.webidl b/dom/webidl/PointerEvent.webidl index 2e83922c8..4e8a0eb90 100644 --- a/dom/webidl/PointerEvent.webidl +++ b/dom/webidl/PointerEvent.webidl @@ -17,8 +17,10 @@ interface PointerEvent : MouseEvent readonly attribute long width; readonly attribute long height; readonly attribute float pressure; + readonly attribute float tangentialPressure; readonly attribute long tiltX; readonly attribute long tiltY; + readonly attribute long twist; readonly attribute DOMString pointerType; readonly attribute boolean isPrimary; }; @@ -29,8 +31,10 @@ dictionary PointerEventInit : MouseEventInit long width = 1; long height = 1; float pressure = 0; + float tangentialPressure = 0; long tiltX = 0; long tiltY = 0; + long twist = 0; DOMString pointerType = ""; boolean isPrimary = false; }; diff --git a/dom/webidl/Response.webidl b/dom/webidl/Response.webidl index 8713146aa..08f31fe29 100644 --- a/dom/webidl/Response.webidl +++ b/dom/webidl/Response.webidl @@ -7,7 +7,7 @@ * https://fetch.spec.whatwg.org/#response-class */ -[Constructor(optional BodyInit body, optional ResponseInit init), +[Constructor(optional BodyInit? body, optional ResponseInit init), Exposed=(Window,Worker)] interface Response { [NewObject] static Response error(); diff --git a/dom/webidl/Selection.webidl b/dom/webidl/Selection.webidl index c90844dfa..c3eac016c 100644 --- a/dom/webidl/Selection.webidl +++ b/dom/webidl/Selection.webidl @@ -33,6 +33,7 @@ interface Selection { void deleteFromDocument(); readonly attribute unsigned long rangeCount; + readonly attribute DOMString type; [Throws] Range getRangeAt(unsigned long index); [Throws] @@ -77,7 +78,7 @@ partial interface Selection { void removeSelectionListener(nsISelectionListener listenerToRemove); [ChromeOnly,BinaryName="rawType"] - readonly attribute short type; + readonly attribute short selectionType; [ChromeOnly,Throws,Pref="dom.testing.selection.GetRangesForInterval"] sequence<Range> GetRangesForInterval(Node beginNode, long beginOffset, Node endNode, long endOffset, diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index 09b09a24b..780b2f5f8 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -948,10 +948,8 @@ ExtendableEvent::GetPromise() } JSContext* cx = jsapi.cx(); - GlobalObject global(cx, globalObj->GetGlobalJSObject()); - ErrorResult result; - RefPtr<Promise> p = Promise::All(global, Move(mPromises), result); + RefPtr<Promise> p = Promise::All(cx, Move(mPromises), result); if (NS_WARN_IF(result.MaybeSetPendingException(cx))) { return nullptr; } diff --git a/editor/libeditor/HTMLEditorDataTransfer.cpp b/editor/libeditor/HTMLEditorDataTransfer.cpp index ed350c0dd..c56fbead7 100644 --- a/editor/libeditor/HTMLEditorDataTransfer.cpp +++ b/editor/libeditor/HTMLEditorDataTransfer.cpp @@ -1538,6 +1538,13 @@ HTMLEditor::CanPaste(int32_t aSelectionType, NS_ENSURE_ARG_POINTER(aCanPaste); *aCanPaste = false; + // Always enable the paste command when inside of a HTML or XHTML document. + nsCOMPtr<nsIDocument> doc = GetDocument(); + if (doc && doc->IsHTMLOrXHTML()) { + *aCanPaste = true; + return NS_OK; + } + // can't paste if readonly if (!IsModifiable()) { return NS_OK; diff --git a/editor/libeditor/TextEditorDataTransfer.cpp b/editor/libeditor/TextEditorDataTransfer.cpp index 0388aa4a8..2cc2906fa 100644 --- a/editor/libeditor/TextEditorDataTransfer.cpp +++ b/editor/libeditor/TextEditorDataTransfer.cpp @@ -383,6 +383,13 @@ TextEditor::CanPaste(int32_t aSelectionType, NS_ENSURE_ARG_POINTER(aCanPaste); *aCanPaste = false; + // Always enable the paste command when inside of a HTML or XHTML document. + nsCOMPtr<nsIDocument> doc = GetDocument(); + if (doc && doc->IsHTMLOrXHTML()) { + *aCanPaste = true; + return NS_OK; + } + // can't paste if readonly if (!IsModifiable()) { return NS_OK; diff --git a/editor/libeditor/tests/chrome.ini b/editor/libeditor/tests/chrome.ini index 98db30001..dd13370a5 100644 --- a/editor/libeditor/tests/chrome.ini +++ b/editor/libeditor/tests/chrome.ini @@ -12,3 +12,4 @@ support-files = green.png [test_set_document_title_transaction.html] [test_texteditor_keyevent_handling.html] skip-if = (debug && os=='win') || (os == 'linux') # Bug 1116205, leaks on windows debug, fails delete key on linux +[test_pasteImgTextarea.xul] diff --git a/editor/libeditor/tests/mochitest.ini b/editor/libeditor/tests/mochitest.ini index 4df3f606b..33b164819 100644 --- a/editor/libeditor/tests/mochitest.ini +++ b/editor/libeditor/tests/mochitest.ini @@ -247,3 +247,5 @@ skip-if = toolkit == 'android' [test_css_chrome_load_access.html] skip-if = toolkit == 'android' # chrome urls not available due to packaging [test_selection_move_commands.html] +[test_pasteImgTextarea.html] +skip-if = toolkit == 'android' # bug 1299578 diff --git a/editor/libeditor/tests/test_pasteImgTextarea.html b/editor/libeditor/tests/test_pasteImgTextarea.html new file mode 100644 index 000000000..3168ae729 --- /dev/null +++ b/editor/libeditor/tests/test_pasteImgTextarea.html @@ -0,0 +1,20 @@ +<!doctype html> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/SpawnTask.js"></script> +<img id="i" src="green.png"> +<textarea id="t"></textarea> + +<script> +let loaded = new Promise(resolve => addLoadEvent(resolve)); + add_task(function*() { + yield loaded; + SpecialPowers.setCommandNode(window, document.getElementById("i")); + SpecialPowers.doCommand(window, "cmd_copyImageContents"); + let input = document.getElementById("t"); + input.focus(); + var controller = + SpecialPowers.wrap(input).controllers.getControllerForCommand("cmd_paste"); + is(controller.isCommandEnabled("cmd_paste"), true, + "paste should be enabled in html textareas when an image is on the clipboard"); + }); +</script> diff --git a/editor/libeditor/tests/test_pasteImgTextarea.xul b/editor/libeditor/tests/test_pasteImgTextarea.xul new file mode 100644 index 000000000..545027aa3 --- /dev/null +++ b/editor/libeditor/tests/test_pasteImgTextarea.xul @@ -0,0 +1,27 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> +<window xmlns:html="http://www.w3.org/1999/xhtml" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script> + + <body xmlns="http://www.w3.org/1999/xhtml"> + <html:img id="i" src="green.png" /> + <html:textarea id="t"></html:textarea> + </body> + <script type="text/javascript"><![CDATA[ + let loaded = new Promise(resolve => addLoadEvent(resolve)); + add_task(function*() { + yield loaded; + SpecialPowers.setCommandNode(window, document.getElementById("i")); + SpecialPowers.doCommand(window, "cmd_copyImageContents"); + let input = document.getElementById("t"); + input.focus(); + var controller = + SpecialPowers.wrap(input).controllers.getControllerForCommand("cmd_paste"); + is(controller.isCommandEnabled("cmd_paste"), false, + "paste should not be enabled in xul textareas when an image is on the clipboard"); + }); + ]]></script> +</window> diff --git a/gfx/2d/FilterNodeSoftware.cpp b/gfx/2d/FilterNodeSoftware.cpp index 3abdb7a02..169694069 100644 --- a/gfx/2d/FilterNodeSoftware.cpp +++ b/gfx/2d/FilterNodeSoftware.cpp @@ -2796,7 +2796,7 @@ FilterNodeArithmeticCombineSoftware::SetAttribute(uint32_t aIndex, uint32_t aSize) { MOZ_ASSERT(aIndex == ATT_ARITHMETIC_COMBINE_COEFFICIENTS); - MOZ_ASSERT(aSize == 4); + MOZ_RELEASE_ASSERT(aSize == 4); mK1 = aFloat[0]; mK2 = aFloat[1]; diff --git a/gfx/gl/GLTextureImage.cpp b/gfx/gl/GLTextureImage.cpp index c91d558af..65678432d 100644 --- a/gfx/gl/GLTextureImage.cpp +++ b/gfx/gl/GLTextureImage.cpp @@ -149,6 +149,9 @@ BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion &uploadSize, needInit, aFrom); + if (mTextureFormat == SurfaceFormat::UNKNOWN) { + return false; + } if (uploadSize > 0) { UpdateUploadSize(uploadSize); diff --git a/gfx/gl/GLUploadHelpers.cpp b/gfx/gl/GLUploadHelpers.cpp index 75165eedf..ca1c890a4 100644 --- a/gfx/gl/GLUploadHelpers.cpp +++ b/gfx/gl/GLUploadHelpers.cpp @@ -27,6 +27,23 @@ DataOffset(const IntPoint& aPoint, int32_t aStride, SurfaceFormat aFormat) return data; } +static bool +CheckUploadBounds(const IntSize& aDst, const IntSize& aSrc, const IntPoint& aOffset) +{ + if (aOffset.x < 0 || aOffset.y < 0 || + aOffset.x >= aSrc.width || + aOffset.y >= aSrc.height) { + MOZ_ASSERT_UNREACHABLE("Offset outside source bounds"); + return false; + } + if (aDst.width > (aSrc.width - aOffset.x) || + aDst.height > (aSrc.height - aOffset.y)) { + MOZ_ASSERT_UNREACHABLE("Source has insufficient data"); + return false; + } + return true; +} + static GLint GetAddressAlignment(ptrdiff_t aAddress) { if (!(aAddress & 0x7)) { @@ -375,6 +392,7 @@ TexImage2DHelper(GLContext* gl, SurfaceFormat UploadImageDataToTexture(GLContext* gl, unsigned char* aData, + const gfx::IntSize& aDataSize, int32_t aStride, SurfaceFormat aFormat, const nsIntRegion& aDstRegion, @@ -498,6 +516,10 @@ UploadImageDataToTexture(GLContext* gl, // Upload each rect in the region to the texture for (auto iter = aDstRegion.RectIter(); !iter.Done(); iter.Next()) { const IntRect& rect = iter.Get(); + if (!CheckUploadBounds(rect.Size(), aDataSize, rect.TopLeft())) { + return SurfaceFormat::UNKNOWN; + } + const unsigned char* rectData = aData + DataOffset(rect.TopLeft(), aStride, aFormat); @@ -534,10 +556,17 @@ UploadSurfaceToTexture(GLContext* gl, int32_t stride = aSurface->Stride(); SurfaceFormat format = aSurface->GetFormat(); + gfx::IntSize size = aSurface->GetSize(); + if (!CheckUploadBounds(aSize, size, aSrcPoint)) { + return SurfaceFormat::UNKNOWN; + } + unsigned char* data = aSurface->GetData() + DataOffset(aSrcPoint, stride, format); + size.width -= aSrcPoint.x; + size.height -= aSrcPoint.y; - return UploadImageDataToTexture(gl, data, stride, format, + return UploadImageDataToTexture(gl, data, size, stride, format, aDstRegion, aTexture, aSize, aOutUploadSize, aNeedInit, aTextureUnit, aTextureTarget); diff --git a/gfx/gl/GLUploadHelpers.h b/gfx/gl/GLUploadHelpers.h index 866d44adb..f732d2b38 100644 --- a/gfx/gl/GLUploadHelpers.h +++ b/gfx/gl/GLUploadHelpers.h @@ -28,6 +28,7 @@ class GLContext; * \param gl The GL Context to use. * \param aData Start of image data of surface to upload. * Corresponds to the first pixel of the texture. + * \param aDataSize The image data's size. * \param aStride The image data's stride. * \param aFormat The image data's format. * \param aDstRegion Region of the texture to upload. @@ -46,6 +47,7 @@ class GLContext; gfx::SurfaceFormat UploadImageDataToTexture(GLContext* gl, unsigned char* aData, + const gfx::IntSize& aDataSize, int32_t aStride, gfx::SurfaceFormat aFormat, const nsIntRegion& aDstRegion, diff --git a/gfx/gl/TextureImageEGL.cpp b/gfx/gl/TextureImageEGL.cpp index 87a547c26..3bb2987d1 100644 --- a/gfx/gl/TextureImageEGL.cpp +++ b/gfx/gl/TextureImageEGL.cpp @@ -119,6 +119,10 @@ TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& &uploadSize, needInit, aFrom); + if (mTextureFormat == SurfaceFormat::UNKNOWN) { + return false; + } + if (uploadSize > 0) { UpdateUploadSize(uploadSize); } diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index e7d87e238..c93037384 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -888,8 +888,7 @@ BufferTextureHost::Upload(nsIntRegion *aRegion) mFirstSource = mCompositor->CreateDataTextureSource(mFlags|TextureFlags::RGB_FROM_YCBCR); mFirstSource->SetOwner(this); } - mFirstSource->Update(surf, aRegion); - return true; + return mFirstSource->Update(surf, aRegion); } RefPtr<DataTextureSource> srcY; diff --git a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp index c05b8edfd..a1521c56d 100644 --- a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp +++ b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp @@ -60,7 +60,7 @@ CompositingRenderTargetOGL::BindRenderTarget() msg.AppendPrintf("Framebuffer not complete -- CheckFramebufferStatus returned 0x%x, " "GLContext=%p, IsOffscreen()=%d, mFBO=%d, aFBOTextureTarget=0x%x, " "aRect.width=%d, aRect.height=%d", - result, mGL, mGL->IsOffscreen(), mFBO, mInitParams.mFBOTextureTarget, + result, mGL.get(), mGL->IsOffscreen(), mFBO, mInitParams.mFBOTextureTarget, mInitParams.mSize.width, mInitParams.mSize.height); NS_WARNING(msg.get()); } diff --git a/gfx/layers/opengl/CompositingRenderTargetOGL.h b/gfx/layers/opengl/CompositingRenderTargetOGL.h index 501701d6f..071dc5cac 100644 --- a/gfx/layers/opengl/CompositingRenderTargetOGL.h +++ b/gfx/layers/opengl/CompositingRenderTargetOGL.h @@ -184,7 +184,7 @@ private: * the target is always cleared at the end of a frame. */ RefPtr<CompositorOGL> mCompositor; - GLContext* mGL; + RefPtr<GLContext> mGL; GLuint mTextureHandle; GLuint mFBO; }; diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index 02c398b51..ec6ba9131 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -161,9 +161,7 @@ TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface, } } - mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset); - - return true; + return mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset); } void diff --git a/gfx/skia/skia/include/core/SkTypes.h b/gfx/skia/skia/include/core/SkTypes.h index 0cef8a125..f45c3c2b7 100644 --- a/gfx/skia/skia/include/core/SkTypes.h +++ b/gfx/skia/skia/include/core/SkTypes.h @@ -109,6 +109,11 @@ SK_API extern void* sk_calloc(size_t size); */ SK_API extern void* sk_calloc_throw(size_t size); +// Performs a safe multiply count * elemSize, checking for overflow +SK_API extern void* sk_calloc_throw(size_t count, size_t elemSize); +SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize); +SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize); + // bzero is safer than memset, but we can't rely on it, so... sk_bzero() static inline void sk_bzero(void* buffer, size_t size) { // Please c.f. sk_careful_memcpy. It's undefined behavior to call memset(null, 0, 0). @@ -295,6 +300,7 @@ template <typename D, typename S> D SkTo(S s) { #define SK_MaxU32 0xFFFFFFFF #define SK_MinU32 0 #define SK_NaN32 ((int) (1U << 31)) +#define SK_MaxSizeT SIZE_MAX /** Returns true if the value can be represented with signed 16bits */ diff --git a/gfx/skia/skia/include/private/SkTDArray.h b/gfx/skia/skia/include/private/SkTDArray.h index f71d35700..a46a05e9d 100644 --- a/gfx/skia/skia/include/private/SkTDArray.h +++ b/gfx/skia/skia/include/private/SkTDArray.h @@ -21,7 +21,7 @@ public: fReserve = fCount = 0; fArray = NULL; if (count) { - fArray = (T*)sk_malloc_throw(count * sizeof(T)); + fArray = (T*)sk_malloc_throw(count, sizeof(T)); memcpy(fArray, src, sizeof(T) * count); fReserve = fCount = count; } @@ -346,7 +346,7 @@ public: void shrinkToFit() { fReserve = fCount; - fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T)); + fArray = (T*)sk_realloc_throw(fArray, fReserve, sizeof(T)); } private: @@ -359,6 +359,7 @@ private: * This is the same as calling setCount(count() + delta). */ void adjustCount(int delta) { + SkASSERT_RELEASE(fCount <= std::numeric_limits<int>::max() - delta); this->setCount(fCount + delta); } @@ -372,9 +373,10 @@ private: */ void resizeStorageToAtLeast(int count) { SkASSERT(count > fReserve); + SkASSERT_RELEASE(count <= std::numeric_limits<int>::max() - std::numeric_limits<int>::max() / 5 - 4); fReserve = count + 4; fReserve += fReserve / 4; - fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T)); + fArray = (T*)sk_realloc_throw(fArray, fReserve, sizeof(T)); } }; diff --git a/gfx/skia/skia/src/core/SkMallocPixelRef.cpp b/gfx/skia/skia/src/core/SkMallocPixelRef.cpp index fffc04484..8db704fa4 100644 --- a/gfx/skia/skia/src/core/SkMallocPixelRef.cpp +++ b/gfx/skia/skia/src/core/SkMallocPixelRef.cpp @@ -8,8 +8,21 @@ #include "SkMallocPixelRef.h" #include "SkBitmap.h" #include "SkReadBuffer.h" +#include "SkSafeMath.h" #include "SkWriteBuffer.h" +void* sk_calloc_throw(size_t count, size_t elemSize) { + return sk_calloc_throw(SkSafeMath::Mul(count, elemSize)); +} + +void* sk_malloc_throw(size_t count, size_t elemSize) { + return sk_malloc_throw(SkSafeMath::Mul(count, elemSize)); +} + +void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize) { + return sk_realloc_throw(buffer, SkSafeMath::Mul(count, elemSize)); +} + // assumes ptr was allocated via sk_malloc static void sk_free_releaseproc(void* ptr, void*) { sk_free(ptr); diff --git a/gfx/skia/skia/src/core/SkMath.cpp b/gfx/skia/skia/src/core/SkMath.cpp index 6eff790c8..84796c522 100644 --- a/gfx/skia/skia/src/core/SkMath.cpp +++ b/gfx/skia/skia/src/core/SkMath.cpp @@ -84,3 +84,18 @@ float SkScalarSinCos(float radians, float* cosValue) { } return sinValue; } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +size_t SkSafeMath::Add(size_t x, size_t y) { + SkSafeMath tmp; + size_t sum = tmp.add(x, y); + return tmp.ok() ? sum : SK_MaxSizeT; +} + +size_t SkSafeMath::Mul(size_t x, size_t y) { + SkSafeMath tmp; + size_t prod = tmp.mul(x, y); + return tmp.ok() ? prod : SK_MaxSizeT; +} + diff --git a/gfx/skia/skia/src/core/SkSafeMath.h b/gfx/skia/skia/src/core/SkSafeMath.h new file mode 100644 index 000000000..0bc0fbfac --- /dev/null +++ b/gfx/skia/skia/src/core/SkSafeMath.h @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSafeMath_DEFINED +#define SkSafeMath_DEFINED + +#include "SkTypes.h" + +// SkSafeMath always check that a series of operations do not overflow. +// This must be correct for all platforms, because this is a check for safety at runtime. + +class SkSafeMath { +public: + SkSafeMath() = default; + + bool ok() const { return fOK; } + explicit operator bool() const { return fOK; } + + size_t mul(size_t x, size_t y) { + return sizeof(size_t) == sizeof(uint64_t) ? mul64(x, y) : mul32(x, y); + } + + size_t add(size_t x, size_t y) { + size_t result = x + y; + fOK &= result >= x; + return result; + } + + /** + * Return a + b, unless this result is an overflow/underflow. In those cases, fOK will + * be set to false, and it is undefined what this returns. + */ + int addInt(int a, int b) { + if (b < 0 && a < std::numeric_limits<int>::min() - b) { + fOK = false; + return a; + } else if (b > 0 && a > std::numeric_limits<int>::max() - b) { + fOK = false; + return a; + } + return a + b; + } + + size_t alignUp(size_t x, size_t alignment) { + SkASSERT(alignment && !(alignment & (alignment - 1))); + return add(x, alignment - 1) & ~(alignment - 1); + } + + template <typename T> T castTo(size_t value) { + if (!SkTFitsIn<T>(value)) { + fOK = false; + } + return static_cast<T>(value); + } + + // These saturate to their results + static size_t Add(size_t x, size_t y); + static size_t Mul(size_t x, size_t y); + static size_t Align4(size_t x) { + SkSafeMath safe; + return safe.alignUp(x, 4); + } + +private: + uint32_t mul32(uint32_t x, uint32_t y) { + uint64_t bx = x; + uint64_t by = y; + uint64_t result = bx * by; + fOK &= result >> 32 == 0; + return result; + } + + uint64_t mul64(uint64_t x, uint64_t y) { + if (x <= std::numeric_limits<uint64_t>::max() >> 32 + && y <= std::numeric_limits<uint64_t>::max() >> 32) { + return x * y; + } else { + auto hi = [](uint64_t x) { return x >> 32; }; + auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; }; + + uint64_t lx_ly = lo(x) * lo(y); + uint64_t hx_ly = hi(x) * lo(y); + uint64_t lx_hy = lo(x) * hi(y); + uint64_t hx_hy = hi(x) * hi(y); + uint64_t result = 0; + result = this->add(lx_ly, (hx_ly << 32)); + result = this->add(result, (lx_hy << 32)); + fOK &= (hx_hy + (hx_ly >> 32) + (lx_hy >> 32)) == 0; + + #if defined(SK_DEBUG) && defined(__clang__) && defined(__x86_64__) + auto double_check = (unsigned __int128)x * y; + SkASSERT(result == (double_check & 0xFFFFFFFFFFFFFFFF)); + SkASSERT(!fOK || (double_check >> 64 == 0)); + #endif + + return result; + } + } + bool fOK = true; +}; + +#endif//SkSafeMath_DEFINED diff --git a/image/Downscaler.cpp b/image/Downscaler.cpp index 18f09c596..2ded487a5 100644 --- a/image/Downscaler.cpp +++ b/image/Downscaler.cpp @@ -231,6 +231,7 @@ Downscaler::CommitRow() int32_t inLineToRead = filterOffset + mLinesInBuffer; MOZ_ASSERT(mCurrentInLine <= inLineToRead, "Reading past end of input"); if (mCurrentInLine == inLineToRead) { + MOZ_RELEASE_ASSERT(mLinesInBuffer < mWindowCapacity, "Need more rows than capacity!"); skia::ConvolveHorizontally(mRowBuffer.get(), *mXFilter, mWindow[mLinesInBuffer++], mHasAlpha, supports_sse2() || supports_mmi()); @@ -239,7 +240,7 @@ Downscaler::CommitRow() MOZ_ASSERT(mCurrentOutLine < mTargetSize.height, "Writing past end of output"); - while (mLinesInBuffer == filterLength) { + while (mLinesInBuffer >= filterLength) { DownscaleInputLine(); if (mCurrentOutLine == mTargetSize.height) { @@ -340,9 +341,14 @@ Downscaler::DownscaleInputLine() // Shift the buffer. We're just moving pointers here, so this is cheap. mLinesInBuffer -= diff; - mLinesInBuffer = max(mLinesInBuffer, 0); - for (int32_t i = 0; i < mLinesInBuffer; ++i) { - swap(mWindow[i], mWindow[filterLength - mLinesInBuffer + i]); + mLinesInBuffer = min(max(mLinesInBuffer, 0), mWindowCapacity); + + // If we already have enough rows to satisfy the filter, there is no need + // to swap as we won't be writing more before the next convolution. + if (filterLength > mLinesInBuffer) { + for (int32_t i = 0; i < mLinesInBuffer; ++i) { + swap(mWindow[i], mWindow[filterLength - mLinesInBuffer + i]); + } } } diff --git a/image/DownscalingFilter.h b/image/DownscalingFilter.h index 6b0d3b26b..1485b85c2 100644 --- a/image/DownscalingFilter.h +++ b/image/DownscalingFilter.h @@ -246,6 +246,7 @@ protected: int32_t inputRowToRead = filterOffset + mRowsInWindow; MOZ_ASSERT(mInputRow <= inputRowToRead, "Reading past end of input"); if (mInputRow == inputRowToRead) { + MOZ_RELEASE_ASSERT(mRowsInWindow < mWindowCapacity, "Need more rows than capacity!"); skia::ConvolveHorizontally(mRowBuffer.get(), *mXFilter, mWindow[mRowsInWindow++], mHasAlpha, supports_sse2() || supports_mmi()); @@ -254,7 +255,7 @@ protected: MOZ_ASSERT(mOutputRow < mNext.InputSize().height, "Writing past end of output"); - while (mRowsInWindow == filterLength) { + while (mRowsInWindow >= filterLength) { DownscaleInputRow(); if (mOutputRow == mNext.InputSize().height) { @@ -330,9 +331,14 @@ private: // Shift the buffer. We're just moving pointers here, so this is cheap. mRowsInWindow -= diff; - mRowsInWindow = std::max(mRowsInWindow, 0); - for (int32_t i = 0; i < mRowsInWindow; ++i) { - std::swap(mWindow[i], mWindow[filterLength - mRowsInWindow + i]); + mRowsInWindow = std::min(std::max(mRowsInWindow, 0), mWindowCapacity); + + // If we already have enough rows to satisfy the filter, there is no need + // to swap as we won't be writing more before the next convolution. + if (filterLength > mRowsInWindow) { + for (int32_t i = 0; i < mRowsInWindow; ++i) { + std::swap(mWindow[i], mWindow[filterLength - mRowsInWindow + i]); + } } } diff --git a/image/decoders/icon/nsIconURI.cpp b/image/decoders/icon/nsIconURI.cpp index 2c2788c8f..632a733fe 100644 --- a/image/decoders/icon/nsIconURI.cpp +++ b/image/decoders/icon/nsIconURI.cpp @@ -372,6 +372,32 @@ nsMozIconURI::SetPath(const nsACString& aPath) } NS_IMETHODIMP +nsMozIconURI::GetFilePath(nsACString& aFilePath) +{ + aFilePath.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsMozIconURI::SetFilePath(const nsACString& aFilePath) +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsMozIconURI::GetQuery(nsACString& aQuery) +{ + aQuery.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsMozIconURI::SetQuery(const nsACString& aQuery) +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsMozIconURI::GetRef(nsACString& aRef) { aRef.Truncate(); diff --git a/intl/tzdata/SVN-INFO b/intl/tzdata/SVN-INFO index 9d39d5a36..fba30f87c 100644 --- a/intl/tzdata/SVN-INFO +++ b/intl/tzdata/SVN-INFO @@ -1,10 +1,10 @@ Path: 44 -URL: https://ssl.icu-project.org/repos/icu/data/trunk/tzdata/icunew/2018c/44 -Relative URL: ^/data/trunk/tzdata/icunew/2018c/44 +URL: https://ssl.icu-project.org/repos/icu/data/trunk/tzdata/icunew/2018d/44 +Relative URL: ^/data/trunk/tzdata/icunew/2018d/44 Repository Root: https://ssl.icu-project.org/repos/icu Repository UUID: 251d0590-4201-4cf1-90de-194747b24ca1 Node Kind: directory Last Changed Author: yoshito -Last Changed Rev: 40799 -Last Changed Date: 2018-01-24 03:22:47 +0000 (Mi, 24 Jan 2018) +Last Changed Rev: 41166 +Last Changed Date: 2018-03-28 13:41:38 +0000 diff --git a/intl/tzdata/source/be/metaZones.res b/intl/tzdata/source/be/metaZones.res Binary files differindex f1d6596fc..68d92ec3b 100644 --- a/intl/tzdata/source/be/metaZones.res +++ b/intl/tzdata/source/be/metaZones.res diff --git a/intl/tzdata/source/be/windowsZones.res b/intl/tzdata/source/be/windowsZones.res Binary files differindex 0b23180a7..356411c0f 100644 --- a/intl/tzdata/source/be/windowsZones.res +++ b/intl/tzdata/source/be/windowsZones.res diff --git a/intl/tzdata/source/be/zoneinfo64.res b/intl/tzdata/source/be/zoneinfo64.res Binary files differindex 94f369bf6..2edd8942e 100644 --- a/intl/tzdata/source/be/zoneinfo64.res +++ b/intl/tzdata/source/be/zoneinfo64.res diff --git a/intl/tzdata/source/ee/metaZones.res b/intl/tzdata/source/ee/metaZones.res Binary files differindex 7ff159e44..349853711 100644 --- a/intl/tzdata/source/ee/metaZones.res +++ b/intl/tzdata/source/ee/metaZones.res diff --git a/intl/tzdata/source/ee/windowsZones.res b/intl/tzdata/source/ee/windowsZones.res Binary files differindex 0009b5552..56f1b19ec 100644 --- a/intl/tzdata/source/ee/windowsZones.res +++ b/intl/tzdata/source/ee/windowsZones.res diff --git a/intl/tzdata/source/ee/zoneinfo64.res b/intl/tzdata/source/ee/zoneinfo64.res Binary files differindex a67e937e6..144ff1530 100644 --- a/intl/tzdata/source/ee/zoneinfo64.res +++ b/intl/tzdata/source/ee/zoneinfo64.res diff --git a/intl/tzdata/source/le/metaZones.res b/intl/tzdata/source/le/metaZones.res Binary files differindex c3c4129e5..c7fd90cee 100644 --- a/intl/tzdata/source/le/metaZones.res +++ b/intl/tzdata/source/le/metaZones.res diff --git a/intl/tzdata/source/le/windowsZones.res b/intl/tzdata/source/le/windowsZones.res Binary files differindex 584bd798e..2409ae877 100644 --- a/intl/tzdata/source/le/windowsZones.res +++ b/intl/tzdata/source/le/windowsZones.res diff --git a/intl/tzdata/source/le/zoneinfo64.res b/intl/tzdata/source/le/zoneinfo64.res Binary files differindex c3c7b22b7..60d2ac03a 100644 --- a/intl/tzdata/source/le/zoneinfo64.res +++ b/intl/tzdata/source/le/zoneinfo64.res diff --git a/intl/tzdata/source/metaZones.txt b/intl/tzdata/source/metaZones.txt index 564992a3b..a9c148a3a 100644 --- a/intl/tzdata/source/metaZones.txt +++ b/intl/tzdata/source/metaZones.txt @@ -131,11 +131,11 @@ metaZones:table(nofallback){ 001{"America/Halifax"} AG{"America/Antigua"} AI{"America/Anguilla"} - AN{"America/Curacao"} AW{"America/Aruba"} BB{"America/Barbados"} BM{"Atlantic/Bermuda"} BQ{"America/Kralendijk"} + CW{"America/Curacao"} DM{"America/Dominica"} GD{"America/Grenada"} GL{"America/Thule"} @@ -2559,6 +2559,11 @@ metaZones:table(nofallback){ { "Casey", "2016-10-21 16:00", + "2016-03-10 17:00", + } + { + "Australia_Western", + "2018-03-10 17:00", "9999-12-31 23:59", } } diff --git a/intl/tzdata/source/windowsZones.txt b/intl/tzdata/source/windowsZones.txt index d7f143cf8..6428c54e8 100644 --- a/intl/tzdata/source/windowsZones.txt +++ b/intl/tzdata/source/windowsZones.txt @@ -156,7 +156,6 @@ windowsZones:table(nofallback){ } "Central Pacific Standard Time"{ 001{"Pacific/Guadalcanal"} - AQ{"Antarctica/Casey"} AU{"Antarctica/Macquarie"} FM{"Pacific/Ponape Pacific/Kosrae"} NC{"Pacific/Noumea"} @@ -212,7 +211,6 @@ windowsZones:table(nofallback){ KE{"Africa/Nairobi"} KM{"Indian/Comoro"} MG{"Indian/Antananarivo"} - SD{"Africa/Khartoum"} SO{"Africa/Mogadishu"} SS{"Africa/Juba"} TZ{"Africa/Dar_es_Salaam"} @@ -614,6 +612,10 @@ windowsZones:table(nofallback){ 001{"Asia/Colombo"} LK{"Asia/Colombo"} } + "Sudan Standard Time"{ + 001{"Africa/Khartoum"} + SD{"Africa/Khartoum"} + } "Syria Standard Time"{ 001{"Asia/Damascus"} SY{"Asia/Damascus"} @@ -728,6 +730,7 @@ windowsZones:table(nofallback){ } "W. Australia Standard Time"{ 001{"Australia/Perth"} + AQ{"Antarctica/Casey"} AU{"Australia/Perth"} } "W. Central Africa Standard Time"{ diff --git a/intl/tzdata/source/zoneinfo64.txt b/intl/tzdata/source/zoneinfo64.txt index 8eed0199d..30fab0972 100644 --- a/intl/tzdata/source/zoneinfo64.txt +++ b/intl/tzdata/source/zoneinfo64.txt @@ -3,17 +3,17 @@ // License & terms of use: http://www.unicode.org/copyright.html#License //--------------------------------------------------------- // Build tool: tz2icu -// Build date: Tue Jan 23 20:51:55 2018 +// Build date: Wed Mar 28 09:18:39 2018 // tz database: ftp://ftp.iana.org/tz/ -// tz version: 2018c -// ICU version: 60.1 +// tz version: 2018d +// ICU version: 61.1 //--------------------------------------------------------- // >> !!! >> THIS IS A MACHINE-GENERATED FILE << !!! << // >> !!! >>> DO NOT EDIT <<< !!! << //--------------------------------------------------------- zoneinfo64:table(nofallback) { - TZVersion { "2018c" } + TZVersion { "2018d" } Zones:array { /* ACT */ :int { 354 } //Z#0 /* AET */ :int { 366 } //Z#1 @@ -44,7 +44,7 @@ zoneinfo64:table(nofallback) { /* Africa/Bangui */ :int { 36 } //Z#12 /* Africa/Banjul */ :int { 5 } //Z#13 /* Africa/Bissau */ :table { - trans:intvector { -1830380260, 157770000 } + trans:intvector { -1830380400, 157770000 } typeOffsets:intvector { -3740, 0, -3600, 0, 0, 0 } typeMap:bin { "0102" } } //Z#14 @@ -156,7 +156,7 @@ zoneinfo64:table(nofallback) { /* Africa/Porto-Novo */ :int { 36 } //Z#53 /* Africa/Sao_Tome */ :table { transPre32:intvector { -1, 1581055280 } - trans:intvector { -1830381795, 1514768400 } + trans:intvector { -1830384000, 1514768400 } typeOffsets:intvector { 1616, 0, -2205, 0, 0, 0, 3600, 0 } typeMap:bin { "010203" } } //Z#54 @@ -534,8 +534,8 @@ zoneinfo64:table(nofallback) { } //Z#121 /* America/Grand_Turk */ :table { transPre32:intvector { -1, 1770462768 } - trans:intvector { -1827687169, 294217200, 309938400, 325666800, 341388000, 357116400, 372837600, 388566000, 404892000, 420015600, 436341600, 452070000, 467791200, 483519600, 499240800, 514969200, 530690400, 544604400, 562140000, 576054000, 594194400, 607503600, 625644000, 638953200, 657093600, 671007600, 688543200, 702457200, 719992800, 733906800, 752047200, 765356400, 783496800, 796806000, 814946400, 828860400, 846396000, 860310000, 877845600, 891759600, 909295200, 923209200, 941349600, 954658800, 972799200, 986108400, 1004248800, 1018162800, 1035698400, 1049612400, 1067148000, 1081062000, 1099202400, 1112511600, 1130652000, 1143961200, 1162101600, 1173596400, 1194156000, 1205046000, 1225605600, 1236495600, 1257055200, 1268550000, 1289109600, 1299999600, 1320559200, 1331449200, 1352008800, 1362898800, 1383458400, 1394348400, 1414908000, 1425798000, 1446357600, 1520751600, 1541311200 } - typeOffsets:intvector { -17072, 0, -18431, 0, -18000, 0, -18000, 3600, -14400, 0 } + trans:intvector { -1827687170, 294217200, 309938400, 325666800, 341388000, 357116400, 372837600, 388566000, 404892000, 420015600, 436341600, 452070000, 467791200, 483519600, 499240800, 514969200, 530690400, 544604400, 562140000, 576054000, 594194400, 607503600, 625644000, 638953200, 657093600, 671007600, 688543200, 702457200, 719992800, 733906800, 752047200, 765356400, 783496800, 796806000, 814946400, 828860400, 846396000, 860310000, 877845600, 891759600, 909295200, 923209200, 941349600, 954658800, 972799200, 986108400, 1004248800, 1018162800, 1035698400, 1049612400, 1067148000, 1081062000, 1099202400, 1112511600, 1130652000, 1143961200, 1162101600, 1173596400, 1194156000, 1205046000, 1225605600, 1236495600, 1257055200, 1268550000, 1289109600, 1299999600, 1320559200, 1331449200, 1352008800, 1362898800, 1383458400, 1394348400, 1414908000, 1425798000, 1446357600, 1520751600, 1541311200 } + typeOffsets:intvector { -17072, 0, -18430, 0, -18000, 0, -18000, 3600, -14400, 0 } typeMap:bin { "010203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203040302" } finalRule { "US" } finalRaw:int { -18000 } @@ -675,8 +675,8 @@ zoneinfo64:table(nofallback) { finalYear:int { 2008 } } //Z#141 /* America/Jamaica */ :table { - trans:intvector { -1827687169, 126687600, 152085600, 162370800, 183535200, 199263600, 215589600, 230713200, 247039200, 262767600, 278488800, 294217200, 309938400, 325666800, 341388000, 357116400, 372837600, 388566000, 404892000, 420015600, 436341600 } - typeOffsets:intvector { -18431, 0, -18000, 0, -18000, 3600 } + trans:intvector { -1827687170, 126687600, 152085600, 162370800, 183535200, 199263600, 215589600, 230713200, 247039200, 262767600, 278488800, 294217200, 309938400, 325666800, 341388000, 357116400, 372837600, 388566000, 404892000, 420015600, 436341600 } + typeOffsets:intvector { -18430, 0, -18000, 0, -18000, 3600 } typeMap:bin { "010201020102010201020102010201020102010201" } links:intvector { 142, 528 } } //Z#142 @@ -836,9 +836,9 @@ zoneinfo64:table(nofallback) { finalYear:int { 2003 } } //Z#168 /* America/Montevideo */ :table { - trans:intvector { -1567455316, -1459542600, -1443819600, -1428006600, -1412283600, -1396470600, -1380747600, -1141590600, -1128286800, -1110141000, -1096837200, -1078691400, -1065387600, -1046637000, -1033938000, -1015187400, -1002488400, -983737800, -971038800, -952288200, -938984400, -920838600, -907534800, -896819400, -883602000, -853619400, -845848800, -334789200, -319672800, -314226000, -309996000, -149720400, -134604000, -118270800, -100044000, -86821200, -68508000, -50446800, -34119000, -18910800, -2583000, 12625200, 28953000, 72932400, 82692000, 132116400, 156911400, 212983200, 250052400, 260244000, 307594800, 325994400, 566449200, 574308000, 597812400, 605671200, 625633200, 636516000, 656478000, 667965600, 688532400, 699415200, 719377200, 730864800, 1095562800, 1111896000, 1128834000, 1142136000, 1159678800, 1173585600, 1191733200, 1205035200, 1223182800, 1236484800, 1254632400, 1268539200, 1286082000, 1299988800, 1317531600, 1331438400, 1349586000, 1362888000, 1381035600, 1394337600, 1412485200, 1425787200 } - typeOffsets:intvector { -13484, 0, -12600, 0, -12600, 1800, -10800, 0, -10800, 1800, -10800, 3600 } - typeMap:bin { "0102010201020102010201020102010201020102010201020105030503050305030503050304030403040305030405030503050305030503050305030503050305030503050305030503050305030503050305030503" } + trans:intvector { -1567455309, -1459627200, -1443819600, -1428006600, -1412283600, -1396470600, -1380747600, -1141590600, -1128286800, -1110141000, -1096837200, -1078691400, -1065387600, -1047241800, -1033938000, -1015187400, -1002488400, -983737800, -971038800, -954707400, -938984400, -920838600, -907534800, -896819400, -853621200, -845847000, -334789200, -319671000, -314226000, -309996000, -149720400, -134604000, -50446800, -34205400, 9860400, 14176800, 72846000, 80100000, 127278000, 132111000, 147234600, 156913200, 165376800, 219812400, 226461600, 250052400, 257911200, 282711600, 289360800, 294202800, 322020000, 566449200, 573012000, 597812400, 605066400, 625633200, 635911200, 656478000, 667965600, 688532400, 699415200, 719377200, 730864800, 1095562800, 1111896000, 1128834000, 1142136000, 1159678800, 1173585600, 1191733200, 1205035200, 1223182800, 1236484800, 1254632400, 1268539200, 1286082000, 1299988800, 1317531600, 1331438400, 1349586000, 1362888000, 1381035600, 1394337600, 1412485200, 1425787200 } + typeOffsets:intvector { -13491, 0, -14400, 0, -12600, 0, -12600, 1800, -10800, 0, -10800, 1800, -10800, 3600, -10800, 5400 } + typeMap:bin { "01030203020302030203020302030203020302030203020305040504060406040504060406040705040604060406040604060406040604060406040604060406040604060406040604060406040604060406040604" } } //Z#169 /* America/Montreal */ :int { 217 } //Z#170 /* America/Montserrat */ :int { 186 } //Z#171 @@ -1182,9 +1182,9 @@ zoneinfo64:table(nofallback) { finalYear:int { 2008 } } //Z#224 /* Antarctica/Casey */ :table { - trans:intvector { -31536000, 1255802400, 1267714800, 1319738400, 1329843600, 1477065600 } + trans:intvector { -31536000, 1255802400, 1267714800, 1319738400, 1329843600, 1477065600, 1520701200 } typeOffsets:intvector { 0, 0, 28800, 0, 39600, 0 } - typeMap:bin { "010201020102" } + typeMap:bin { "01020102010201" } } //Z#225 /* Antarctica/Davis */ :table { trans:intvector { -409190400, -163062000, -28857600, 1255806000, 1268251200, 1319742000, 1329854400 } @@ -1498,7 +1498,7 @@ zoneinfo64:table(nofallback) { /* Asia/Kuwait */ :int { 308 } //Z#290 /* Asia/Macao */ :int { 292 } //Z#291 /* Asia/Macau */ :table { - trans:intvector { -1830411260, -277360200, -257405400, -245910600, -225955800, -214473600, -194506200, -182406600, -163056600, -150969600, -131619600, -117088200, -101367000, -85638600, -69312600, -53584200, -37863000, -22134600, -6413400, 9315000, 25036200, 40764600, 56485800, 72201600, 87922800, 103651200, 119977200, 135705600, 151439400, 167167800, 182889000, 198617400, 214338600, 230067000, 245788200, 261504000, 277225200, 292953600, 309279600, 325008000, 340729200 } + trans:intvector { -1830412800, -277360200, -257405400, -245910600, -225955800, -214473600, -194506200, -182406600, -163056600, -150969600, -131619600, -117088200, -101367000, -85638600, -69312600, -53584200, -37863000, -22134600, -6413400, 9315000, 25036200, 40764600, 56485800, 72201600, 87922800, 103651200, 119977200, 135705600, 151439400, 167167800, 182889000, 198617400, 214338600, 230067000, 245788200, 261504000, 277225200, 292953600, 309279600, 325008000, 340729200 } typeOffsets:intvector { 27260, 0, 28800, 0, 28800, 3600 } typeMap:bin { "0102010201020102010201020102010201020102010201020102010201020102010201020102010201" } links:intvector { 291, 292 } @@ -1709,7 +1709,7 @@ zoneinfo64:table(nofallback) { } //Z#335 /* Atlantic/Azores */ :table { transPre32:intvector { -1, 1581063056 } - trans:intvector { -1830377128, -1689548400, -1677794400, -1667430000, -1647730800, -1635807600, -1616194800, -1604358000, -1584658800, -1572735600, -1553036400, -1541199600, -1521500400, -1442444400, -1426806000, -1379286000, -1364770800, -1348441200, -1333321200, -1316386800, -1301266800, -1284332400, -1269817200, -1221433200, -1206918000, -1191193200, -1175468400, -1127689200, -1111964400, -1096844400, -1080514800, -1063580400, -1049065200, -1033340400, -1017615600, -1002495600, -986166000, -969231600, -950482800, -942015600, -922662000, -906937200, -891126000, -877302000, -873676800, -864000000, -857948400, -845852400, -842832000, -831340800, -825894000, -814402800, -810777600, -799891200, -794444400, -782953200, -779328000, -768441600, -762994800, -749084400, -733359600, -717624000, -701899200, -686174400, -670449600, -654724800, -639000000, -591825600, -575496000, -559771200, -544046400, -528321600, -512596800, -496872000, -481147200, -465422400, -449697600, -433972800, -417643200, -401918400, -386193600, -370468800, -354744000, -339019200, -323294400, -307569600, -291844800, -276120000, -260395200, -244670400, -228340800, -212616000, -196891200, -181166400, -165441600, -149716800, -133992000, -118267200, 228272400, 243997200, 260326800, 276051600, 291776400, 307504800, 323226000, 338954400, 354679200, 370404000, 386128800, 401853600, 417582000, 433303200, 449028000, 465357600, 481082400, 496807200, 512532000, 528256800, 543981600, 559706400, 575431200, 591156000, 606880800, 622605600, 638330400, 654660000, 670384800, 686109600, 701834400, 717559200, 733280400, 749005200, 764730000, 780454800, 796179600, 811904400, 828234000, 846378000 } + trans:intvector { -1830376800, -1689548400, -1677794400, -1667430000, -1647730800, -1635807600, -1616194800, -1604358000, -1584658800, -1572735600, -1553036400, -1541199600, -1521500400, -1442444400, -1426806000, -1379286000, -1364770800, -1348441200, -1333321200, -1316386800, -1301266800, -1284332400, -1269817200, -1221433200, -1206918000, -1191193200, -1175468400, -1127689200, -1111964400, -1096844400, -1080514800, -1063580400, -1049065200, -1033340400, -1017615600, -1002495600, -986166000, -969231600, -950482800, -942015600, -922662000, -906937200, -891126000, -877302000, -873676800, -864000000, -857948400, -845852400, -842832000, -831340800, -825894000, -814402800, -810777600, -799891200, -794444400, -782953200, -779328000, -768441600, -762994800, -749084400, -733359600, -717624000, -701899200, -686174400, -670449600, -654724800, -639000000, -591825600, -575496000, -559771200, -544046400, -528321600, -512596800, -496872000, -481147200, -465422400, -449697600, -433972800, -417643200, -401918400, -386193600, -370468800, -354744000, -339019200, -323294400, -307569600, -291844800, -276120000, -260395200, -244670400, -228340800, -212616000, -196891200, -181166400, -165441600, -149716800, -133992000, -118267200, 228272400, 243997200, 260326800, 276051600, 291776400, 307504800, 323226000, 338954400, 354679200, 370404000, 386128800, 401853600, 417582000, 433303200, 449028000, 465357600, 481082400, 496807200, 512532000, 528256800, 543981600, 559706400, 575431200, 591156000, 606880800, 622605600, 638330400, 654660000, 670384800, 686109600, 701834400, 717559200, 733280400, 749005200, 764730000, 780454800, 796179600, 811904400, 828234000, 846378000 } typeOffsets:intvector { -6160, 0, -7200, 0, -7200, 3600, -7200, 7200, -6872, 0, -3600, 0, -3600, 3600, 0, 0 } typeMap:bin { "04010201020102010201020102010201020102010201020102010201020102010201020102010201020102010203020102030201020302010203020102010201020102010201020102010201020102010201020102010201020102010201020102010506050605060506050605060506050605060506050605060506050605060506070605060506050605" } finalRule { "EU" } @@ -1733,7 +1733,7 @@ zoneinfo64:table(nofallback) { finalYear:int { 1997 } } //Z#338 /* Atlantic/Cape_Verde */ :table { - trans:intvector { -1988144756, -862610400, -764118000, 186120000 } + trans:intvector { -1830376800, -862610400, -764118000, 186120000 } typeOffsets:intvector { -5644, 0, -7200, 0, -7200, 3600, -3600, 0 } typeMap:bin { "01020103" } } //Z#339 @@ -1749,7 +1749,7 @@ zoneinfo64:table(nofallback) { } //Z#341 /* Atlantic/Jan_Mayen */ :int { 473 } //Z#342 /* Atlantic/Madeira */ :table { - trans:intvector { -1830379944, -1689552000, -1677798000, -1667433600, -1647734400, -1635811200, -1616198400, -1604361600, -1584662400, -1572739200, -1553040000, -1541203200, -1521504000, -1442448000, -1426809600, -1379289600, -1364774400, -1348444800, -1333324800, -1316390400, -1301270400, -1284336000, -1269820800, -1221436800, -1206921600, -1191196800, -1175472000, -1127692800, -1111968000, -1096848000, -1080518400, -1063584000, -1049068800, -1033344000, -1017619200, -1002499200, -986169600, -969235200, -950486400, -942019200, -922665600, -906940800, -891129600, -877305600, -873680400, -864003600, -857952000, -845856000, -842835600, -831344400, -825897600, -814406400, -810781200, -799894800, -794448000, -782956800, -779331600, -768445200, -762998400, -749088000, -733363200, -717627600, -701902800, -686178000, -670453200, -654728400, -639003600, -591829200, -575499600, -559774800, -544050000, -528325200, -512600400, -496875600, -481150800, -465426000, -449701200, -433976400, -417646800, -401922000, -386197200, -370472400, -354747600, -339022800, -323298000, -307573200, -291848400, -276123600, -260398800, -244674000, -228344400, -212619600, -196894800, -181170000, -165445200, -149720400, -133995600, -118270800, 228268800, 243993600, 260323200, 276048000, 291772800, 307501200, 323222400, 338950800, 354675600, 370400400, 386125200, 401850000, 417578400, 433299600, 449024400, 465354000, 481078800, 496803600, 512528400, 528253200, 543978000, 559702800, 575427600, 591152400, 606877200, 622602000, 638326800, 654656400, 670381200, 686106000, 701830800, 717555600, 733280400, 749005200, 764730000, 780454800, 796179600, 811904400, 828234000, 846378000 } + trans:intvector { -1830380400, -1689552000, -1677798000, -1667433600, -1647734400, -1635811200, -1616198400, -1604361600, -1584662400, -1572739200, -1553040000, -1541203200, -1521504000, -1442448000, -1426809600, -1379289600, -1364774400, -1348444800, -1333324800, -1316390400, -1301270400, -1284336000, -1269820800, -1221436800, -1206921600, -1191196800, -1175472000, -1127692800, -1111968000, -1096848000, -1080518400, -1063584000, -1049068800, -1033344000, -1017619200, -1002499200, -986169600, -969235200, -950486400, -942019200, -922665600, -906940800, -891129600, -877305600, -873680400, -864003600, -857952000, -845856000, -842835600, -831344400, -825897600, -814406400, -810781200, -799894800, -794448000, -782956800, -779331600, -768445200, -762998400, -749088000, -733363200, -717627600, -701902800, -686178000, -670453200, -654728400, -639003600, -591829200, -575499600, -559774800, -544050000, -528325200, -512600400, -496875600, -481150800, -465426000, -449701200, -433976400, -417646800, -401922000, -386197200, -370472400, -354747600, -339022800, -323298000, -307573200, -291848400, -276123600, -260398800, -244674000, -228344400, -212619600, -196894800, -181170000, -165445200, -149720400, -133995600, -118270800, 228268800, 243993600, 260323200, 276048000, 291772800, 307501200, 323222400, 338950800, 354675600, 370400400, 386125200, 401850000, 417578400, 433299600, 449024400, 465354000, 481078800, 496803600, 512528400, 528253200, 543978000, 559702800, 575427600, 591152400, 606877200, 622602000, 638326800, 654656400, 670381200, 686106000, 701830800, 717555600, 733280400, 749005200, 764730000, 780454800, 796179600, 811904400, 828234000, 846378000 } typeOffsets:intvector { -4056, 0, -3600, 0, -3600, 3600, -3600, 7200, 0, 0, 0, 3600 } typeMap:bin { "010201020102010201020102010201020102010201020102010201020102010201020102010201020102010203020102030201020302010203020102010201020102010201020102010201020102010201020102010201020102010201020102010405040504050405040504050405040504050405040504050405040504050405040504050405040504" } finalRule { "EU" } @@ -2201,7 +2201,7 @@ zoneinfo64:table(nofallback) { typeMap:bin { "010304030403040304030403040304030403020102010302010201020102010201020102010201020102010201020102010201020102010201020102010301" } } //Z#461 /* Europe/Lisbon */ :table { - trans:intvector { -1830381795, -1689555600, -1677801600, -1667437200, -1647738000, -1635814800, -1616202000, -1604365200, -1584666000, -1572742800, -1553043600, -1541206800, -1521507600, -1442451600, -1426813200, -1379293200, -1364778000, -1348448400, -1333328400, -1316394000, -1301274000, -1284339600, -1269824400, -1221440400, -1206925200, -1191200400, -1175475600, -1127696400, -1111971600, -1096851600, -1080522000, -1063587600, -1049072400, -1033347600, -1017622800, -1002502800, -986173200, -969238800, -950490000, -942022800, -922669200, -906944400, -891133200, -877309200, -873684000, -864007200, -857955600, -845859600, -842839200, -831348000, -825901200, -814410000, -810784800, -799898400, -794451600, -782960400, -779335200, -768448800, -763002000, -749091600, -733366800, -717631200, -701906400, -686181600, -670456800, -654732000, -639007200, -591832800, -575503200, -559778400, -544053600, -528328800, -512604000, -496879200, -481154400, -465429600, -449704800, -433980000, -417650400, -401925600, -386200800, -370476000, -354751200, -339026400, -323301600, -307576800, -291852000, -276127200, -260402400, -244677600, -228348000, -212623200, -196898400, -181173600, -165448800, -149724000, -133999200, -118274400, 212544000, 228268800, 243993600, 260323200, 276048000, 291772800, 307501200, 323222400, 338950800, 354675600, 370400400, 386125200, 401850000, 417578400, 433299600, 449024400, 465354000, 481078800, 496803600, 512528400, 528253200, 543978000, 559702800, 575427600, 591152400, 606877200, 622602000, 638326800, 654656400, 670381200, 686106000, 701830800, 717555600, 733280400, 749005200, 764730000, 780454800, 796179600, 811904400, 828234000, 846378000 } + trans:intvector { -1830384000, -1689555600, -1677801600, -1667437200, -1647738000, -1635814800, -1616202000, -1604365200, -1584666000, -1572742800, -1553043600, -1541206800, -1521507600, -1442451600, -1426813200, -1379293200, -1364778000, -1348448400, -1333328400, -1316394000, -1301274000, -1284339600, -1269824400, -1221440400, -1206925200, -1191200400, -1175475600, -1127696400, -1111971600, -1096851600, -1080522000, -1063587600, -1049072400, -1033347600, -1017622800, -1002502800, -986173200, -969238800, -950490000, -942022800, -922669200, -906944400, -891133200, -877309200, -873684000, -864007200, -857955600, -845859600, -842839200, -831348000, -825901200, -814410000, -810784800, -799898400, -794451600, -782960400, -779335200, -768448800, -763002000, -749091600, -733366800, -717631200, -701906400, -686181600, -670456800, -654732000, -639007200, -591832800, -575503200, -559778400, -544053600, -528328800, -512604000, -496879200, -481154400, -465429600, -449704800, -433980000, -417650400, -401925600, -386200800, -370476000, -354751200, -339026400, -323301600, -307576800, -291852000, -276127200, -260402400, -244677600, -228348000, -212623200, -196898400, -181173600, -165448800, -149724000, -133999200, -118274400, 212544000, 228268800, 243993600, 260323200, 276048000, 291772800, 307501200, 323222400, 338950800, 354675600, 370400400, 386125200, 401850000, 417578400, 433299600, 449024400, 465354000, 481078800, 496803600, 512528400, 528253200, 543978000, 559702800, 575427600, 591152400, 606877200, 622602000, 638326800, 654656400, 670381200, 686106000, 701830800, 717555600, 733280400, 749005200, 764730000, 780454800, 796179600, 811904400, 828234000, 846378000 } typeOffsets:intvector { -2205, 0, 0, 0, 0, 3600, 0, 7200, 3600, 0, 3600, 3600 } typeMap:bin { "01020102010201020102010201020102010201020102010201020102010201020102010201020102010201020302010203020102030201020302010201020102010201020102010201020102010201020102010201020102010201020102010201040102010201020102010201020102010201020102010201020102010201020102040504050405040201" } finalRule { "EU" } @@ -2605,7 +2605,7 @@ zoneinfo64:table(nofallback) { } //Z#556 /* Pacific/Enderbury */ :table { transPre32:intvector { -1, 2117555556 } - trans:intvector { 307627200, 788958000 } + trans:intvector { 307627200, 788871600 } typeOffsets:intvector { -41060, 0, -43200, 0, -39600, 0, 46800, 0 } typeMap:bin { "010203" } } //Z#557 @@ -2660,7 +2660,7 @@ zoneinfo64:table(nofallback) { /* Pacific/Johnston */ :int { 565 } //Z#566 /* Pacific/Kiritimati */ :table { transPre32:intvector { -1, 2117552256 } - trans:intvector { 307622400, 788954400 } + trans:intvector { 307622400, 788868000 } typeOffsets:intvector { -37760, 0, -38400, 0, -36000, 0, 50400, 0 } typeMap:bin { "010203" } } //Z#567 @@ -3142,7 +3142,7 @@ zoneinfo64:table(nofallback) { 8, -30, -1, 7200, 1, 3, 1, -1, 7200, 1, 3600 } //_#21 Palestine:intvector { - 2, -31, -7, 3600, 0, 9, -31, -7, 3600, 0, 3600 + 2, 22, -7, 3600, 0, 9, -31, -7, 3600, 0, 3600 } //_#22 Para:intvector { 9, 1, -1, 0, 0, 2, 22, -1, 0, 0, 3600 diff --git a/intl/uconv/nsScriptableUConv.cpp b/intl/uconv/nsScriptableUConv.cpp index 7d4e932e2..43889ffa2 100644 --- a/intl/uconv/nsScriptableUConv.cpp +++ b/intl/uconv/nsScriptableUConv.cpp @@ -11,6 +11,7 @@ #include "nsIUnicodeDecoder.h" #include "nsIUnicodeEncoder.h" #include "mozilla/dom/EncodingUtils.h" +#include "mozilla/CheckedInt.h" using mozilla::dom::EncodingUtils; @@ -39,7 +40,12 @@ nsScriptableUnicodeConverter::ConvertFromUnicodeWithLength(const nsAString& aSrc const nsAFlatString& flatSrc = PromiseFlatString(aSrc); rv = mEncoder->GetMaxLength(flatSrc.get(), inLength, aOutLen); if (NS_SUCCEEDED(rv)) { - *_retval = (char*)malloc(*aOutLen+1); + mozilla::CheckedInt<int32_t> needed(*aOutLen); + needed += 1; + if (!needed.isValid()) { + return NS_ERROR_OUT_OF_MEMORY; + } + *_retval = (char*)malloc(needed.value()); if (!*_retval) return NS_ERROR_OUT_OF_MEMORY; @@ -145,7 +151,13 @@ nsScriptableUnicodeConverter::ConvertFromByteArray(const uint8_t* aData, inLength, &outLength); if (NS_SUCCEEDED(rv)) { - char16_t* buf = (char16_t*)malloc((outLength+1) * sizeof(char16_t)); + mozilla::CheckedInt<nsACString::size_type> needed(outLength); + needed += 1; + needed *= sizeof(char16_t); + if (!needed.isValid()) { + return NS_ERROR_OUT_OF_MEMORY; + } + char16_t* buf = (char16_t*)malloc(needed.value()); if (!buf) return NS_ERROR_OUT_OF_MEMORY; diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index b335f5c23..e115fa74c 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -280,6 +280,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo, aLoadInfo->GetUpgradeInsecureRequests(), aLoadInfo->GetVerifySignedContent(), aLoadInfo->GetEnforceSRI(), + aLoadInfo->GetForceAllowDataURI(), aLoadInfo->GetForceInheritPrincipalDropped(), aLoadInfo->GetInnerWindowID(), aLoadInfo->GetOuterWindowID(), @@ -294,6 +295,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo, aLoadInfo->CorsUnsafeHeaders(), aLoadInfo->GetForcePreflight(), aLoadInfo->GetIsPreflight(), + aLoadInfo->GetLoadTriggeredFromExternal(), aLoadInfo->GetForceHSTSPriming(), aLoadInfo->GetMixedContentWouldBlock()); @@ -356,6 +358,7 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs, loadInfoArgs.upgradeInsecureRequests(), loadInfoArgs.verifySignedContent(), loadInfoArgs.enforceSRI(), + loadInfoArgs.forceAllowDataURI(), loadInfoArgs.forceInheritPrincipalDropped(), loadInfoArgs.innerWindowID(), loadInfoArgs.outerWindowID(), @@ -370,6 +373,7 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs, loadInfoArgs.corsUnsafeHeaders(), loadInfoArgs.forcePreflight(), loadInfoArgs.isPreflight(), + loadInfoArgs.loadTriggeredFromExternal(), loadInfoArgs.forceHSTSPriming(), loadInfoArgs.mixedContentWouldBlock() ); diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 3be6a6781..b007954b1 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -147,13 +147,6 @@ ifeq ($(OS_ARCH),AIX) CFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 CXXFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 endif -ifeq ($(OS_ARCH),HP-UX) -# Suppress warnings from aCC -# 3055: anonymous unions declaring types -# 4189: offsetof() on non-POD types -CFLAGS += +W3055,4189 -CXXFLAGS += +W3055,4189 -endif endif ifeq ($(OS_ARCH),SunOS) ifeq ($(TARGET_CPU),sparc) diff --git a/js/src/builtin/Intl.js b/js/src/builtin/Intl.js index 37c87365b..509168d7a 100644 --- a/js/src/builtin/Intl.js +++ b/js/src/builtin/Intl.js @@ -9,8 +9,7 @@ JSMSG_INVALID_OPTION_VALUE: false, JSMSG_INVALID_DIGITS_VALUE: false, JSMSG_INTL_OBJECT_REINITED: false, JSMSG_INVALID_CURRENCY_CODE: false, JSMSG_UNDEFINED_CURRENCY: false, JSMSG_INVALID_TIME_ZONE: false, - JSMSG_DATE_NOT_FINITE: false, JSMSG_INVALID_KEYS_TYPE: false, - JSMSG_INVALID_KEY: false, + JSMSG_DATE_NOT_FINITE: false, intl_Collator_availableLocales: false, intl_availableCollations: false, intl_CompareStrings: false, @@ -21,9 +20,6 @@ intl_availableCalendars: false, intl_patternForSkeleton: false, intl_FormatDateTime: false, - intl_SelectPluralRule: false, - intl_GetPluralCategories: false, - intl_GetCalendarInfo: false, */ /* @@ -860,7 +856,6 @@ function BestAvailableLocaleIgnoringDefault(availableLocales, locale) { return BestAvailableLocaleHelper(availableLocales, locale, false); } -var noRelevantExtensionKeys = []; /** * Compares a BCP 47 language priority list against the set of locales in @@ -1188,10 +1183,9 @@ function GetOption(options, property, type, values, fallback) { * Spec: ECMAScript Internationalization API Specification, 9.2.10. */ function GetNumberOption(options, property, minimum, maximum, fallback) { - assert(typeof minimum === "number" && (minimum | 0) === minimum, "GetNumberOption"); - assert(typeof maximum === "number" && (maximum | 0) === maximum, "GetNumberOption"); - assert(typeof fallback === "number" && (fallback | 0) === fallback, "GetNumberOption"); - assert(minimum <= fallback && fallback <= maximum, "GetNumberOption"); + assert(typeof minimum === "number", "GetNumberOption"); + assert(typeof maximum === "number", "GetNumberOption"); + assert(fallback === undefined || (fallback >= minimum && fallback <= maximum), "GetNumberOption"); // Step 1. var value = options[property]; @@ -1201,10 +1195,7 @@ function GetNumberOption(options, property, minimum, maximum, fallback) { value = ToNumber(value); if (Number_isNaN(value) || value < minimum || value > maximum) ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value); - - // Apply bitwise-or to convert -0 to +0 per ES2017, 5.2 and to ensure - // the result is an int32 value. - return std_Math_floor(value) | 0; + return std_Math_floor(value); } // Step 3. @@ -1278,9 +1269,7 @@ function initializeIntlObject(obj) { function setLazyData(internals, type, lazyData) { assert(internals.type === "partial", "can't set lazy data for anything but a newborn"); - assert(type === "Collator" || type === "DateTimeFormat" || - type == "NumberFormat" || type === "PluralRules", - "bad type"); + assert(type === "Collator" || type === "DateTimeFormat" || type == "NumberFormat", "bad type"); assert(IsObject(lazyData), "non-object lazy data"); // Set in reverse order so that the .type change is a barrier. @@ -1330,9 +1319,7 @@ function isInitializedIntlObject(obj) { if (IsObject(internals)) { assert(callFunction(std_Object_hasOwnProperty, internals, "type"), "missing type"); var type = internals.type; - assert(type === "partial" || type === "Collator" || - type === "DateTimeFormat" || type === "NumberFormat" || type === "PluralRules", - "unexpected type"); + assert(type === "partial" || type === "Collator" || type === "DateTimeFormat" || type === "NumberFormat", "unexpected type"); assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData"); assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps"); } else { @@ -1389,8 +1376,6 @@ function getInternals(obj) internalProps = resolveCollatorInternals(lazyData) else if (type === "DateTimeFormat") internalProps = resolveDateTimeFormatInternals(lazyData) - else if (type === "PluralRules") - internalProps = resolvePluralRulesInternals(lazyData) else internalProps = resolveNumberFormatInternals(lazyData); setInternalProperties(internals, internalProps); @@ -1722,7 +1707,6 @@ function Intl_Collator_compare_get() { // Step 2. return internals.boundCompare; } -_SetCanonicalName(Intl_Collator_compare_get, "get compare"); /** @@ -1791,37 +1775,45 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { // Step 6. var opt = lazyNumberFormatData.opt; + // Compute effective locale. + // Step 9. var NumberFormat = numberFormatInternalProperties; - // Step 9. + // Step 10. var localeData = NumberFormat.localeData; - // Step 10. + // Step 11. var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat), lazyNumberFormatData.requestedLocales, lazyNumberFormatData.opt, NumberFormat.relevantExtensionKeys, localeData); - // Steps 11-12. (Step 13 is not relevant to our implementation.) + // Steps 12-13. (Step 14 is not relevant to our implementation.) internalProps.locale = r.locale; internalProps.numberingSystem = r.nu; // Compute formatting options. - // Step 15. - var style = lazyNumberFormatData.style; - internalProps.style = style; + // Step 16. + var s = lazyNumberFormatData.style; + internalProps.style = s; - // Steps 19, 21. - if (style === "currency") { + // Steps 20, 22. + if (s === "currency") { internalProps.currency = lazyNumberFormatData.currency; internalProps.currencyDisplay = lazyNumberFormatData.currencyDisplay; } + // Step 24. internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits; + + // Steps 27. internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits; + + // Step 30. internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits; + // Step 33. if ("minimumSignificantDigits" in lazyNumberFormatData) { // Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the // actual presence (versus undefined-ness) of these properties. @@ -1830,10 +1822,10 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits; } - // Step 27. + // Step 35. internalProps.useGrouping = lazyNumberFormatData.useGrouping; - // Step 34. + // Step 42. internalProps.boundFormat = undefined; // The caller is responsible for associating |internalProps| with the right @@ -1861,44 +1853,6 @@ function getNumberFormatInternals(obj, methodName) { return internalProps; } -/** - * Applies digit options used for number formatting onto the intl object. - * - * Spec: ECMAScript Internationalization API Specification, 11.1.1. - */ -function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault, mxfdDefault) { - // We skip Step 1 because we set the properties on a lazyData object. - - // Step 2-3. - assert(IsObject(options), "SetNumberFormatDigitOptions"); - assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions"); - assert(typeof mxfdDefault === "number", "SetNumberFormatDigitOptions"); - assert(mnfdDefault <= mxfdDefault, "SetNumberFormatDigitOptions"); - - // Steps 4-6. - const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); - const mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault); - const mxfdActualDefault = std_Math_max(mnfd, mxfdDefault); - const mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdActualDefault); - - // Steps 7-8. - let mnsd = options.minimumSignificantDigits; - let mxsd = options.maximumSignificantDigits; - - // Steps 9-11. - lazyData.minimumIntegerDigits = mnid; - lazyData.minimumFractionDigits = mnfd; - lazyData.maximumFractionDigits = mxfd; - - // Step 12. - if (mnsd !== undefined || mxsd !== undefined) { - mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); - mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21); - lazyData.minimumSignificantDigits = mnsd; - lazyData.maximumSignificantDigits = mxsd; - } -} - /** * Initializes an object as a NumberFormat. @@ -1948,7 +1902,7 @@ function InitializeNumberFormat(numberFormat, locales, options) { // } // // Note that lazy data is only installed as a final step of initialization, - // so every NumberFormat lazy data object has *all* these properties, never a + // so every Collator lazy data object has *all* these properties, never a // subset of them. var lazyNumberFormatData = std_Object_create(null); @@ -1978,46 +1932,67 @@ function InitializeNumberFormat(numberFormat, locales, options) { opt.localeMatcher = matcher; // Compute formatting options. - // Step 14. - var style = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal"); - lazyNumberFormatData.style = style; + // Step 15. + var s = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal"); + lazyNumberFormatData.style = s; - // Steps 16-19. + // Steps 17-20. var c = GetOption(options, "currency", "string", undefined, undefined); if (c !== undefined && !IsWellFormedCurrencyCode(c)) ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c); var cDigits; - if (style === "currency") { + if (s === "currency") { if (c === undefined) ThrowTypeError(JSMSG_UNDEFINED_CURRENCY); - // Steps 19.a-c. + // Steps 20.a-c. c = toASCIIUpperCase(c); lazyNumberFormatData.currency = c; cDigits = CurrencyDigits(c); } - // Step 20. + // Step 21. var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol"); - if (style === "currency") + if (s === "currency") lazyNumberFormatData.currencyDisplay = cd; - // Steps 22-25. - var mnfdDefault, mxfdDefault; - if (style === "currency") { - mnfdDefault = cDigits; - mxfdDefault = cDigits; - } else { - mnfdDefault = 0; - mxfdDefault = style === "percent" ? 0 : 3; + // Step 23. + var mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); + lazyNumberFormatData.minimumIntegerDigits = mnid; + + // Steps 25-26. + var mnfdDefault = (s === "currency") ? cDigits : 0; + var mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault); + lazyNumberFormatData.minimumFractionDigits = mnfd; + + // Steps 28-29. + var mxfdDefault; + if (s === "currency") + mxfdDefault = std_Math_max(mnfd, cDigits); + else if (s === "percent") + mxfdDefault = std_Math_max(mnfd, 0); + else + mxfdDefault = std_Math_max(mnfd, 3); + var mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdDefault); + lazyNumberFormatData.maximumFractionDigits = mxfd; + + // Steps 31-32. + var mnsd = options.minimumSignificantDigits; + var mxsd = options.maximumSignificantDigits; + + // Step 33. + if (mnsd !== undefined || mxsd !== undefined) { + mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); + mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21); + lazyNumberFormatData.minimumSignificantDigits = mnsd; + lazyNumberFormatData.maximumSignificantDigits = mxsd; } - SetNumberFormatDigitOptions(lazyNumberFormatData, options, mnfdDefault, mxfdDefault); - // Steps 26. + // Step 34. var g = GetOption(options, "useGrouping", "boolean", undefined, true); lazyNumberFormatData.useGrouping = g; - // Steps 35-36. + // Step 43. // // We've done everything that must be done now: mark the lazy data as fully // computed and install it. @@ -2026,6 +2001,43 @@ function InitializeNumberFormat(numberFormat, locales, options) { /** + * Mapping from currency codes to the number of decimal digits used for them. + * Default is 2 digits. + * + * Spec: ISO 4217 Currency and Funds Code List. + * http://www.currency-iso.org/en/home/tables/table-a1.html + */ +var currencyDigits = { + BHD: 3, + BIF: 0, + BYR: 0, + CLF: 4, + CLP: 0, + DJF: 0, + GNF: 0, + IQD: 3, + ISK: 0, + JOD: 3, + JPY: 0, + KMF: 0, + KRW: 0, + KWD: 3, + LYD: 3, + OMR: 3, + PYG: 0, + RWF: 0, + TND: 3, + UGX: 0, + UYI: 0, + VND: 0, + VUV: 0, + XAF: 0, + XOF: 0, + XPF: 0 +}; + + +/** * Returns the number of decimal digits to be used for the given currency. * * Spec: ECMAScript Internationalization API Specification, 11.1.1. @@ -2106,7 +2118,7 @@ function numberFormatFormatToBind(value) { // Step 1.a.ii-iii. var x = ToNumber(value); - return intl_FormatNumber(this, x, /* formatToParts = */ false); + return intl_FormatNumber(this, x); } @@ -2133,22 +2145,6 @@ function Intl_NumberFormat_format_get() { // Step 2. return internals.boundFormat; } -_SetCanonicalName(Intl_NumberFormat_format_get, "get format"); - - -function Intl_NumberFormat_formatToParts(value) { - // Step 1. - var nf = this; - - // Steps 2-3. - getNumberFormatInternals(nf, "formatToParts"); - - // Step 4. - var x = ToNumber(value); - - // Step 5. - return intl_FormatNumber(nf, x, /* formatToParts = */ true); -} /** @@ -2290,6 +2286,26 @@ function getDateTimeFormatInternals(obj, methodName) { return internalProps; } +/** + * Components of date and time formats and their values. + * + * Spec: ECMAScript Internationalization API Specification, 12.1.1. + */ +var dateTimeComponentValues = { + weekday: ["narrow", "short", "long"], + era: ["narrow", "short", "long"], + year: ["2-digit", "numeric"], + month: ["2-digit", "numeric", "narrow", "short", "long"], + day: ["2-digit", "numeric"], + hour: ["2-digit", "numeric"], + minute: ["2-digit", "numeric"], + second: ["2-digit", "numeric"], + timeZoneName: ["short", "long"] +}; + + +var dateTimeComponents = std_Object_getOwnPropertyNames(dateTimeComponentValues); + /** * Initializes an object as a DateTimeFormat. @@ -2379,19 +2395,12 @@ function InitializeDateTimeFormat(dateTimeFormat, locales, options) { lazyDateTimeFormatData.formatOpt = formatOpt; // Step 19. - // 12.1, Table 4: Components of date and time formats. - formatOpt.weekday = GetOption(options, "weekday", "string", ["narrow", "short", "long"], - undefined); - formatOpt.era = GetOption(options, "era", "string", ["narrow", "short", "long"], undefined); - formatOpt.year = GetOption(options, "year", "string", ["2-digit", "numeric"], undefined); - formatOpt.month = GetOption(options, "month", "string", - ["2-digit", "numeric", "narrow", "short", "long"], undefined); - formatOpt.day = GetOption(options, "day", "string", ["2-digit", "numeric"], undefined); - formatOpt.hour = GetOption(options, "hour", "string", ["2-digit", "numeric"], undefined); - formatOpt.minute = GetOption(options, "minute", "string", ["2-digit", "numeric"], undefined); - formatOpt.second = GetOption(options, "second", "string", ["2-digit", "numeric"], undefined); - formatOpt.timeZoneName = GetOption(options, "timeZoneName", "string", ["short", "long"], - undefined); + var i, prop; + for (i = 0; i < dateTimeComponents.length; i++) { + prop = dateTimeComponents[i]; + var value = GetOption(options, prop, "string", dateTimeComponentValues[prop], undefined); + formatOpt[prop] = value; + } // Steps 20-21 provided by ICU - see comment after this function. @@ -2659,6 +2668,7 @@ function ToDateTimeOptions(options, required, defaults) { return options; } + /** * Compares the date and time components requested by options with the available * date and time formats in formats, and selects the best match according @@ -2844,7 +2854,6 @@ function Intl_DateTimeFormat_format_get() { // Step 2. return internals.boundFormat; } -_SetCanonicalName(Intl_DateTimeFormat_format_get, "get format"); function Intl_DateTimeFormat_formatToParts() { @@ -2980,232 +2989,6 @@ function resolveICUPattern(pattern, result) { } } -/********** Intl.PluralRules **********/ - -/** - * PluralRules internal properties. - * - * Spec: ECMAScript 402 API, PluralRules, 1.3.3. - */ -var pluralRulesInternalProperties = { - _availableLocales: null, - availableLocales: function() - { - var locales = this._availableLocales; - if (locales) - return locales; - - locales = intl_PluralRules_availableLocales(); - addSpecialMissingLanguageTags(locales); - return (this._availableLocales = locales); - } -}; - -/** - * Compute an internal properties object from |lazyPluralRulesData|. - */ -function resolvePluralRulesInternals(lazyPluralRulesData) { - assert(IsObject(lazyPluralRulesData), "lazy data not an object?"); - - var internalProps = std_Object_create(null); - - var requestedLocales = lazyPluralRulesData.requestedLocales; - - var PluralRules = pluralRulesInternalProperties; - - // Step 13. - const r = ResolveLocale(callFunction(PluralRules.availableLocales, PluralRules), - lazyPluralRulesData.requestedLocales, - lazyPluralRulesData.opt, - noRelevantExtensionKeys, undefined); - - // Step 14. - internalProps.locale = r.locale; - internalProps.type = lazyPluralRulesData.type; - - internalProps.pluralCategories = intl_GetPluralCategories( - internalProps.locale, - internalProps.type); - - internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits; - internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits; - internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits; - - if ("minimumSignificantDigits" in lazyPluralRulesData) { - assert("maximumSignificantDigits" in lazyPluralRulesData, "min/max sig digits mismatch"); - internalProps.minimumSignificantDigits = lazyPluralRulesData.minimumSignificantDigits; - internalProps.maximumSignificantDigits = lazyPluralRulesData.maximumSignificantDigits; - } - - return internalProps; -} - -/** - * Returns an object containing the PluralRules internal properties of |obj|, - * or throws a TypeError if |obj| isn't PluralRules-initialized. - */ -function getPluralRulesInternals(obj, methodName) { - var internals = getIntlObjectInternals(obj, "PluralRules", methodName); - assert(internals.type === "PluralRules", "bad type escaped getIntlObjectInternals"); - - var internalProps = maybeInternalProperties(internals); - if (internalProps) - return internalProps; - - internalProps = resolvePluralRulesInternals(internals.lazyData); - setInternalProperties(internals, internalProps); - return internalProps; -} - -/** - * Initializes an object as a PluralRules. - * - * This method is complicated a moderate bit by its implementing initialization - * as a *lazy* concept. Everything that must happen now, does -- but we defer - * all the work we can until the object is actually used as a PluralRules. - * This later work occurs in |resolvePluralRulesInternals|; steps not noted - * here occur there. - * - * Spec: ECMAScript 402 API, PluralRules, 1.1.1. - */ -function InitializePluralRules(pluralRules, locales, options) { - assert(IsObject(pluralRules), "InitializePluralRules"); - - // Step 1. - if (isInitializedIntlObject(pluralRules)) - ThrowTypeError(JSMSG_INTL_OBJECT_REINITED); - - let internals = initializeIntlObject(pluralRules); - - // Lazy PluralRules data has the following structure: - // - // { - // requestedLocales: List of locales, - // type: "cardinal" / "ordinal", - // - // opt: // opt object computer in InitializePluralRules - // { - // localeMatcher: "lookup" / "best fit", - // } - // - // minimumIntegerDigits: integer ∈ [1, 21], - // minimumFractionDigits: integer ∈ [0, 20], - // maximumFractionDigits: integer ∈ [0, 20], - // - // // optional - // minimumSignificantDigits: integer ∈ [1, 21], - // maximumSignificantDigits: integer ∈ [1, 21], - // } - // - // Note that lazy data is only installed as a final step of initialization, - // so every PluralRules lazy data object has *all* these properties, never a - // subset of them. - const lazyPluralRulesData = std_Object_create(null); - - // Step 3. - let requestedLocales = CanonicalizeLocaleList(locales); - lazyPluralRulesData.requestedLocales = requestedLocales; - - // Steps 4-5. - if (options === undefined) - options = {}; - else - options = ToObject(options); - - // Step 6. - const type = GetOption(options, "type", "string", ["cardinal", "ordinal"], "cardinal"); - lazyPluralRulesData.type = type; - - // Step 8. - let opt = new Record(); - lazyPluralRulesData.opt = opt; - - // Steps 9-10. - let matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit"); - opt.localeMatcher = matcher; - - // Steps 11-12. - SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3); - - setLazyData(internals, "PluralRules", lazyPluralRulesData) -} - -/** - * Returns the subset of the given locale list for which this locale list has a - * matching (possibly fallback) locale. Locales appear in the same order in the - * returned list as in the input list. - * - * Spec: ECMAScript 402 API, PluralRules, 1.3.2. - */ -function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) { - var options = arguments.length > 1 ? arguments[1] : undefined; - - // Step 1. - var availableLocales = callFunction(pluralRulesInternalProperties.availableLocales, - pluralRulesInternalProperties); - // Step 2. - let requestedLocales = CanonicalizeLocaleList(locales); - - // Step 3. - return SupportedLocales(availableLocales, requestedLocales, options); -} - -/** - * Returns a String value representing the plural category matching - * the number passed as value according to the - * effective locale and the formatting options of this PluralRules. - * - * Spec: ECMAScript 402 API, PluralRules, 1.4.3. - */ -function Intl_PluralRules_select(value) { - // Step 1. - let pluralRules = this; - // Step 2. - let internals = getPluralRulesInternals(pluralRules, "select"); - - // Steps 3-4. - let n = ToNumber(value); - - // Step 5. - return intl_SelectPluralRule(pluralRules, n); -} - -/** - * Returns the resolved options for a PluralRules object. - * - * Spec: ECMAScript 402 API, PluralRules, 1.4.4. - */ -function Intl_PluralRules_resolvedOptions() { - var internals = getPluralRulesInternals(this, "resolvedOptions"); - - var internalsPluralCategories = internals.pluralCategories; - var pluralCategories = []; - for (var i = 0; i < internalsPluralCategories.length; i++) - _DefineDataProperty(pluralCategories, i, internalsPluralCategories[i]); - - var result = { - locale: internals.locale, - type: internals.type, - pluralCategories, - minimumIntegerDigits: internals.minimumIntegerDigits, - minimumFractionDigits: internals.minimumFractionDigits, - maximumFractionDigits: internals.maximumFractionDigits, - }; - - var optionalProperties = [ - "minimumSignificantDigits", - "maximumSignificantDigits" - ]; - - for (var i = 0; i < optionalProperties.length; i++) { - var p = optionalProperties[i]; - if (callFunction(std_Object_hasOwnProperty, internals, p)) - _DefineDataProperty(result, p, internals[p]); - } - return result; -} - - function Intl_getCanonicalLocales(locales) { let codes = CanonicalizeLocaleList(locales); let result = []; @@ -3241,126 +3024,3 @@ function Intl_getCalendarInfo(locales) { return result; } - -/** - * This function is a custom method designed after Intl API, but currently - * not part of the spec or spec proposal. - * We want to use it internally to retrieve translated values from CLDR in - * order to ensure they're aligned with what Intl API returns. - * - * This API may one day be a foundation for an ECMA402 API spec proposal. - * - * The function takes two arguments - locales which is a list of locale strings - * and options which is an object with two optional properties: - * - * keys: - * an Array of string values that are paths to individual terms - * - * style: - * a String with a value "long", "short" or "narrow" - * - * It returns an object with properties: - * - * locale: - * a negotiated locale string - * - * style: - * negotiated style - * - * values: - * A key-value pair list of requested keys and corresponding - * translated values - * - */ -function Intl_getDisplayNames(locales, options) { - // 1. Let requestLocales be ? CanonicalizeLocaleList(locales). - const requestedLocales = CanonicalizeLocaleList(locales); - - // 2. If options is undefined, then - if (options === undefined) - // a. Let options be ObjectCreate(%ObjectPrototype%). - options = {}; - // 3. Else, - else - // a. Let options be ? ToObject(options). - options = ToObject(options); - - const DateTimeFormat = dateTimeFormatInternalProperties; - - // 4. Let localeData be %DateTimeFormat%.[[localeData]]. - const localeData = DateTimeFormat.localeData; - - // 5. Let opt be a new Record. - const localeOpt = new Record(); - // 6. Set localeOpt.[[localeMatcher]] to "best fit". - localeOpt.localeMatcher = "best fit"; - - // 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt, - // %DateTimeFormat%.[[relevantExtensionKeys]], localeData). - const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat), - requestedLocales, - localeOpt, - DateTimeFormat.relevantExtensionKeys, - localeData); - - // 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long"). - const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long"); - // 9. Let keys be ? Get(options, "keys"). - let keys = options.keys; - - // 10. If keys is undefined, - if (keys === undefined) { - // a. Let keys be ArrayCreate(0). - keys = []; - } else if (!IsObject(keys)) { - // 11. Else, - // a. If Type(keys) is not Object, throw a TypeError exception. - ThrowTypeError(JSMSG_INVALID_KEYS_TYPE); - } - - // 12. Let processedKeys be ArrayCreate(0). - // (This really should be a List, but we use an Array here in order that - // |intl_ComputeDisplayNames| may infallibly access the list's length via - // |ArrayObject::length|.) - let processedKeys = []; - // 13. Let len be ? ToLength(? Get(keys, "length")). - let len = ToLength(keys.length); - // 14. Let i be 0. - // 15. Repeat, while i < len - for (let i = 0; i < len; i++) { - // a. Let processedKey be ? ToString(? Get(keys, i)). - // b. Perform ? CreateDataPropertyOrThrow(processedKeys, i, processedKey). - callFunction(std_Array_push, processedKeys, ToString(keys[i])); - } - - // 16. Let names be ? ComputeDisplayNames(r.[[locale]], style, processedKeys). - const names = intl_ComputeDisplayNames(r.locale, style, processedKeys); - - // 17. Let values be ObjectCreate(%ObjectPrototype%). - const values = {}; - - // 18. Set i to 0. - // 19. Repeat, while i < len - for (let i = 0; i < len; i++) { - // a. Let key be ? Get(processedKeys, i). - const key = processedKeys[i]; - // b. Let name be ? Get(names, i). - const name = names[i]; - // c. Assert: Type(name) is string. - assert(typeof name === "string", "unexpected non-string value"); - // d. Assert: the length of name is greater than zero. - assert(name.length > 0, "empty string value"); - // e. Perform ? DefinePropertyOrThrow(values, key, name). - _DefineDataProperty(values, key, name); - } - - // 20. Let options be ObjectCreate(%ObjectPrototype%). - // 21. Perform ! DefinePropertyOrThrow(result, "locale", r.[[locale]]). - // 22. Perform ! DefinePropertyOrThrow(result, "style", style). - // 23. Perform ! DefinePropertyOrThrow(result, "values", values). - const result = { locale: r.locale, style, values }; - - // 24. Return result. - return result; -} - diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h index f92c583df..3d5c1b0d5 100644 --- a/js/src/builtin/IntlTimeZoneData.h +++ b/js/src/builtin/IntlTimeZoneData.h @@ -1,5 +1,5 @@ // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d #ifndef builtin_IntlTimeZoneData_h #define builtin_IntlTimeZoneData_h diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index f633b9b7b..9dbbe7624 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -2214,6 +2214,12 @@ MacroAssembler::finish() } MacroAssemblerSpecific::finish(); + + MOZ_RELEASE_ASSERT(size() <= MaxCodeBytesPerProcess, + "AssemblerBuffer should ensure we don't exceed MaxCodeBytesPerProcess"); + + if (bytesNeeded() > MaxCodeBytesPerProcess) + setOOM(); } void diff --git a/js/src/jit/ProcessExecutableMemory.cpp b/js/src/jit/ProcessExecutableMemory.cpp index 71c2ab0dc..301541541 100644 --- a/js/src/jit/ProcessExecutableMemory.cpp +++ b/js/src/jit/ProcessExecutableMemory.cpp @@ -385,14 +385,6 @@ class PageBitSet #endif }; -// Limit on the number of bytes of executable memory to prevent JIT spraying -// attacks. -#if JS_BITS_PER_WORD == 32 -static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; -#else -static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; -#endif - // Per-process executable memory allocator. It reserves a block of memory of // MaxCodeBytesPerProcess bytes, then allocates/deallocates pages from that. // diff --git a/js/src/jit/ProcessExecutableMemory.h b/js/src/jit/ProcessExecutableMemory.h index 078ce7cb7..a0e2fab98 100644 --- a/js/src/jit/ProcessExecutableMemory.h +++ b/js/src/jit/ProcessExecutableMemory.h @@ -17,6 +17,14 @@ namespace jit { // alignment though. static const size_t ExecutableCodePageSize = 64 * 1024; +// Limit on the number of bytes of executable memory to prevent JIT spraying +// attacks. +#if JS_BITS_PER_WORD == 32 +static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; +#else +static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; +#endif + enum class ProtectionSetting { Protected, // Not readable, writable, or executable. Writable, diff --git a/js/src/jit/shared/IonAssemblerBuffer.h b/js/src/jit/shared/IonAssemblerBuffer.h index cc20e26d2..3a6552696 100644 --- a/js/src/jit/shared/IonAssemblerBuffer.h +++ b/js/src/jit/shared/IonAssemblerBuffer.h @@ -181,6 +181,10 @@ class AssemblerBuffer protected: virtual Slice* newSlice(LifoAlloc& a) { + if (size() > MaxCodeBytesPerProcess - sizeof(Slice)) { + fail_oom(); + return nullptr; + } Slice* tmp = static_cast<Slice*>(a.alloc(sizeof(Slice))); if (!tmp) { fail_oom(); diff --git a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h index 8cb557784..fe678fc7d 100644 --- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h +++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h @@ -68,6 +68,33 @@ namespace js { namespace jit { + // AllocPolicy for AssemblerBuffer. OOMs when trying to allocate more than + // MaxCodeBytesPerProcess bytes. Use private inheritance to make sure we + // explicitly have to expose SystemAllocPolicy methods. + class AssemblerBufferAllocPolicy : private SystemAllocPolicy + { + public: + using SystemAllocPolicy::checkSimulatedOOM; + using SystemAllocPolicy::reportAllocOverflow; + using SystemAllocPolicy::free_; + + template <typename T> T* pod_realloc(T* p, size_t oldSize, size_t newSize) { + static_assert(sizeof(T) == 1, + "AssemblerBufferAllocPolicy should only be used with byte vectors"); + MOZ_ASSERT(oldSize <= MaxCodeBytesPerProcess); + if (MOZ_UNLIKELY(newSize > MaxCodeBytesPerProcess)) + return nullptr; + return SystemAllocPolicy::pod_realloc<T>(p, oldSize, newSize); + } + template <typename T> T* pod_malloc(size_t numElems) { + static_assert(sizeof(T) == 1, + "AssemblerBufferAllocPolicy should only be used with byte vectors"); + if (MOZ_UNLIKELY(numElems > MaxCodeBytesPerProcess)) + return nullptr; + return SystemAllocPolicy::pod_malloc<T>(numElems); + } + }; + class AssemblerBuffer { template<size_t size, typename T> @@ -93,6 +120,9 @@ namespace jit { void ensureSpace(size_t space) { + // This should only be called with small |space| values to ensure + // we don't overflow below. + MOZ_ASSERT(space <= 16); if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space))) oomDetected(); } @@ -168,7 +198,7 @@ namespace jit { m_buffer.clear(); } - PageProtectingVector<unsigned char, 256, SystemAllocPolicy> m_buffer; + PageProtectingVector<unsigned char, 256, AssemblerBufferAllocPolicy> m_buffer; bool m_oom; }; diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 6593d2067..75774e5b8 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -160,10 +160,6 @@ # if defined(__64BIT__) # define JS_64BIT # endif -#elif defined(__HP_cc) || defined(__HP_aCC) /* HP-UX cc/aCC */ -# if defined(__LP64__) -# define JS_64BIT -# endif #else # error "Implement me" #endif diff --git a/js/src/moz.build b/js/src/moz.build index a18170a75..2d4e83db3 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -708,7 +708,7 @@ if CONFIG['_MSC_VER']: CXXFLAGS += ['-wd4577'] CXXFLAGS += ['-wd4312'] -if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'): +if CONFIG['OS_ARCH'] not in ('WINNT'): OS_LIBS += [ 'm', ] diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js index 890b1c1d5..7b3a46a60 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js index 19fd871eb..ed63df921 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js index 34425acec..215808765 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js index 8b2dedec2..48242dfbd 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js b/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js deleted file mode 100644 index f5f5b62a8..000000000 --- a/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js +++ /dev/null @@ -1,27 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty("addIntlExtras")) - -// Tests the PluralRules.resolvedOptions function for overriden Array[Symbol.species]. - -addIntlExtras(Intl); - -var pl = new Intl.PluralRules("de"); - -Object.defineProperty(Array, Symbol.species, { - value: function() { - return new Proxy(["?"], { - get(t, pk, r) { - return Reflect.get(t, pk, r); - }, - defineProperty(t, pk) { - return true; - } - }); - } -}); - -var pluralCategories = pl.resolvedOptions().pluralCategories; - -assertEqArray(pluralCategories, ["one", "other"]); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCanonicalLocales-overridden-species.js b/js/src/tests/Intl/getCanonicalLocales-overridden-species.js deleted file mode 100644 index 858735b58..000000000 --- a/js/src/tests/Intl/getCanonicalLocales-overridden-species.js +++ /dev/null @@ -1,23 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("Intl")) - -// Tests the getCanonicalLocales function for overriden Array[Symbol.species]. - -Object.defineProperty(Array, Symbol.species, { - value: function() { - return new Proxy(["?"], { - get(t, pk, r) { - return Reflect.get(t, pk, r); - }, - defineProperty(t, pk) { - return true; - } - }); - } -}); - -var arr = Intl.getCanonicalLocales("de-x-private"); - -assertEqArray(arr, ["de-x-private"]); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/xpconnect/src/ExportHelpers.cpp b/js/xpconnect/src/ExportHelpers.cpp index 3dbf83e3b..e574e708c 100644 --- a/js/xpconnect/src/ExportHelpers.cpp +++ b/js/xpconnect/src/ExportHelpers.cpp @@ -329,11 +329,20 @@ NewFunctionForwarder(JSContext* cx, HandleId idArg, HandleObject callable, if (id == JSID_VOIDHANDLE) id = GetJSIDByIndex(cx, XPCJSContext::IDX_EMPTYSTRING); + // If our callable is a (possibly wrapped) function, we can give + // the exported thing the right number of args. + unsigned nargs = 0; + RootedObject unwrapped(cx, js::UncheckedUnwrap(callable)); + if (unwrapped) { + if (JSFunction* fun = JS_GetObjectFunction(unwrapped)) + nargs = JS_GetFunctionArity(fun); + } + // We have no way of knowing whether the underlying function wants to be a // constructor or not, so we just mark all forwarders as constructors, and // let the underlying function throw for construct calls if it wants. JSFunction* fun = js::NewFunctionByIdWithReserved(cx, FunctionForwarder, - 0, JSFUN_CONSTRUCTOR, id); + nargs, JSFUN_CONSTRUCTOR, id); if (!fun) return false; diff --git a/js/xpconnect/tests/unit/test_exportFunction.js b/js/xpconnect/tests/unit/test_exportFunction.js index 830816342..9e1bf2082 100644 --- a/js/xpconnect/tests/unit/test_exportFunction.js +++ b/js/xpconnect/tests/unit/test_exportFunction.js @@ -10,12 +10,14 @@ function run_test() { epsb.do_check_true = do_check_true; epsb.do_check_eq = do_check_eq; subsb.do_check_true = do_check_true; + subsb.do_check_eq = do_check_eq; // Exporting should work if prinicipal of the source sandbox // subsumes the principal of the target sandbox. Cu.evalInSandbox("(" + function() { var wasCalled = false; this.funToExport = function(expectedThis, a, obj, native, mixed, callback) { + do_check_eq(arguments.callee.length, 6); do_check_eq(a, 42); do_check_eq(obj, subsb.tobecloned); do_check_eq(obj.cloned, "cloned"); @@ -53,6 +55,7 @@ function run_test() { invokedCallback = false; callback = function() { invokedCallback = true; }; imported(this, 42, tobecloned, native, mixed, callback); + do_check_eq(imported.length, 6); do_check_true(invokedCallback); }.toSource() + ")()", subsb); diff --git a/layout/base/RestyleManagerBase.cpp b/layout/base/RestyleManagerBase.cpp index 9a5ce43eb..d96d9dbbb 100644 --- a/layout/base/RestyleManagerBase.cpp +++ b/layout/base/RestyleManagerBase.cpp @@ -154,7 +154,7 @@ RestyleManagerBase::ChangeHintToString(nsChangeHint aHint) "NeutralChange", "InvalidateRenderingObservers", "ReflowChangesSizeOrPosition", "UpdateComputedBSize", "UpdateUsesOpacity", "UpdateBackgroundPosition", - "AddOrRemoveTransform" + "AddOrRemoveTransform", "CSSOverflowChange", }; static_assert(nsChangeHint_AllHints == (1 << ArrayLength(names)) - 1, "Name list doesn't match change hints."); @@ -1070,6 +1070,67 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) FramePropertyTable* propTable = presContext->PropertyTable(); nsCSSFrameConstructor* frameConstructor = presContext->FrameConstructor(); + // Handle nsChangeHint_CSSOverflowChange, by either updating the + // scrollbars on the viewport, or upgrading the change hint to frame-reconstruct. + for (nsStyleChangeData& data : aChangeList) { + if (data.mHint & nsChangeHint_CSSOverflowChange) { + data.mHint &= ~nsChangeHint_CSSOverflowChange; + bool doReconstruct = true; // assume the worst + + // Only bother with this if we're html/body, since: + // (a) It'd be *expensive* to reframe these particular nodes. They're + // at the root, so reframing would mean rebuilding the world. + // (b) It's often *unnecessary* to reframe for "overflow" changes on + // these particular nodes. In general, the only reason we reframe + // for "overflow" changes is so we can construct (or destroy) a + // scrollframe & scrollbars -- and the html/body nodes often don't + // need their own scrollframe/scrollbars because they coopt the ones + // on the viewport (which always exist). So depending on whether + // that's happening, we can skip the reframe for these nodes. + if (data.mContent->IsAnyOfHTMLElements(nsGkAtoms::body, + nsGkAtoms::html)) { + // If the restyled element provided/provides the scrollbar styles for + // the viewport before and/or after this restyle, AND it's not coopting + // that responsibility from some other element (which would need + // reconstruction to make its own scrollframe now), THEN: we don't need + // to reconstruct - we can just reflow, because no scrollframe is being + // added/removed. + nsIContent* prevOverrideNode = + presContext->GetViewportScrollbarStylesOverrideNode(); + nsIContent* newOverrideNode = + presContext->UpdateViewportScrollbarStylesOverride(); + + if (data.mContent == prevOverrideNode || + data.mContent == newOverrideNode) { + // If we get here, the restyled element provided the scrollbar styles + // for viewport before this restyle, OR it will provide them after. + if (!prevOverrideNode || !newOverrideNode || + prevOverrideNode == newOverrideNode) { + // If we get here, the restyled element is NOT replacing (or being + // replaced by) some other element as the viewport's + // scrollbar-styles provider. (If it were, we'd potentially need to + // reframe to create a dedicated scrollframe for whichever element + // is being booted from providing viewport scrollbar styles.) + // + // Under these conditions, we're OK to assume that this "overflow" + // change only impacts the root viewport's scrollframe, which + // already exists, so we can simply reflow instead of reframing. + // When requesting this reflow, we send the exact same change hints + // that "width" and "height" would send (since conceptually, + // adding/removing scrollbars is like changing the available + // space). + data.mHint |= (nsChangeHint_ReflowHintsForISizeChange | + nsChangeHint_ReflowHintsForBSizeChange); + doReconstruct = false; + } + } + } + if (doReconstruct) { + data.mHint |= nsChangeHint_ReconstructFrame; + } + } + } + // Make sure to not rebuild quote or counter lists while we're // processing restyles frameConstructor->BeginUpdate(); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index f8c7f52a9..767298b85 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -8246,11 +8246,19 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, *aDestroyedFramesFor = aChild; } + nsPresContext* presContext = mPresShell->GetPresContext(); + MOZ_ASSERT(presContext, "Our presShell should have a valid presContext"); + if (aChild->IsHTMLElement(nsGkAtoms::body) || (!aContainer && aChild->IsElement())) { - // This might be the element we propagated viewport scrollbar - // styles from. Recompute those. - mPresShell->GetPresContext()->UpdateViewportScrollbarStylesOverride(); + // We might be removing the element that we propagated viewport scrollbar + // styles from. Recompute those. (This clause covers two of the three + // possible scrollbar-propagation sources: the <body> [as aChild or a + // descendant] and the root node. The other possible scrollbar-propagation + // source is a fullscreen element, and we have code elsewhere to update + // scrollbars after fullscreen elements are removed -- specifically, it's + // part of the fullscreen cleanup code called by Element::UnbindFromTree.) + presContext->UpdateViewportScrollbarStylesOverride(); } // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and @@ -8316,7 +8324,6 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, ClearDisplayContentsIn(aChild, aContainer); } - nsPresContext* presContext = mPresShell->GetPresContext(); #ifdef MOZ_XUL if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling, childFrame, CONTENT_REMOVED)) { diff --git a/layout/base/nsCaret.cpp b/layout/base/nsCaret.cpp index 2f08d156e..8ad435950 100644 --- a/layout/base/nsCaret.cpp +++ b/layout/base/nsCaret.cpp @@ -200,8 +200,8 @@ nsCaret::ComputeMetrics(nsIFrame* aFrame, int32_t aOffset, nscoord aCaretHeight) // between 0 and 1 goes up to 1 so we don't let the caret disappear. int32_t tpp = aFrame->PresContext()->AppUnitsPerDevPixel(); Metrics result; - result.mCaretWidth = NS_ROUND_BORDER_TO_PIXELS(caretWidth, tpp); - result.mBidiIndicatorSize = NS_ROUND_BORDER_TO_PIXELS(bidiIndicatorSize, tpp); + result.mCaretWidth = NS_ROUND_CARET_TO_PIXELS(caretWidth, tpp); + result.mBidiIndicatorSize = NS_ROUND_CARET_TO_PIXELS(bidiIndicatorSize, tpp); return result; } diff --git a/layout/base/nsChangeHint.h b/layout/base/nsChangeHint.h index 318b84840..eb2709de6 100644 --- a/layout/base/nsChangeHint.h +++ b/layout/base/nsChangeHint.h @@ -217,6 +217,16 @@ enum nsChangeHint { */ nsChangeHint_AddOrRemoveTransform = 1 << 27, + /** + * Indicates that the overflow-x and/or overflow-y property changed. + * + * In most cases, this is equivalent to nsChangeHint_ReconstructFrame. But + * in some special cases where the change is really targeting the viewport's + * scrollframe, this is instead equivalent to nsChangeHint_AllReflowHints + * (because the viewport always has an associated scrollframe). + */ + nsChangeHint_CSSOverflowChange = 1 << 28, + // IMPORTANT NOTE: When adding new hints, consider whether you need // to add them to NS_HintsNotHandledForDescendantsIn() below. Please // also add them to RestyleManager::ChangeHintToString and modify @@ -225,7 +235,7 @@ enum nsChangeHint { /** * Dummy hint value for all hints. It exists for compile time check. */ - nsChangeHint_AllHints = (1 << 28) - 1, + nsChangeHint_AllHints = (1 << 29) - 1, }; // Redefine these operators to return nothing. This will catch any use @@ -306,6 +316,7 @@ inline nsChangeHint operator^=(nsChangeHint& aLeft, nsChangeHint aRight) nsChangeHint_UpdatePostTransformOverflow | \ nsChangeHint_UpdateParentOverflow | \ nsChangeHint_ChildrenOnlyTransform | \ + nsChangeHint_CSSOverflowChange | \ nsChangeHint_RecomputePosition | \ nsChangeHint_UpdateContainingBlock | \ nsChangeHint_AddOrRemoveTransform | \ @@ -374,6 +385,48 @@ inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint) nsChangeHint_ClearAncestorIntrinsics | \ nsChangeHint_ClearDescendantIntrinsics | \ nsChangeHint_NeedDirtyReflow) + +// Below are the change hints that we send for ISize & BSize changes. +// Each is similar to nsChangeHint_AllReflowHints with a few changes. + +// * For an ISize change, we send nsChangeHint_AllReflowHints, with two bits +// excluded: nsChangeHint_ClearDescendantIntrinsics (because an ancestor's +// inline-size change can't affect descendant intrinsic sizes), and +// nsChangeHint_NeedDirtyReflow (because ISize changes don't need to *force* +// all descendants to reflow). +#define nsChangeHint_ReflowHintsForISizeChange \ + nsChangeHint(nsChangeHint_AllReflowHints & \ + ~(nsChangeHint_ClearDescendantIntrinsics | \ + nsChangeHint_NeedDirtyReflow)) + +// * For a BSize change, we send almost the same hints as for ISize changes, +// with one extra: nsChangeHint_UpdateComputedBSize. We need this hint because +// BSize changes CAN affect descendant intrinsic sizes, due to replaced +// elements with percentage BSizes in descendants which also have percentage +// BSizes. nsChangeHint_UpdateComputedBSize clears intrinsic sizes for frames +// that have such replaced elements. (We could instead send +// nsChangeHint_ClearDescendantIntrinsics, but that's broader than we need.) +// +// NOTE: You might think that BSize changes could exclude +// nsChangeHint_ClearAncestorIntrinsics (which is inline-axis specific), but we +// do need to send it, to clear cached results from CSS Flex measuring reflows. +#define nsChangeHint_ReflowHintsForBSizeChange \ + nsChangeHint((nsChangeHint_AllReflowHints | \ + nsChangeHint_UpdateComputedBSize) & \ + ~(nsChangeHint_ClearDescendantIntrinsics | \ + nsChangeHint_NeedDirtyReflow)) + +// * For changes to the float area of an already-floated element, we need all +// reflow hints, but not the ones that apply to descendants. +// Our descendants aren't impacted when our float area only changes +// placement but not size/shape. (e.g. if we change which side we float to). +// But our ancestors/siblings are potentially impacted, so we need to send +// the non-descendant reflow hints. +#define nsChangeHint_ReflowHintsForFloatAreaChange \ + nsChangeHint(nsChangeHint_AllReflowHints & \ + ~(nsChangeHint_ClearDescendantIntrinsics | \ + nsChangeHint_NeedDirtyReflow)) + #define NS_STYLE_HINT_REFLOW \ nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_AllReflowHints) diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index cbbae0e8f..5990402ed 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -1298,11 +1298,11 @@ public: } }; - static void DispatchGotOrLostPointerCaptureEvent(bool aIsGotCapture, - uint32_t aPointerId, - uint16_t aPointerType, - bool aIsPrimary, - nsIContent* aCaptureTarget); + static void DispatchGotOrLostPointerCaptureEvent( + bool aIsGotCapture, + const mozilla::WidgetPointerEvent* aPointerEvent, + nsIContent* aCaptureTarget); + static PointerCaptureInfo* GetPointerCaptureInfo(uint32_t aPointerId); static void SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aContent); @@ -1311,8 +1311,8 @@ public: // CheckPointerCaptureState checks cases, when got/lostpointercapture events // should be fired. - static void CheckPointerCaptureState(uint32_t aPointerId, - uint16_t aPointerType, bool aIsPrimary); + static void CheckPointerCaptureState( + const mozilla::WidgetPointerEvent* aPointerEvent); // GetPointerInfo returns true if pointer with aPointerId is situated in // device, false otherwise. diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index d9f7b368c..4a54a8432 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -208,6 +208,7 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType) mTextZoom(1.0), mFullZoom(1.0), mOverrideDPPX(0.0), mLastFontInflationScreenSize(gfxSize(-1.0, -1.0)), mPageSize(-1, -1), mPPScale(1.0f), + mViewportScrollbarOverrideNode(nullptr), mViewportStyleScrollbar(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO), mImageAnimationModePref(imgIContainer::kNormalAnimMode), mAllInvalidated(false), @@ -1423,10 +1424,10 @@ nsPresContext::UpdateViewportScrollbarStylesOverride() // Start off with our default styles, and then update them as needed. mViewportStyleScrollbar = ScrollbarStyles(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO); - nsIContent* propagatedFrom = nullptr; + mViewportScrollbarOverrideNode = nullptr; // Don't propagate the scrollbar state in printing or print preview. if (!IsPaginated()) { - propagatedFrom = + mViewportScrollbarOverrideNode = GetPropagatedScrollbarStylesForViewport(this, &mViewportStyleScrollbar); } @@ -1438,13 +1439,13 @@ nsPresContext::UpdateViewportScrollbarStylesOverride() // the styles are from, so that the state of those elements is not // affected across fullscreen change. if (fullscreenElement != document->GetRootElement() && - fullscreenElement != propagatedFrom) { + fullscreenElement != mViewportScrollbarOverrideNode) { mViewportStyleScrollbar = ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN); } } - return propagatedFrom; + return mViewportScrollbarOverrideNode; } bool diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 4fdc60a2e..d8f876291 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -719,7 +719,18 @@ public: * it was propagated from. */ nsIContent* UpdateViewportScrollbarStylesOverride(); - const ScrollbarStyles& GetViewportScrollbarStylesOverride() + + /** + * Returns the cached result from the last call to + * UpdateViewportScrollbarStylesOverride() -- i.e. return the node + * whose scrollbar styles we have propagated to the viewport (or nullptr if + * there is no such node). + */ + nsIContent* GetViewportScrollbarStylesOverrideNode() const { + return mViewportScrollbarOverrideNode; + } + + const ScrollbarStyles& GetViewportScrollbarStylesOverride() const { return mViewportStyleScrollbar; } @@ -1310,7 +1321,16 @@ protected: nscolor mBodyTextColor; + // This is a non-owning pointer. May be null. If non-null, it's guaranteed + // to be pointing to a node that's still alive, because we'll reset it in + // UpdateViewportScrollbarStylesOverride() as part of the cleanup code + // when this node is removed from the document. (For <body> and the root node, + // this call happens in nsCSSFrameConstructor::ContentRemoved(). For + // fullscreen elements, it happens in the fullscreen-specific cleanup + // invoked by Element::UnbindFromTree().) + nsIContent* MOZ_NON_OWNING_REF mViewportScrollbarOverrideNode; ScrollbarStyles mViewportStyleScrollbar; + uint8_t mFocusRingWidth; bool mExistThrottledUpdates; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 56ac370b9..42b39c860 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -6514,10 +6514,11 @@ nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId) } /* static */ void -nsIPresShell::CheckPointerCaptureState(uint32_t aPointerId, - uint16_t aPointerType, bool aIsPrimary) +nsIPresShell::CheckPointerCaptureState(const WidgetPointerEvent* aPointerEvent) { - PointerCaptureInfo* captureInfo = GetPointerCaptureInfo(aPointerId); + PointerCaptureInfo* captureInfo = + GetPointerCaptureInfo(aPointerEvent->pointerId); + if (captureInfo && captureInfo->mPendingContent != captureInfo->mOverrideContent) { // cache captureInfo->mPendingContent since it may be changed in the pointer @@ -6525,17 +6526,16 @@ nsIPresShell::CheckPointerCaptureState(uint32_t aPointerId, nsIContent* pendingContent = captureInfo->mPendingContent.get(); if (captureInfo->mOverrideContent) { DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false, - aPointerId, aPointerType, aIsPrimary, + aPointerEvent, captureInfo->mOverrideContent); } if (pendingContent) { - DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true, aPointerId, - aPointerType, aIsPrimary, - pendingContent); + DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true, + aPointerEvent, pendingContent); } captureInfo->mOverrideContent = pendingContent; if (captureInfo->Empty()) { - sPointerCaptureList->Remove(aPointerId); + sPointerCaptureList->Remove(aPointerEvent->pointerId); } } } @@ -6976,37 +6976,30 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell, return NS_OK; } -class ReleasePointerCaptureCaller +class ReleasePointerCaptureCaller final { public: - ReleasePointerCaptureCaller() : - mPointerId(0), - mPointerType(nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN), - mIsPrimary(false), - mIsSet(false) + ReleasePointerCaptureCaller() + : mPointerEvent(nullptr) { } ~ReleasePointerCaptureCaller() { - if (mIsSet) { - nsIPresShell::ReleasePointerCapturingContent(mPointerId); - nsIPresShell::CheckPointerCaptureState(mPointerId, mPointerType, - mIsPrimary); + if (mPointerEvent) { + nsIPresShell::ReleasePointerCapturingContent(mPointerEvent->pointerId); + nsIPresShell::CheckPointerCaptureState(mPointerEvent); } } - void SetTarget(uint32_t aPointerId, uint16_t aPointerType, bool aIsPrimary) + + void SetTarget(const WidgetPointerEvent* aPointerEvent) { - mPointerId = aPointerId; - mPointerType = aPointerType; - mIsPrimary = aIsPrimary; - mIsSet = true; + MOZ_ASSERT(aPointerEvent); + mPointerEvent = aPointerEvent; } private: - int32_t mPointerId; - uint16_t mPointerType; - bool mIsPrimary; - bool mIsSet; + // This is synchronously used inside PresShell::HandleEvent. + const WidgetPointerEvent* mPointerEvent; }; static bool @@ -7719,9 +7712,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, nsWeakFrame frameKeeper(frame); // Handle pending pointer capture before any pointer events except // gotpointercapture / lostpointercapture. - CheckPointerCaptureState(pointerEvent->pointerId, - pointerEvent->inputSource, - pointerEvent->mIsPrimary); + CheckPointerCaptureState(pointerEvent); // Prevent application crashes, in case damaged frame. if (!frameKeeper.IsAlive()) { frame = nullptr; @@ -7742,33 +7733,29 @@ PresShell::HandleEvent(nsIFrame* aFrame, } } - if (aEvent->mClass == ePointerEventClass && - aEvent->mMessage != ePointerDown) { - if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { - uint32_t pointerId = pointerEvent->pointerId; + // Mouse events should be fired to the same target as their mapped pointer + // events + if ((aEvent->mClass == ePointerEventClass || + aEvent->mClass == eMouseEventClass) && + aEvent->mMessage != ePointerDown && aEvent->mMessage != eMouseDown) { + if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { + uint32_t pointerId = mouseEvent->pointerId; nsIContent* pointerCapturingContent = GetPointerCapturingContent(pointerId); if (pointerCapturingContent) { if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) { - // If pointer capture is set, we should suppress - // pointerover/pointerenter events for all elements except element - // which have pointer capture. (Code in EventStateManager) - pointerEvent->retargetedByPointerCapture = - frame && frame->GetContent() && - !nsContentUtils::ContentIsDescendantOf(frame->GetContent(), - pointerCapturingContent); frame = capturingFrame; } - if (pointerEvent->mMessage == ePointerUp || - pointerEvent->mMessage == ePointerCancel) { + if (aEvent->mMessage == ePointerUp || + aEvent->mMessage == ePointerCancel) { // Implicitly releasing capture for given pointer. // ePointerLostCapture should be send after ePointerUp or // ePointerCancel. - releasePointerCaptureCaller.SetTarget(pointerId, - pointerEvent->inputSource, - pointerEvent->mIsPrimary); + WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent(); + MOZ_ASSERT(pointerEvent); + releasePointerCaptureCaller.SetTarget(pointerEvent); } } } @@ -8204,6 +8191,8 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, } case eMouseDown: case eMouseUp: + case ePointerDown: + case ePointerUp: isHandlingUserInput = true; break; @@ -8340,35 +8329,44 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, return rv; } -void -nsIPresShell::DispatchGotOrLostPointerCaptureEvent(bool aIsGotCapture, - uint32_t aPointerId, - uint16_t aPointerType, - bool aIsPrimary, - nsIContent* aCaptureTarget) -{ - PointerEventInit init; - init.mPointerId = aPointerId; - init.mBubbles = true; - ConvertPointerTypeToString(aPointerType, init.mPointerType); - init.mIsPrimary = aIsPrimary; - RefPtr<mozilla::dom::PointerEvent> event; - event = PointerEvent::Constructor(aCaptureTarget, - aIsGotCapture - ? NS_LITERAL_STRING("gotpointercapture") - : NS_LITERAL_STRING("lostpointercapture"), - init); - if (event) { +/* static */ void +nsIPresShell::DispatchGotOrLostPointerCaptureEvent( + bool aIsGotCapture, + const WidgetPointerEvent* aPointerEvent, + nsIContent* aCaptureTarget) +{ + nsIDocument* targetDoc = aCaptureTarget->OwnerDoc(); + nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell(); + NS_ENSURE_TRUE_VOID(shell); + + if (!aIsGotCapture && !aCaptureTarget->IsInUncomposedDoc()) { + // If the capturing element was removed from the DOM tree, fire + // ePointerLostCapture at the document. + PointerEventInit init; + init.mPointerId = aPointerEvent->pointerId; + init.mBubbles = true; + init.mComposed = true; + ConvertPointerTypeToString(aPointerEvent->inputSource, init.mPointerType); + init.mIsPrimary = aPointerEvent->mIsPrimary; + RefPtr<mozilla::dom::PointerEvent> event; + event = PointerEvent::Constructor(aCaptureTarget, + NS_LITERAL_STRING("lostpointercapture"), + init); bool dummy; - // If the capturing element was removed from the DOM tree, - // lostpointercapture event should be fired at the document. - if (!aIsGotCapture && !aCaptureTarget->IsInUncomposedDoc()) { - aCaptureTarget->OwnerDoc()->DispatchEvent(event->InternalDOMEvent(), - &dummy); - } else { - aCaptureTarget->DispatchEvent(event->InternalDOMEvent(), &dummy); - } + targetDoc->DispatchEvent(event->InternalDOMEvent(), &dummy); + return; } + nsEventStatus status = nsEventStatus_eIgnore; + WidgetPointerEvent localEvent(aPointerEvent->IsTrusted(), + aIsGotCapture ? ePointerGotCapture : + ePointerLostCapture, + aPointerEvent->mWidget); + localEvent.AssignPointerEventData(*aPointerEvent, true); + nsresult rv = shell->HandleEventWithTarget( + &localEvent, + aCaptureTarget->GetPrimaryFrame(), + aCaptureTarget, &status); + NS_ENSURE_SUCCESS_VOID(rv); } nsresult diff --git a/layout/base/tests/bug1078327_inner.html b/layout/base/tests/bug1078327_inner.html index 9e32fc996..0cfb9da7f 100644 --- a/layout/base/tests/bug1078327_inner.html +++ b/layout/base/tests/bug1078327_inner.html @@ -24,16 +24,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1078327 var test_mediator_move = false; var test_mediator_out = false; var test_listener = false; + var test_lost_capture = false; function TargetHandler(event) { logger("Target receive event: " + event.type + ". Mediator.setPointerCapture()"); mediator.setPointerCapture(event.pointerId); test_target = true; + test_capture = true; } function MediatorHandler(event) { logger("Mediator receive event: " + event.type); - if(event.type == "gotpointercapture") - test_capture = true; if(!test_capture) return; if(event.type == "pointermove") @@ -43,7 +43,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1078327 if(event.type == "pointerout") test_mediator_out++; if(event.type == "lostpointercapture") - test_capture = false; + test_lost_capture = true; } function ListenerHandler(event) { logger("Listener receive event: " + event.type); @@ -86,7 +86,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1078327 } function finishTest() { parent.is(test_target, true, "pointerdown event should be received by target"); - parent.is(test_capture, false, "test_capture should be false at the end of the test"); + parent.is(test_lost_capture, true, "mediator should receive lostpointercapture"); parent.is(test_mediator_over, 1, "mediator should receive pointerover event only once"); parent.is(test_mediator_move, 5, "mediator should receive pointermove event five times"); parent.is(test_mediator_out, 1, "mediator should receive pointerout event only once"); diff --git a/layout/base/tests/bug1162990_inner_1.html b/layout/base/tests/bug1162990_inner_1.html index 4ea5edb5c..0f950df8d 100644 --- a/layout/base/tests/bug1162990_inner_1.html +++ b/layout/base/tests/bug1162990_inner_1.html @@ -111,10 +111,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1162990 } function finishTest() { - parent.is(test_basketLeave, 0, "Part1: basket should not receive pointerleave event after pointer capturing"); + parent.is(test_basketLeave, 1, "Part1: basket should receive pointerleave event after pointer capturing"); parent.is(test_targetGotCapture, 1, "Part1: target should receive gotpointercapture event"); parent.is(test_targetLostCapture, 1, "Part1: target should receive lostpointercapture event"); - parent.is(test_targetLeave, 2, "Part1: target should receive pointerleave event two times"); + parent.is(test_targetLeave, 1, "Part1: target should receive pointerleave event only one time"); parent.is(test_childLeave, 0, "Part1: child should not receive pointerleave event after pointer capturing"); parent.is(test_listenerDown, 1, "Part1: listener should receive pointerdown event"); parent.is(test_listenerLeave, 1, "Part1: listener should receive pointerleave event only one time"); diff --git a/layout/base/tests/bug1162990_inner_2.html b/layout/base/tests/bug1162990_inner_2.html index 54aa74ca3..e418927bd 100644 --- a/layout/base/tests/bug1162990_inner_2.html +++ b/layout/base/tests/bug1162990_inner_2.html @@ -116,7 +116,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1162990 parent.is(test_targetDown, 1, "Part2: target should receive pointerdown event"); parent.is(test_targetGotCapture, 1, "Part2: target should receive gotpointercapture event"); parent.is(test_targetLostCapture, 1, "Part2: target should receive lostpointercapture event"); - parent.is(test_targetLeave, 1, "Part2: target should receive pointerleave event"); + parent.is(test_targetLeave, 0, "Part2: target should not receive pointerleave event"); parent.is(test_childLeave, 0, "Part2: child should not receive pointerleave event after pointer capturing"); parent.is(test_listenerLeave, 0, "Part2: listener should not receive pointerleave event after pointer capturing"); logger("finishTest"); diff --git a/layout/base/tests/bug976963_inner.html b/layout/base/tests/bug976963_inner.html deleted file mode 100644 index 2c55fbccd..000000000 --- a/layout/base/tests/bug976963_inner.html +++ /dev/null @@ -1,241 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=976963 ---> -<head> - <meta charset="utf-8"> - <title>Test for Bug 976963</title> - <meta name="author" content="Maksim Lebedev" /> - <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - <style> - div#listener { - background: yellow; - position: absolute; - top: -100px; - } - div#middler { - background: yellow; - margin: 10px; - } - div#target { - background: yellow; - } - </style> - <script type="application/javascript"> - /** Test for Bug 976963 **/ - var All_Pointer_Events = ["pointerover", "pointerenter", - "pointermove", - "pointerdown", "pointerup", - "pointerout", "pointerleave", - "pointercancel", - "gotpointercapture", "lostpointercapture"]; - - function on_event(object, event, callback) { - object.addEventListener(event, callback, false); - } - function ok(check, msg) { - parent.ok(check, msg); - } - function is(a, b, msg) { - parent.is(a, b, msg); - } - - var listener = undefined; - var middler = undefined; - var target = undefined; - - var test_ListenerGotCapture = 0; - var test_ListenerUnwanted = 0; - var test_ListenerLostCapture = 0; - var test_ListenerAfterCapture = 0; - var test_MiddlerGotCapture = 0; - var test_MiddlerOver = 0; - var test_MiddlerLeave = 0; - var test_MiddlerUp = 0; - var test_MiddlerLostCapture = 0; - var test_TargetDown = 0; - var test_TargetUnwanted = 0; - var test_TargetUp = 0; - - var captured_event = undefined; - var f_gotPointerCapture = false; - var f_lostPointerCapture = false; - var f_gotMiddlerPointerCapture = false; - - function listenerEventHandler(event) { - logger("Listener: " + event.type + ". Captured_event: " + captured_event); - if(test_ListenerLostCapture) - test_ListenerAfterCapture++; - if (event.type == "gotpointercapture") { - f_gotPointerCapture = true; - test_ListenerGotCapture++; - } - else if (event.type == "lostpointercapture") { - f_lostPointerCapture = true; - f_gotPointerCapture = false; - test_ListenerLostCapture++; - } - else if (event.type == "pointermove") { - ok(captured_event && captured_event.pointerId == event.pointerId, "Listener: equals pointerId for lostpointercapture event"); - if (f_gotPointerCapture) { - // on first event received for capture, release capture - logger("Listener call release"); - ok(!!listener, "Listener should be live!"); - ok(typeof(listener.releasePointerCapture) == "function", "Listener should have a function releasePointerCapture"); - listener.releasePointerCapture(event.pointerId); - } - else { - logger("Listener.ASSERT: " + event.type); - test_ListenerUnwanted++; - // if any other events are received after releaseCapture, then the test fails - ok(false, event.target.id + "-" + event.type + " should be handled by target element handler"); - } - } - else { - test_ListenerUnwanted++; - logger("Listener.ASSERT: " + event.type); - ok(false, event.type + "should be never handled by listener"); - } - } - - function middlerEventHandler(event) { - logger("Middler: " + event.type + ". Captured_event: " + captured_event); - if (event.type == "gotpointercapture") { - test_MiddlerGotCapture++; - f_gotMiddlerPointerCapture = true; - ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for gotpointercapture event"); - } - else if (event.type == "pointerover") { - test_MiddlerOver++; - ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for pointerover event"); - } - else if (event.type == "pointerleave") { - test_MiddlerLeave++; - ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for pointerleave event"); - ok(!!listener, "Listener should be live!"); - ok(typeof(listener.setPointerCapture) == "function", "Listener should have a function setPointerCapture"); - listener.setPointerCapture(event.pointerId); - } - else if (event.type == "lostpointercapture") { - test_MiddlerLostCapture++; - f_gotMiddlerPointerCapture = false; - ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for lostpointercapture event"); - } - else if (event.type == "pointerup" ) { - test_MiddlerUp++; - } - } - - function targetEventHandler(event) { - logger("Target: " + event.type + ". Captured_event: " + captured_event); - if (f_gotPointerCapture || f_gotMiddlerPointerCapture) { - if (event.type != "pointerout" && event.type != "pointerleave") { - logger("Target.ASSERT: " + event.type + " " + event.pointerId); - test_TargetUnwanted++; - ok(false, "The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". "); - } - } - if (event.type == "pointerdown") { - logger("Target.pointerdown 1: " + captured_event); - test_TargetDown++; - captured_event = event; - ok(!!middler, "Middler should be live!"); - ok(typeof(middler.setPointerCapture) == "function", "Middler should have a function setPointerCapture"); - middler.setPointerCapture(event.pointerId); - logger("Target.pointerdown 2: " + captured_event); - } - else if (event.type == "pointerup") { - ok(f_lostPointerCapture, "Target should have received pointerup"); - ok(captured_event && captured_event.pointerId == event.pointerId, "Target: equals pointerId for lostpointercapture event"); - test_TargetUp++; // complete test - } - } - - function colorerHandler(event) { - if(event.type == "pointerover") - event.target.style.background = "red"; - else if(event.type == "pointerout") - event.target.style.background = "yellow"; - } - - function setEventHandlers() { - listener = document.getElementById("listener"); - middler = document.getElementById("middler"); - target = document.getElementById("target"); - target.style["touchAction"] = "none"; - - // target and listener - handle all events - for (var i = 0; i < All_Pointer_Events.length; i++) { - on_event(target, All_Pointer_Events[i], targetEventHandler); - on_event(listener, All_Pointer_Events[i], listenerEventHandler); - on_event(middler, All_Pointer_Events[i], middlerEventHandler); - on_event(target, All_Pointer_Events[i], colorerHandler); - on_event(middler, All_Pointer_Events[i], colorerHandler); - } - } - - function prepareTest() { - SpecialPowers.pushPrefEnv({ - "set": [ - ["dom.w3c_pointer_events.enabled", true] - ] - }, executeTest); - } - - function executeTest() - { - logger("executeTest"); - setEventHandlers(); - document.body.offsetLeft; - var rect = target.getBoundingClientRect(); - synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"}); - synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerdown"}); - synthesizePointer(target, rect.width/3, rect.height/3, {type: "pointermove"}); - synthesizePointer(middler, rect.width/2, rect.height/2, {type: "pointermove"}); - synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"}); - synthesizePointer(middler, rect.width/2, rect.height/2, {type: "pointermove"}); - synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"}); - synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerup"}); - finishTest(); - } - - function finishTest() { - setTimeout(function() { - is(test_ListenerGotCapture, 1, "Listener should receive gotpointercapture event"); - is(test_ListenerUnwanted, 0, "Listener should not receive any unwanted events"); - is(test_ListenerLostCapture, 1, "Listener should receive lostpointercapture event"); - is(test_ListenerAfterCapture, 0, "Listener should not receive any events after release pointer capture"); - is(test_MiddlerGotCapture, 1, "Middler should receive gotpointercapture event"); - is(test_MiddlerOver, 1, "Middler should receive pointerover event"); - is(test_MiddlerLeave, 1, "Middler should receive pointerleave event"); - is(test_MiddlerUp, 0, "Middler should not receive pointerup event"); - is(test_MiddlerLostCapture, 1, "Middler should receive lostpointercapture event"); - is(test_TargetDown, 1, "Target should receive pointerdown event"); - is(test_TargetUnwanted, 0, "Target should not receive any event while pointer capture is active"); - is(test_TargetUp, 1, "Target should receive pointerup event"); - logger("finishTest"); - parent.finishTest(); - }, 1000); - } - - function logger(message) { - console.log(message); - var log = document.getElementById('log'); - log.innerHTML = message + "<br>" + log.innerHTML; - } - </script> -</head> -<body onload="prepareTest()"> - <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=976963">Mozilla Bug 976963</a> - <p id="display"></p> - <div id="content" style="display: none"> - </div> - <div id="listener">div id=listener</div> - <div id="middler">div id=middler</div> - <div id="target">div id=target</div> - <pre id="log"> - </pre> -</body> -</html> diff --git a/layout/base/tests/bug977003_inner_5.html b/layout/base/tests/bug977003_inner_5.html index 70fc5ba40..81094043c 100644 --- a/layout/base/tests/bug977003_inner_5.html +++ b/layout/base/tests/bug977003_inner_5.html @@ -26,6 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098139 var test_lost_listener = false; var test_lost_type = ""; var test_move_listener = false; + var test_over_listener = false; var test_listener = false; var test_lost_primary = false; @@ -53,6 +54,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098139 logger("Receive event on Listener: " + event.type); test_move_listener = true; } + function ListenerOverHandler(event) { + logger("Receive event on Listener: " + event.type); + test_over_listener = true; + } function ListenerHandler(event) { logger("Receive event on Listener: " + event.type); test_listener = true; @@ -74,7 +79,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098139 target.addEventListener("pointerdown", TargetDownHandler, false); listener.addEventListener("gotpointercapture", ListenerGotPCHandler, false); listener.addEventListener("lostpointercapture", ListenerLostPCHandler, false); - listener.addEventListener("pointerover", ListenerHandler, false); + listener.addEventListener("pointerover", ListenerOverHandler, false); listener.addEventListener("pointermove", ListenerMoveHandler, false); listener.addEventListener("pointerup", ListenerHandler, false); listener.addEventListener("pointerout", ListenerHandler, false); @@ -93,6 +98,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098139 parent.is(test_lost_type, "touch", "Part 5: lostpointercapture event should have pointerType touch"); parent.is(test_lost_primary, true, "Part 5: lostpointercapture event should have isPrimary as true"); parent.is(test_move_listener, true, "Part 5: gotpointercapture should be triggered by pointermove"); + parent.is(test_over_listener, true, "Part 5: listener should receive pointerover when capturing pointer"); parent.is(test_listener, false, "Part 5: listener should not receive any other events"); logger("finishTest"); parent.finishTest(); diff --git a/layout/base/tests/bug977003_inner_6.html b/layout/base/tests/bug977003_inner_6.html index 12424b1f2..b60ca5c31 100644 --- a/layout/base/tests/bug977003_inner_6.html +++ b/layout/base/tests/bug977003_inner_6.html @@ -19,6 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1073563 var listener = undefined; var test_target = false; var test_move = false; + var test_over = false; var test_listener = false; var receive_lostpointercapture = false; @@ -44,6 +45,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1073563 } } else if(event.type == "pointermove") { test_move = true; + } else if(event.type == "pointerover") { + test_over = true; } else { test_listener = true; } @@ -81,7 +84,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1073563 // PE level 2 defines that the pending pointer capture is processed when firing next pointer events. // In this test case, pointer capture release is processed when firing pointermove parent.is(test_move, true, "Part 6: gotpointercapture should be triggered by pointermove"); - parent.is(test_listener, false, "Part 6: no other pointerevents should be fired before gotpointercapture"); + parent.is(test_over, true, "Part 6: pointerover should be received when capturing pointer"); + parent.is(test_listener, false, "Part 6: no other pointerevents should be fired before gotpointercapture except pointerover"); logger("finishTest"); parent.finishTest(); } diff --git a/layout/base/tests/mochitest.ini b/layout/base/tests/mochitest.ini index 279b0af8a..405697977 100644 --- a/layout/base/tests/mochitest.ini +++ b/layout/base/tests/mochitest.ini @@ -256,8 +256,6 @@ skip-if = toolkit == 'android' support-files = bug851445_helper.html [test_bug970964.html] support-files = bug970964_inner.html -[test_bug976963.html] -support-files = bug976963_inner.html [test_bug977003.html] support-files = bug977003_inner_1.html diff --git a/layout/base/tests/test_bug976963.html b/layout/base/tests/test_bug976963.html deleted file mode 100644 index 4b8da3a6e..000000000 --- a/layout/base/tests/test_bug976963.html +++ /dev/null @@ -1,35 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=976963 ---> - <head> - <meta charset="utf-8"> - <meta name="author" content="Maksim Lebedev" /> - <title>Test for Bug 976963</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - <script type="text/javascript"> - function prepareTest() { - SimpleTest.waitForExplicitFinish(); - SimpleTest.requestFlakyTimeout("untriaged"); - SpecialPowers.pushPrefEnv({ - "set": [ - ["dom.w3c_pointer_events.enabled", true], - ["layout.reflow.synthMouseMove", false] - ] - }, startTest); - } - function startTest() { - var iframe = document.getElementById("testFrame"); - iframe.src = "bug976963_inner.html"; - } - function finishTest() { - SimpleTest.finish(); - } - </script> - </head> - <body onload="prepareTest()"> - <iframe id="testFrame" height="700" width="700"></iframe> - </body> -</html> diff --git a/layout/generic/Selection.h b/layout/generic/Selection.h index 6f94303ca..3d5e334fc 100644 --- a/layout/generic/Selection.h +++ b/layout/generic/Selection.h @@ -179,6 +179,9 @@ public: { return mRanges.Length(); } + + void GetType(nsAString& aOutType) const; + nsRange* GetRangeAt(uint32_t aIndex, mozilla::ErrorResult& aRv); void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv); void RemoveRange(nsRange& aRange, mozilla::ErrorResult& aRv); diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index b61024324..3818d3cb7 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -33,6 +33,8 @@ typedef nsFlexContainerFrame::FlexItem FlexItem; typedef nsFlexContainerFrame::FlexLine FlexLine; typedef nsFlexContainerFrame::FlexboxAxisTracker FlexboxAxisTracker; typedef nsFlexContainerFrame::StrutInfo StrutInfo; +typedef nsFlexContainerFrame::CachedMeasuringReflowResult + CachedMeasuringReflowResult; static mozilla::LazyLogModule gFlexContainerLog("nsFlexContainerFrame"); @@ -1756,6 +1758,108 @@ nsFlexContainerFrame:: } } +/** + * A cached result for a measuring reflow. + * + * Right now we only need to cache the available size and the computed height + * for checking that the reflow input is valid, and the height and the ascent + * to be used. This can be extended later if needed. + * + * The assumption here is that a given flex item measurement won't change until + * either the available size or computed height changes, or the flex container + * intrinsic size is marked as dirty (due to a style or DOM change). + * + * In particular the computed height may change between measuring reflows due to + * how the mIsFlexContainerMeasuringReflow flag affects size computation (see + * bug 1336708). + * + * Caching it prevents us from doing exponential reflows in cases of deeply + * nested flex and scroll frames. + * + * We store them in the frame property table for simplicity. + */ +class nsFlexContainerFrame::CachedMeasuringReflowResult +{ + // Members that are part of the cache key: + const LogicalSize mAvailableSize; + const nscoord mComputedHeight; + + // Members that are part of the cache value: + const nscoord mHeight; + const nscoord mAscent; + +public: + CachedMeasuringReflowResult(const ReflowInput& aReflowInput, + const ReflowOutput& aDesiredSize) + : mAvailableSize(aReflowInput.AvailableSize()) + , mComputedHeight(aReflowInput.ComputedHeight()) + , mHeight(aDesiredSize.Height()) + , mAscent(aDesiredSize.BlockStartAscent()) + {} + + bool IsValidFor(const ReflowInput& aReflowInput) const { + return mAvailableSize == aReflowInput.AvailableSize() && + mComputedHeight == aReflowInput.ComputedHeight(); + } + + nscoord Height() const { return mHeight; } + + nscoord Ascent() const { return mAscent; } +}; + +NS_DECLARE_FRAME_PROPERTY_DELETABLE(CachedFlexMeasuringReflow, + CachedMeasuringReflowResult); + +const CachedMeasuringReflowResult& +nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem( + FlexItem& aItem, + nsPresContext* aPresContext, + ReflowInput& aChildReflowInput) +{ + const FrameProperties props = aItem.Frame()->Properties(); + if (const auto* cachedResult = props.Get(CachedFlexMeasuringReflow())) { + if (cachedResult->IsValidFor(aChildReflowInput)) { + return *cachedResult; + } + } + + ReflowOutput childDesiredSize(aChildReflowInput); + nsReflowStatus childReflowStatus; + + const uint32_t flags = NS_FRAME_NO_MOVE_FRAME; + ReflowChild(aItem.Frame(), aPresContext, + childDesiredSize, aChildReflowInput, + 0, 0, flags, childReflowStatus); + aItem.SetHadMeasuringReflow(); + + // XXXdholbert Once we do pagination / splitting, we'll need to actually + // handle incomplete childReflowStatuses. But for now, we give our kids + // unconstrained available height, which means they should always complete. + MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus), + "We gave flex item unconstrained available height, so it " + "should be complete"); + + // Tell the child we're done with its initial reflow. + // (Necessary for e.g. GetBaseline() to work below w/out asserting) + FinishReflowChild(aItem.Frame(), aPresContext, + childDesiredSize, &aChildReflowInput, 0, 0, flags); + + auto result = + new CachedMeasuringReflowResult(aChildReflowInput, childDesiredSize); + + props.Set(CachedFlexMeasuringReflow(), result); + return *result; +} + +/* virtual */ void +nsFlexContainerFrame::MarkIntrinsicISizesDirty() +{ + for (nsIFrame* childFrame : mFrames) { + childFrame->Properties().Delete(CachedFlexMeasuringReflow()); + } + nsContainerFrame::MarkIntrinsicISizesDirty(); +} + nscoord nsFlexContainerFrame:: MeasureFlexItemContentHeight(nsPresContext* aPresContext, @@ -1783,27 +1887,15 @@ nsFlexContainerFrame:: childRIForMeasuringHeight.SetVResize(true); } - ReflowOutput childDesiredSize(childRIForMeasuringHeight); - nsReflowStatus childReflowStatus; - const uint32_t flags = NS_FRAME_NO_MOVE_FRAME; - ReflowChild(aFlexItem.Frame(), aPresContext, - childDesiredSize, childRIForMeasuringHeight, - 0, 0, flags, childReflowStatus); - - MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus), - "We gave flex item unconstrained available height, so it " - "should be complete"); - - FinishReflowChild(aFlexItem.Frame(), aPresContext, - childDesiredSize, &childRIForMeasuringHeight, - 0, 0, flags); + const CachedMeasuringReflowResult& reflowResult = + MeasureAscentAndHeightForFlexItem(aFlexItem, aPresContext, + childRIForMeasuringHeight); - aFlexItem.SetHadMeasuringReflow(); - aFlexItem.SetAscent(childDesiredSize.BlockStartAscent()); + aFlexItem.SetAscent(reflowResult.Ascent()); // Subtract border/padding in vertical axis, to get _just_ // the effective computed value of the "height" property. - nscoord childDesiredHeight = childDesiredSize.Height() - + nscoord childDesiredHeight = reflowResult.Height() - childRIForMeasuringHeight.ComputedPhysicalBorderPadding().TopBottom(); return std::max(0, childDesiredHeight); @@ -3959,25 +4051,10 @@ nsFlexContainerFrame::SizeItemInCrossAxis( // whether any of its ancestors are being resized). aChildReflowInput.SetVResize(true); } - ReflowOutput childDesiredSize(aChildReflowInput); - nsReflowStatus childReflowStatus; - const uint32_t flags = NS_FRAME_NO_MOVE_FRAME; - ReflowChild(aItem.Frame(), aPresContext, - childDesiredSize, aChildReflowInput, - 0, 0, flags, childReflowStatus); - aItem.SetHadMeasuringReflow(); - - // XXXdholbert Once we do pagination / splitting, we'll need to actually - // handle incomplete childReflowStatuses. But for now, we give our kids - // unconstrained available height, which means they should always complete. - MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus), - "We gave flex item unconstrained available height, so it " - "should be complete"); - // Tell the child we're done with its initial reflow. - // (Necessary for e.g. GetBaseline() to work below w/out asserting) - FinishReflowChild(aItem.Frame(), aPresContext, - childDesiredSize, &aChildReflowInput, 0, 0, flags); + // Potentially reflow the item, and get the sizing info. + const CachedMeasuringReflowResult& reflowResult = + MeasureAscentAndHeightForFlexItem(aItem, aPresContext, aChildReflowInput); // Save the sizing info that we learned from this reflow // ----------------------------------------------------- @@ -3989,7 +4066,7 @@ nsFlexContainerFrame::SizeItemInCrossAxis( // so we don't bother with making aAxisTracker pick the cross-axis component // for us.) nscoord crossAxisBorderPadding = aItem.GetBorderPadding().TopBottom(); - if (childDesiredSize.Height() < crossAxisBorderPadding) { + if (reflowResult.Height() < crossAxisBorderPadding) { // Child's requested size isn't large enough for its border/padding! // This is OK for the trivial nsFrame::Reflow() impl, but other frame // classes should know better. So, if we get here, the child had better be @@ -4002,10 +4079,10 @@ nsFlexContainerFrame::SizeItemInCrossAxis( aItem.SetCrossSize(0); } else { // (normal case) - aItem.SetCrossSize(childDesiredSize.Height() - crossAxisBorderPadding); + aItem.SetCrossSize(reflowResult.Height() - crossAxisBorderPadding); } - aItem.SetAscent(childDesiredSize.BlockStartAscent()); + aItem.SetAscent(reflowResult.Ascent()); } void @@ -4295,7 +4372,7 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext, LogicalSize availSize = aReflowInput.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; ReflowInput childReflowInput(aPresContext, aReflowInput, - item->Frame(), availSize); + item->Frame(), availSize); if (!sizeOverride) { // Directly override the computed main-size, by tweaking reflow state: if (aAxisTracker.IsMainAxisHorizontal()) { diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index 22b420d85..459ae8e20 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -56,6 +56,7 @@ public: class FlexLine; class FlexboxAxisTracker; struct StrutInfo; + class CachedMeasuringReflowResult; // nsIFrame overrides void Init(nsIContent* aContent, @@ -66,6 +67,8 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; + void MarkIntrinsicISizesDirty() override; + virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, @@ -195,6 +198,18 @@ protected: const FlexboxAxisTracker& aAxisTracker); /** + * This method gets a cached measuring reflow for a flex item, or does it and + * caches it. + * + * This avoids exponential reflows, see the comment on + * CachedMeasuringReflowResult. + */ + const CachedMeasuringReflowResult& MeasureAscentAndHeightForFlexItem( + FlexItem& aItem, + nsPresContext* aPresContext, + ReflowInput& aChildReflowInput); + + /** * This method performs a "measuring" reflow to get the content height of * aFlexItem.Frame() (treating it as if it had auto-height), & returns the * resulting height. diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index e0d65632e..a2227c39c 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -5349,6 +5349,18 @@ Selection::GetRangeCount(int32_t* aRangeCount) return NS_OK; } +void +Selection::GetType(nsAString& aOutType) const +{ + if (!RangeCount()) { + aOutType.AssignLiteral("None"); + } else if (IsCollapsed()) { + aOutType.AssignLiteral("Caret"); + } else { + aOutType.AssignLiteral("Range"); + } +} + NS_IMETHODIMP Selection::GetRangeAt(int32_t aIndex, nsIDOMRange** aReturn) { diff --git a/layout/reftests/scrolling/propagated-overflow-style-1-ref.html b/layout/reftests/scrolling/propagated-overflow-style-1-ref.html new file mode 100644 index 000000000..7c2b1b315 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-1-ref.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title> + Reference case with body and html *independently* scrollable. + </title> + <style> + html { + overflow: scroll; + } + body { + overflow: scroll; + } + </style> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-1a.html b/layout/reftests/scrolling/propagated-overflow-style-1a.html new file mode 100644 index 000000000..b5115d36f --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-1a.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> + <title> + Testcase with body and html *independently* scrollable, + with body's "overflow" set dynamically. + </title> + <style> + html { + overflow: scroll; + } + </style> + <script> + function doTest() { + document.body.style.overflow = "scroll"; + document.documentElement.removeAttribute("class"); + } + window.addEventListener("MozReftestInvalidate", doTest); + </script> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-1b.html b/layout/reftests/scrolling/propagated-overflow-style-1b.html new file mode 100644 index 000000000..4608b87d6 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-1b.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> + <title> + Testcase with body and html *independently* scrollable, + with html's "overflow" set dynamically. + </title> + <style> + body { + overflow: scroll; + } + </style> + <script> + function doTest() { + document.documentElement.style.overflow = "scroll"; + document.documentElement.removeAttribute("class"); + } + window.addEventListener("MozReftestInvalidate", doTest); + </script> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-1c.html b/layout/reftests/scrolling/propagated-overflow-style-1c.html new file mode 100644 index 000000000..11809915a --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-1c.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> + <title> + Testcase with body and html *independently* scrollable, + with both html & body's "overflow" set dynamically. + </title> + <script> + function doTest() { + document.documentElement.style.overflow = "scroll"; + document.body.style.overflow = "scroll"; + document.documentElement.removeAttribute("class"); + } + window.addEventListener("MozReftestInvalidate", doTest); + </script> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-2-ref.html b/layout/reftests/scrolling/propagated-overflow-style-2-ref.html new file mode 100644 index 000000000..20c3b8ae5 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2-ref.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <title> + Reference case with the root viewport scrollable, via styles on html node. + </title> + <style> + html { + overflow: scroll; + } + </style> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-2a.html b/layout/reftests/scrolling/propagated-overflow-style-2a.html new file mode 100644 index 000000000..250bedd6c --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2a.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> + <title> + Testcase with only one of [html,body] being scrollable, + after body's "overflow" is reset dynamically. + </title> + <style> + html { + overflow: scroll; + } + body { + overflow: scroll; + } + </style> + <script> + function doTest() { + document.body.style.overflow = "visible"; + document.documentElement.removeAttribute("class"); + } + window.addEventListener("MozReftestInvalidate", doTest); + </script> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-2b.html b/layout/reftests/scrolling/propagated-overflow-style-2b.html new file mode 100644 index 000000000..c94ddedb2 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2b.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> + <title> + Testcase with only one of [html,body] being scrollable, + after html's "overflow" is reset dynamically. + </title> + <style> + html { + overflow: scroll; + } + body { + overflow: scroll; + } + </style> + <script> + function doTest() { + document.documentElement.style.overflow = "visible"; + document.documentElement.removeAttribute("class"); + } + window.addEventListener("MozReftestInvalidate", doTest); + </script> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-2c.html b/layout/reftests/scrolling/propagated-overflow-style-2c.html new file mode 100644 index 000000000..0ceb1f21a --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2c.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> + <title> + Testcase with only one of [html,body] being scrollable, + with their "overflow" styles being dynamically swapped. + </title> + <style> + html { + overflow: scroll; + } + </style> + <script> + function doTest() { + document.documentElement.style.overflow = "visible"; + document.body.style.overflow = "scroll"; + document.documentElement.removeAttribute("class"); + } + window.addEventListener("MozReftestInvalidate", doTest); + </script> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-2d.html b/layout/reftests/scrolling/propagated-overflow-style-2d.html new file mode 100644 index 000000000..3353a3374 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2d.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> + <title> + Testcase with only one of [html,body] being scrollable, + with their "overflow" styles being dynamically swapped. + </title> + <style> + body { + overflow: scroll; + } + </style> + <script> + function doTest() { + document.documentElement.style.overflow = "scroll"; + document.body.style.overflow = "visible"; + document.documentElement.removeAttribute("class"); + } + window.addEventListener("MozReftestInvalidate", doTest); + </script> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/propagated-overflow-style-2e.html b/layout/reftests/scrolling/propagated-overflow-style-2e.html new file mode 100644 index 000000000..f9105185b --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2e.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <title> + Testcase with the root viewport scrollable, via styles on body node. + </title> + <style> + body { + overflow: scroll; + } + </style> +</head> +<body> +</body> +</html> diff --git a/layout/reftests/scrolling/reftest.list b/layout/reftests/scrolling/reftest.list index db1b81db6..43997ced7 100644 --- a/layout/reftests/scrolling/reftest.list +++ b/layout/reftests/scrolling/reftest.list @@ -85,3 +85,13 @@ fuzzy-if(asyncPan&&!layersGPUAccelerated,102,2420) == frame-scrolling-attr-2.htm == fractional-scroll-area.html?top=0.4&outerBottom=99.6&innerBottom=200.4&scrollBefore=999 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200&scrollBefore=999 == fractional-scroll-area.html?top=0.4&outerBottom=100.4&innerBottom=200.4&scrollBefore=999 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200&scrollBefore=999 != fractional-scroll-area-invalidation.html about:blank + +# Tests for "overflow" styles that may be propagated to the viewport: +== propagated-overflow-style-1a.html propagated-overflow-style-1-ref.html +== propagated-overflow-style-1b.html propagated-overflow-style-1-ref.html +== propagated-overflow-style-1c.html propagated-overflow-style-1-ref.html +== propagated-overflow-style-2a.html propagated-overflow-style-2-ref.html +== propagated-overflow-style-2b.html propagated-overflow-style-2-ref.html +== propagated-overflow-style-2c.html propagated-overflow-style-2-ref.html +== propagated-overflow-style-2d.html propagated-overflow-style-2-ref.html +== propagated-overflow-style-2e.html propagated-overflow-style-2-ref.html diff --git a/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001-ref.html b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001-ref.html new file mode 100644 index 000000000..2473417b8 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001-ref.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>CSS Test Reference</title> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<style> +html, body { margin: 0; padding: 0; } + +.content { + margin-top: 100px; + width: 200px; + height: 200px; + background: blue; +} +</style> +<body> + <div class="content"></div> +</body> diff --git a/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001.html b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001.html new file mode 100644 index 000000000..b6e2fdff0 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001.html @@ -0,0 +1,47 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Test: Flexbox nested containers with align-items: center and flexible items</title> +<link rel="match" href="flexbox-align-items-center-nested-001-ref.html"> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#align-items-property"> +<style> +html, body { margin: 0; padding: 0; } +body { + height: 400px; + position: relative; +} + +.container-0 { + display: flex; + position: absolute; + height: 100%; + flex-direction: column; +} + +.container-1 { + flex: 1 0 auto; + display: flex; + align-items: center; +} + +.container-2 { + height: 100%; + display: flex; + align-items: center; +} + +.content { + width: 200px; + height: 200px; + background: blue; +} +</style> +<body> + <div class="container-0"> + <div class="container-1"> + <div class="container-2"> + <div class="content"></div> + </div> + </div> + </div> +</body> diff --git a/layout/reftests/w3c-css/submitted/flexbox/reftest.list b/layout/reftests/w3c-css/submitted/flexbox/reftest.list index a623a0b59..fd8bfccc9 100644 --- a/layout/reftests/w3c-css/submitted/flexbox/reftest.list +++ b/layout/reftests/w3c-css/submitted/flexbox/reftest.list @@ -39,6 +39,8 @@ fuzzy-if(Android,158,32) == flexbox-align-self-vert-rtl-001.xhtml flexbox-align == flexbox-align-self-vert-rtl-003.xhtml flexbox-align-self-vert-rtl-003-ref.xhtml == flexbox-align-self-vert-rtl-004.xhtml flexbox-align-self-vert-rtl-004-ref.xhtml +== flexbox-align-items-center-nested-001.html flexbox-align-items-center-nested-001-ref.html + # Tests for computing the baseline of a flex container == flexbox-baseline-align-self-baseline-horiz-001.html flexbox-baseline-align-self-baseline-horiz-001-ref.html == flexbox-baseline-align-self-baseline-vert-001.html flexbox-baseline-align-self-baseline-vert-001-ref.html diff --git a/layout/reftests/xul/css-flex-1-ref.html b/layout/reftests/xul/css-flex-1-ref.html new file mode 100644 index 000000000..a47eb8e9c --- /dev/null +++ b/layout/reftests/xul/css-flex-1-ref.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <style> + body { margin: 0 } + div.ref { + border: 1px solid black; + box-sizing: border-box; + background: green; + height: 50px; + width: 100px; + } + </style> +</head> +<body> + <div class="ref"></div> +</body> +</html> diff --git a/layout/reftests/xul/css-flex-1.xul b/layout/reftests/xul/css-flex-1.xul new file mode 100644 index 000000000..7955373dd --- /dev/null +++ b/layout/reftests/xul/css-flex-1.xul @@ -0,0 +1,153 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US"> +<head> +<link rel="icon" href="/mozilla-central/static/hgicon.png" type="image/png" /> +<meta name="robots" content="index, nofollow"/> +<link rel="stylesheet" href="/mozilla-central/static/style-gitweb.css" type="text/css" /> + +<style type="text/css"> +div.feed { + float: right; +} +a img { + border-width: 0px; +} +div.log_link { + width: 80px; + background-color: white; +} + +div.log_body { + padding-left: 96px; +} +</style> +<script type="text/javascript" src="/mozilla-central/static/mercurial.js"></script> + +<link rel="stylesheet" href="/mozilla-central/highlightcss" type="text/css" /> +<title>mozilla-central: layout/reftests/xul/css-flex-1.xul@67bbef772796</title> +<link rel="alternate" type="application/atom+xml" + href="/mozilla-central/atom-log" title="Atom feed for mozilla-central"/> +<link rel="alternate" type="application/rss+xml" + href="/mozilla-central/rss-log" title="RSS feed for mozilla-central"/> +</head> +<body> + +<div class="page_header"> +<div class="logo"> <a href="https://developer.mozilla.org/en/docs/Mercurial"> <img src="/mozilla-central/static/moz-logo-bw-rgb.svg" alt="mercurial" /> </a> </div> +<a href="/">Mercurial</a> > <a href="/mozilla-central">mozilla-central</a> / file revision / layout/reftests/xul/css-flex-1.xul@67bbef772796 +</div> + +<div class="page_nav"> +<div> +<a href="/mozilla-central/summary">summary</a> | +<a href="/mozilla-central/shortlog">shortlog</a> | +<a href="/mozilla-central/log">changelog</a> | +<a href="/mozilla-central/pushloghtml">pushlog</a> | +<a href="/mozilla-central/graph">graph</a> | +<a href="/mozilla-central/tags">tags</a> | +<a href="/mozilla-central/bookmarks">bookmarks</a> | +<a href="/mozilla-central/branches">branches</a> | +<a href="/mozilla-central/file/67bbef772796/layout/reftests/xul/">files</a> | +<a href="/mozilla-central/rev/67bbef772796">changeset</a> | +file | +<a href="/mozilla-central/file/tip/layout/reftests/xul/css-flex-1.xul">latest</a> | +<a href="/mozilla-central/log/67bbef772796/layout/reftests/xul/css-flex-1.xul">revisions</a> | +<a href="/mozilla-central/annotate/67bbef772796/layout/reftests/xul/css-flex-1.xul">annotate</a> | +<a href="/mozilla-central/diff/67bbef772796/layout/reftests/xul/css-flex-1.xul">diff</a> | +<a href="/mozilla-central/comparison/67bbef772796/layout/reftests/xul/css-flex-1.xul">comparison</a> | +<a href="/mozilla-central/raw-file/67bbef772796/layout/reftests/xul/css-flex-1.xul">raw</a> | +<a href="/mozilla-central/help">help</a> +</div> + +<div class="search"> +<form id="searchform" action="/mozilla-central/log"> + +<input name="rev" type="text" value="" size="40" /> +<div id="hint">Find changesets by keywords (author, files, the commit message), revision +number or hash, or <a href="/mozilla-central/help/revsets">revset expression</a>.</div> +</form> +</div> +</div> + +<div class="title">layout/reftests/xul/css-flex-1.xul</div> + +<div class="title_text"> +<table cellspacing="0"> +<tr> + <td>author</td> + <td>Daniel Holbert <dholbert@cs.stanford.edu></td> +</tr> +<tr> + <td></td> + <td class="date age">Wed, 08 Feb 2017 23:08:43 -0800</td> +</tr> + +<tr> + <td>changeset 341731</td> + <td style="font-family:monospace"><a class="list" href="/mozilla-central/rev/67bbef772796">67bbef772796</a></td> +</tr> + + +<tr> + <td>permissions</td> + <td style="font-family:monospace">-rw-r--r--</td> +</tr> +</table> +</div> + +<div class="page_path description"><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1338053">Bug 1338053</a>: Make nsFlexContainerFrame::MarkIntrinsicISizesDirty() also call its parent class's method. r=emilio + +MozReview-Commit-ID: 72oIlunLcVq</div> + +<div class="page_body"> +<pre class="sourcelines stripes" + data-logurl="/mozilla-central/log/67bbef772796/layout/reftests/xul/css-flex-1.xul" + data-selectabletag="SPAN" + data-ishead="1"> + +<a href="#l1"></a><span id="l1"><?xml version="1.0"?></span> +<a href="#l2"></a><span id="l2"><window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"</span> +<a href="#l3"></a><span id="l3"> class="reftest-wait"</span> +<a href="#l4"></a><span id="l4"> onload="tweak()"></span> +<a href="#l5"></a><span id="l5"> <style xmlns="http://www.w3.org/1999/xhtml"></span> +<a href="#l6"></a><span id="l6"> <![CDATA[</span> +<a href="#l7"></a><span id="l7"> panelview {</span> +<a href="#l8"></a><span id="l8"> border: 1px solid black;</span> +<a href="#l9"></a><span id="l9"> background: green;</span> +<a href="#l10"></a><span id="l10"> display: flex;</span> +<a href="#l11"></a><span id="l11"> height: 50px;</span> +<a href="#l12"></a><span id="l12"> }</span> +<a href="#l13"></a><span id="l13"> ]]></span> +<a href="#l14"></a><span id="l14"> </style></span> +<a href="#l15"></a><span id="l15"> <script></span> +<a href="#l16"></a><span id="l16"> <![CDATA[</span> +<a href="#l17"></a><span id="l17"> function tweak() {</span> +<a href="#l18"></a><span id="l18"> var tweakMe = document.getElementById("tweakMe");</span> +<a href="#l19"></a><span id="l19"> tweakMe.style.width = "100px";</span> +<a href="#l20"></a><span id="l20"> document.documentElement.className = "";</span> +<a href="#l21"></a><span id="l21"> }</span> +<a href="#l22"></a><span id="l22"> ]]></span> +<a href="#l23"></a><span id="l23"> </script></span> +<a href="#l24"></a><span id="l24"> <hbox></span> +<a href="#l25"></a><span id="l25"> <panelview id="tweakMe"></panelview></span> +<a href="#l26"></a><span id="l26"> </hbox></span> +<a href="#l27"></a><span id="l27"></window></span> +</pre> +</div> + +<script type="text/javascript" src="/mozilla-central/static/followlines.js"></script> + +<div class="page_footer"> +<div class="page_footer_text">mozilla-central</div> +<div class="page_footer_text" style="padding-left: 10px">Deployed from <a href="https://hg.mozilla.org/hgcustom/version-control-tools/rev/bd13917afa61">bd13917afa61</a> at 2018-04-20T21:06:08Z.</div> +<div class="rss_logo"> +<a href="/mozilla-central/rss-log">RSS</a> +<a href="/mozilla-central/atom-log">Atom</a> +</div> +<br /> + +</div> +</body> +</html> + diff --git a/layout/reftests/xul/reftest.list b/layout/reftests/xul/reftest.list index da09b7c81..35b9f9025 100644 --- a/layout/reftests/xul/reftest.list +++ b/layout/reftests/xul/reftest.list @@ -1,3 +1,5 @@ +== css-flex-1.xul css-flex-1-ref.html + == menuitem-key.xul menuitem-key-ref.xul # these random-if(Android) are due to differences between Android Native & Xul, see bug 732569 random-if(Android) == menulist-shrinkwrap-1.xul menulist-shrinkwrap-1-ref.xul diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index 59626fba4..550a7d71a 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -343,17 +343,7 @@ FontFaceSet::Load(JSContext* aCx, } } - nsIGlobalObject* globalObject = GetParentObject(); - if (!globalObject) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - JS::Rooted<JSObject*> jsGlobal(aCx, globalObject->GetGlobalJSObject()); - GlobalObject global(aCx, jsGlobal); - - RefPtr<Promise> result = Promise::All(global, promises, aRv); - return result.forget(); + return Promise::All(aCx, promises, aRv); } bool diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 2f12d6201..553239e0e 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1629,23 +1629,11 @@ nsStylePosition::CalcDifference(const nsStylePosition& aNewData, if (aOldStyleVisibility) { bool isVertical = WritingMode(aOldStyleVisibility).IsVertical(); if (isVertical ? widthChanged : heightChanged) { - // Block-size changes can affect descendant intrinsic sizes due to - // replaced elements with percentage bsizes in descendants which - // also have percentage bsizes. This is handled via - // nsChangeHint_UpdateComputedBSize which clears intrinsic sizes - // for frames that have such replaced elements. - hint |= nsChangeHint_NeedReflow | - nsChangeHint_UpdateComputedBSize | - nsChangeHint_ReflowChangesSizeOrPosition; + hint |= nsChangeHint_ReflowHintsForBSizeChange; } if (isVertical ? heightChanged : widthChanged) { - // None of our inline-size differences can affect descendant - // intrinsic sizes and none of them need to force children to - // reflow. - hint |= nsChangeHint_AllReflowHints & - ~(nsChangeHint_ClearDescendantIntrinsics | - nsChangeHint_NeedDirtyReflow); + hint |= nsChangeHint_ReflowHintsForISizeChange; } } else { if (widthChanged || heightChanged) { @@ -3258,8 +3246,6 @@ nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const || mDisplay != aNewData.mDisplay || mContain != aNewData.mContain || (mFloat == StyleFloat::None) != (aNewData.mFloat == StyleFloat::None) - || mOverflowX != aNewData.mOverflowX - || mOverflowY != aNewData.mOverflowY || mScrollBehavior != aNewData.mScrollBehavior || mScrollSnapTypeX != aNewData.mScrollSnapTypeX || mScrollSnapTypeY != aNewData.mScrollSnapTypeY @@ -3271,6 +3257,11 @@ nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const hint |= nsChangeHint_ReconstructFrame; } + if (mOverflowX != aNewData.mOverflowX + || mOverflowY != aNewData.mOverflowY) { + hint |= nsChangeHint_CSSOverflowChange; + } + /* Note: When mScrollBehavior, mScrollSnapTypeX, mScrollSnapTypeY, * mScrollSnapPointsX, mScrollSnapPointsY, or mScrollSnapDestination are * changed, nsChangeHint_NeutralChange is not sufficient to enter diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index ca5d03056..05a6be91e 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1197,11 +1197,14 @@ private: nsCSSShadowItem mArray[1]; // This MUST be the last item }; -// Border widths are rounded to the nearest-below integer number of pixels, -// but values between zero and one device pixels are always rounded up to -// one device pixel. +// Border widths are rounded to the nearest integer number of pixels, but values +// between zero and one device pixels are always rounded up to one device pixel. #define NS_ROUND_BORDER_TO_PIXELS(l,tpp) \ - ((l) == 0) ? 0 : std::max((tpp), (l) / (tpp) * (tpp)) + ((l) == 0) ? 0 : std::max((tpp), ((l) + ((tpp) / 2)) / (tpp) * (tpp)) +// Caret widths are rounded to the nearest-below integer number of pixels, but values +// between zero and one device pixels are always rounded up to one device pixel. +#define NS_ROUND_CARET_TO_PIXELS(l,tpp) \ + ((l) == 0) ? 0 : std::max((tpp), (l) / (tpp) * (tpp)) // Outline offset is rounded to the nearest integer number of pixels, but values // between zero and one device pixels are always rounded up to one device pixel. // Note that the offset can be negative. diff --git a/layout/style/test/mochitest.ini b/layout/style/test/mochitest.ini index 406c6f901..8182691ca 100644 --- a/layout/style/test/mochitest.ini +++ b/layout/style/test/mochitest.ini @@ -295,6 +295,7 @@ skip-if = toolkit == 'android' [test_variables.html] support-files = support/external-variable-url.css [test_video_object_fit.html] +[test_viewport_scrollbar_causing_reflow.html] [test_viewport_units.html] [test_visited_image_loading.html] skip-if = toolkit == 'android' #TIMED_OUT diff --git a/layout/style/test/test_dynamic_change_causing_reflow.html b/layout/style/test/test_dynamic_change_causing_reflow.html index a941191f6..a5bb3045c 100644 --- a/layout/style/test/test_dynamic_change_causing_reflow.html +++ b/layout/style/test/test_dynamic_change_causing_reflow.html @@ -95,6 +95,90 @@ const gTestcases = [ expectReflow: true, }, + // * Changing 'overflow' on <body> should cause reflow, + // but not frame reconstruction + { + elem: document.body, + /* beforeStyle: implicitly 'overflow:visible' */ + afterStyle: "overflow: hidden", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + /* beforeStyle: implicitly 'overflow:visible' */ + afterStyle: "overflow: scroll", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: hidden", + afterStyle: "overflow: auto", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: hidden", + afterStyle: "overflow: scroll", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: hidden", + afterStyle: "overflow: visible", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: auto", + afterStyle: "overflow: hidden", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: visible", + afterStyle: "overflow: hidden", + expectConstruction: false, + expectReflow: true, + }, + + // * Changing 'overflow' on <html> should cause reflow, + // but not frame reconstruction + { + elem: document.documentElement, + /* beforeStyle: implicitly 'overflow:visible' */ + afterStyle: "overflow: auto", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.documentElement, + beforeStyle: "overflow: visible", + afterStyle: "overflow: auto", + expectConstruction: false, + expectReflow: true, + }, + + // * Setting 'overflow' on arbitrary node should cause reflow as well as + // frame reconstruction + { + /* beforeStyle: implicitly 'overflow:visible' */ + afterStyle: "overflow: auto", + expectConstruction: true, + expectReflow: true, + }, + { + beforeStyle: "overflow: auto", + afterStyle: "overflow: visible", + expectConstruction: true, + expectReflow: true, + }, + // * Changing 'display' should cause frame construction and reflow. { beforeStyle: "display: inline", @@ -135,23 +219,34 @@ function runOneTest(aTestcase) return; } + // Figure out which element we'll be tweaking (defaulting to gElem) + let elem = aTestcase.elem ? + aTestcase.elem : gElem; + + // Verify that 'style' attribute is unset (avoid causing ourselves trouble): + if (elem.hasAttribute("style")) { + ok(false, + "test element has 'style' attribute already set! We're going to stomp " + + "on whatever's there when we clean up..."); + } + // Set the "before" style, and compose the first part of the message // to be used in our "is"/"isnot" invocations: let msgPrefix = "Changing style "; if (aTestcase.beforeStyle) { - gElem.setAttribute("style", aTestcase.beforeStyle); + elem.setAttribute("style", aTestcase.beforeStyle); msgPrefix += "from '" + aTestcase.beforeStyle + "' "; } - msgPrefix += "to '" + aTestcase.afterStyle + "' "; + msgPrefix += "on " + elem.nodeName + " "; // Establish initial counts: - let unusedVal = gElem.offsetHeight; // flush layout + let unusedVal = elem.offsetHeight; // flush layout let origFramesConstructed = gUtils.framesConstructed; let origFramesReflowed = gUtils.framesReflowed; // Make the change and flush: - gElem.setAttribute("style", aTestcase.afterStyle); - unusedVal = gElem.offsetHeight; // flush layout + elem.setAttribute("style", aTestcase.afterStyle); + unusedVal = elem.offsetHeight; // flush layout // Make our is/isnot assertions about whether things should have changed: checkFinalCount(gUtils.framesConstructed, origFramesConstructed, @@ -162,7 +257,7 @@ function runOneTest(aTestcase) "reflow"); // Clean up! - gElem.removeAttribute("style"); + elem.removeAttribute("style"); } gTestcases.forEach(runOneTest); diff --git a/layout/style/test/test_viewport_scrollbar_causing_reflow.html b/layout/style/test/test_viewport_scrollbar_causing_reflow.html new file mode 100644 index 000000000..dfd7ec450 --- /dev/null +++ b/layout/style/test/test_viewport_scrollbar_causing_reflow.html @@ -0,0 +1,125 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1367568 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1367568</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug 1367568</a> +<div id="content"> + <!-- Some fixed-width divs that we shouldn't have to reflow when the viewport + changes: --> + <div style="width: 100px"> + fixed-width + <div>(child)</div> + </div> + <div style="position: absolute; width: 150px"> + abs-fixed-width + <div>(child)</div> + </div> +</div> +<pre id="test"> +<script type="application/javascript"> +"use strict"; + +/** Test for Bug 1367568 **/ + +/** + * This test verifies that "overflow" changes on the <body> don't cause + * an unnecessarily large amount of reflow. + */ + +// Vars used in setStyleAndMeasure that we really only have to look up once: +const gUtils = SpecialPowers.getDOMWindowUtils(window); + +function setStyleAndMeasure(initialStyle, finalStyle) { + is(document.body.style.length, 0, + "Bug in test - body should start with empty style"); + let unusedVal = document.body.offsetHeight; // flush layout + let constructCount = gUtils.framesConstructed; + + document.body.style = initialStyle; + unusedVal = document.body.offsetHeight; // flush layout + let reflowCountBeforeTweak = gUtils.framesReflowed; + + document.body.style = finalStyle; + unusedVal = document.body.offsetHeight; // flush layout + let reflowCountAfterTweak = gUtils.framesReflowed; + + // Clean up: + document.body.style = ""; + + is(gUtils.framesConstructed, constructCount, + "Style tweak shouldn't have triggered frame construction"); + + // ...and return the delta: + return reflowCountAfterTweak - reflowCountBeforeTweak; +} + +function main() { + // First, we sanity-check that our measurement make sense -- if we leave + // styles unchanged, we should measure no frames being reflowed: + let count = setStyleAndMeasure("width: 50px; height: 80px", + "width: 50px; height: 80px"); + is(count, 0, + "Shouldn't reflow anything when we leave 'width' & 'height' unchanged"); + + // Now: see how many frames are reflowed when the "width" & "height" change. + // We'll use this as the reference when measuring reflow counts for various + // changes to "overflow" below. + count = setStyleAndMeasure("width: 50px; height: 80px", + "width: 90px; height: 60px"); + ok(count > 0, + "Should reflow some frames when 'width' & 'height' change"); + + // Expected maximum number of frames reflowed for "overflow" changes + // (+2 is to allow for reflowing scrollbars themselves): + const expectedMax = count + 2; + + // Shared ending for messages in all ok() checks below: + const messageSuffix = + " shouldn't be greater than count for tweaking width/height on body (" + + expectedMax + ")"; + + // OK, here is where the relevant tests actually begin!! + // See how many frames we reflow for various tweaks to "overflow" on + // the body -- we expect the count to be no larger than |expectedMax|. + count = setStyleAndMeasure("", "overflow: scroll"); + ok(count <= expectedMax, + "Reflow count when setting 'overflow: scroll' on body (" + count + ")" + + messageSuffix); + + count = setStyleAndMeasure("", "overflow: hidden"); + ok(count <= expectedMax, + "Reflow count when setting 'overflow: hidden' on body (" + count + ")" + + messageSuffix); + + // Test removal of "overflow: scroll": + count = setStyleAndMeasure("overflow: scroll", ""); + ok(count <= expectedMax, + "Reflow count when removing 'overflow: scroll' from body (" + count + ")" + + messageSuffix); + + count = setStyleAndMeasure("overflow: hidden", ""); + ok(count <= expectedMax, + "Reflow count when removing 'overflow: hidden' from body (" + count + ")" + + messageSuffix); + + // Test change between two non-'visible' overflow values: + count = setStyleAndMeasure("overflow: scroll", "overflow: hidden"); + ok(count <= expectedMax, + "Reflow count when changing 'overflow' on body (" + count + ")" + + messageSuffix); +} + +main(); + +</script> +</pre> +</body> +</html> diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp index e68126068..e5a03333f 100644 --- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -5111,8 +5111,8 @@ SVGTextFrame::DoGlyphPositioning() float actualTextLength = static_cast<float>(presContext->AppUnitsToGfxUnits(frameLength) * factor); - RefPtr<SVGAnimatedEnumeration> lengthAdjustEnum = element->LengthAdjust(); - uint16_t lengthAdjust = lengthAdjustEnum->AnimVal(); + uint16_t lengthAdjust = + element->EnumAttributes()[SVGTextContentElement::LENGTHADJUST].GetAnimValue(); switch (lengthAdjust) { case SVG_LENGTHADJUST_SPACINGANDGLYPHS: // Scale the glyphs and their positions. diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index ff74d5baf..344ebf645 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -1127,8 +1127,7 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags) if (clipPathFrame && isOK) { SVGClipPathElement *clipContent = static_cast<SVGClipPathElement*>(clipPathFrame->GetContent()); - RefPtr<SVGAnimatedEnumeration> units = clipContent->ClipPathUnits(); - if (units->AnimVal() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (clipContent->IsUnitsObjectBoundingBox()) { matrix.Translate(gfxPoint(x, y)); matrix.Scale(width, height); } else if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) { diff --git a/media/libtremor/lib/tremor_codebook.c b/media/libtremor/lib/tremor_codebook.c index f8b798384..1e1ae8a91 100644 --- a/media/libtremor/lib/tremor_codebook.c +++ b/media/libtremor/lib/tremor_codebook.c @@ -258,7 +258,7 @@ long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a, t[i] = book->valuelist+entry[i]*book->dim; } for(i=0,o=0;i<book->dim;i++,o+=step) - for (j=0;j<step;j++) + for (j=0;o+j<n && j<step;j++) a[o+j]+=t[j][i]>>shift; }else{ for (i = 0; i < step; i++) { @@ -267,7 +267,7 @@ long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a, t[i] = book->valuelist+entry[i]*book->dim; } for(i=0,o=0;i<book->dim;i++,o+=step) - for (j=0;j<step;j++) + for (j=0;o+j<n && j<step;j++) a[o+j]+=t[j][i]<<-shift; } } @@ -287,7 +287,7 @@ long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a, entry = decode_packed_entry_number(book,b); if(entry==-1)return(-1); t = book->valuelist+entry*book->dim; - for (j=0;j<book->dim;) + for (j=0;i<n && j<book->dim;) a[i++]+=t[j++]>>shift; } }else{ @@ -295,7 +295,7 @@ long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a, entry = decode_packed_entry_number(book,b); if(entry==-1)return(-1); t = book->valuelist+entry*book->dim; - for (j=0;j<book->dim;) + for (j=0;i<n && j<book->dim;) a[i++]+=t[j++]<<-shift; } } @@ -352,15 +352,15 @@ long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,\ long i,j,entry; int chptr=0; int shift=point-book->binarypoint; - + int m=offset+n; if(shift>=0){ - for(i=offset;i<offset+n;){ + for(i=offset;i<m;){ entry = decode_packed_entry_number(book,b); if(entry==-1)return(-1); { const ogg_int32_t *t = book->valuelist+entry*book->dim; - for (j=0;j<book->dim;j++){ + for (j=0;i<m && j<book->dim;j++){ a[chptr++][i]+=t[j]>>shift; if(chptr==ch){ chptr=0; @@ -371,12 +371,12 @@ long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,\ } }else{ - for(i=offset;i<offset+n;){ + for(i=offset;i<m;){ entry = decode_packed_entry_number(book,b); if(entry==-1)return(-1); { const ogg_int32_t *t = book->valuelist+entry*book->dim; - for (j=0;j<book->dim;j++){ + for (j=0;i<m && j<book->dim;j++){ a[chptr++][i]+=t[j]<<-shift; if(chptr==ch){ chptr=0; diff --git a/media/libvorbis/lib/vorbis_codebook.c b/media/libvorbis/lib/vorbis_codebook.c index 72f8a17a3..49b7b09b2 100644 --- a/media/libvorbis/lib/vorbis_codebook.c +++ b/media/libvorbis/lib/vorbis_codebook.c @@ -387,7 +387,7 @@ long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){ t[i] = book->valuelist+entry[i]*book->dim; } for(i=0,o=0;i<book->dim;i++,o+=step) - for (j=0;j<step;j++) + for (j=0;o+j<n && j<step;j++) a[o+j]+=t[j][i]; } return(0); @@ -399,41 +399,12 @@ long vorbis_book_decodev_add(codebook *book,float *a,oggpack_buffer *b,int n){ int i,j,entry; float *t; - if(book->dim>8){ - for(i=0;i<n;){ - entry = decode_packed_entry_number(book,b); - if(entry==-1)return(-1); - t = book->valuelist+entry*book->dim; - for (j=0;j<book->dim;) - a[i++]+=t[j++]; - } - }else{ - for(i=0;i<n;){ - entry = decode_packed_entry_number(book,b); - if(entry==-1)return(-1); - t = book->valuelist+entry*book->dim; - j=0; - switch((int)book->dim){ - case 8: - a[i++]+=t[j++]; - case 7: - a[i++]+=t[j++]; - case 6: - a[i++]+=t[j++]; - case 5: - a[i++]+=t[j++]; - case 4: - a[i++]+=t[j++]; - case 3: - a[i++]+=t[j++]; - case 2: - a[i++]+=t[j++]; - case 1: - a[i++]+=t[j++]; - case 0: - break; - } - } + for(i=0;i<n;){ + entry = decode_packed_entry_number(book,b); + if(entry==-1)return(-1); + t = book->valuelist+entry*book->dim; + for(j=0;i<n && j<book->dim;) + a[i++]+=t[j++]; } } return(0); @@ -471,12 +442,13 @@ long vorbis_book_decodevv_add(codebook *book,float **a,long offset,int ch, long i,j,entry; int chptr=0; if(book->used_entries>0){ - for(i=offset/ch;i<(offset+n)/ch;){ + int m=(offset+n)/ch; + for(i=offset/ch;i<m;){ entry = decode_packed_entry_number(book,b); if(entry==-1)return(-1); { const float *t = book->valuelist+entry*book->dim; - for (j=0;j<book->dim;j++){ + for (j=0;i<m && j<book->dim;j++){ a[chptr++][i]+=t[j]; if(chptr==ch){ chptr=0; diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 9a28bd716..c0eba6596 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -215,8 +215,8 @@ pref("extensions.hideUpdateButton", false); pref("extensions.strictCompatibility", false); pref("extensions.minCompatibleAppVersion", "11.0"); -pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); -pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); +pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=52.9&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); +pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=52.9&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); pref("extensions.hotfix.id", "firefox-android-hotfix@mozilla.org"); pref("extensions.hotfix.cert.checkAttributes", true); diff --git a/modules/libjar/nsJARURI.cpp b/modules/libjar/nsJARURI.cpp index e46e51467..d1e4b5a59 100644 --- a/modules/libjar/nsJARURI.cpp +++ b/modules/libjar/nsJARURI.cpp @@ -41,7 +41,6 @@ NS_IMPL_RELEASE(nsJARURI) NS_INTERFACE_MAP_BEGIN(nsJARURI) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJARURI) NS_INTERFACE_MAP_ENTRY(nsIURI) - NS_INTERFACE_MAP_ENTRY(nsIURIWithQuery) NS_INTERFACE_MAP_ENTRY(nsIURL) NS_INTERFACE_MAP_ENTRY(nsIJARURI) NS_INTERFACE_MAP_ENTRY(nsISerializable) diff --git a/modules/libjar/nsJARURI.h b/modules/libjar/nsJARURI.h index 31271e4ac..d2608a5c6 100644 --- a/modules/libjar/nsJARURI.h +++ b/modules/libjar/nsJARURI.h @@ -41,7 +41,6 @@ class nsJARURI final : public nsIJARURI, public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIURI - NS_DECL_NSIURIWITHQUERY NS_DECL_NSIURL NS_DECL_NSIJARURI NS_DECL_NSISERIALIZABLE diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index e3e23550a..903665ff8 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -118,6 +118,14 @@ pref("browser.cache.compression_level", 0); // Don't show "Open with" option on download dialog if true. pref("browser.download.forbid_open_with", false); +#ifdef XP_WIN +// Save internet zone information on downloaded files: +// 0 => Never +// 1 => Always +// 2 => Use system setting +pref("browser.download.saveZoneInformation", 2); +#endif + // Whether or not testing features are enabled. pref("dom.quotaManager.testing", false); @@ -192,11 +200,7 @@ pref("dom.enable_performance_observer", false); #endif // Enable requestIdleCallback API -#ifdef NIGHTLY_BUILD pref("dom.requestIdleCallback.enabled", true); -#else -pref("dom.requestIdleCallback.enabled", false); -#endif // Whether the Gamepad API is enabled pref("dom.gamepad.enabled", true); @@ -777,16 +781,17 @@ pref("gfx.font_rendering.opentype_svg.enabled", true); // comma separated list of backends to use in order of preference // e.g., pref("gfx.canvas.azure.backends", "direct2d,skia,cairo"); pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo"); -pref("gfx.content.azure.backends", "direct2d1.1,skia,cairo"); +pref("gfx.content.azure.backends", "direct2d1.1,cairo"); #else #ifdef XP_MACOSX -pref("gfx.content.azure.backends", "skia"); -pref("gfx.canvas.azure.backends", "skia"); +pref("gfx.content.azure.backends", "cg"); +pref("gfx.canvas.azure.backends", "skia,cg"); // Accelerated cg canvas where available (10.7+) pref("gfx.canvas.azure.accelerated", true); #else -pref("gfx.canvas.azure.backends", "skia"); -pref("gfx.content.azure.backends", "skia"); +// Linux etc. +pref("gfx.canvas.azure.backends", "skia,cairo"); +pref("gfx.content.azure.backends", "cairo"); #endif #endif @@ -1156,7 +1161,7 @@ pref("dom.require_user_interaction_for_beforeunload", true); pref("dom.disable_open_during_load", false); pref("dom.popup_maximum", 20); -pref("dom.popup_allowed_events", "change click dblclick mouseup notificationclick reset submit touchend"); +pref("dom.popup_allowed_events", "change click dblclick mouseup pointerup notificationclick reset submit touchend"); pref("dom.disable_open_click_delay", 1000); pref("dom.storage.enabled", true); @@ -4748,23 +4753,16 @@ pref("alerts.showFavicons", false); // DOM full-screen API. pref("full-screen-api.enabled", false); -#ifdef RELEASE_OR_BETA -pref("full-screen-api.unprefix.enabled", false); -#else pref("full-screen-api.unprefix.enabled", true); -#endif pref("full-screen-api.allow-trusted-requests-only", true); pref("full-screen-api.pointer-lock.enabled", true); + // transition duration of fade-to-black and fade-from-black, unit: ms -#ifndef MOZ_WIDGET_GTK -pref("full-screen-api.transition-duration.enter", "200 200"); -pref("full-screen-api.transition-duration.leave", "200 200"); -#else pref("full-screen-api.transition-duration.enter", "0 0"); pref("full-screen-api.transition-duration.leave", "0 0"); -#endif + // timeout for black screen in fullscreen transition, unit: ms -pref("full-screen-api.transition.timeout", 1000); +pref("full-screen-api.transition.timeout", 500); // time for the warning box stays on the screen before sliding out, unit: ms pref("full-screen-api.warning.timeout", 3000); // delay for the warning box to show when pointer stays on the top, unit: ms @@ -5559,6 +5557,12 @@ pref("security.mixed_content.use_hsts", true); // Approximately 1 week default cache for HSTS priming failures pref ("security.mixed_content.hsts_priming_cache_timeout", 10080); +// TODO: Bug 1380959: Block toplevel data: URI navigations +// If true, all toplevel data: URI navigations will be blocked. +// Please note that manually entering a data: URI in the +// URL-Bar will not be blocked when flipping this pref. +pref("security.data_uri.block_toplevel_data_uri_navigations", false); + // Disable Storage api in release builds. #ifdef NIGHTLY_BUILD pref("dom.storageManager.enabled", true); diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 42fdea4a1..ede825b8f 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -7,6 +7,7 @@ #include "mozilla/LoadInfo.h" #include "mozilla/Assertions.h" +#include "mozilla/dom/TabChild.h" #include "mozilla/dom/ToJSValue.h" #include "mozIThirdPartyUtil.h" #include "nsFrameLoader.h" @@ -47,12 +48,14 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, aTriggeringPrincipal : mLoadingPrincipal.get()) , mPrincipalToInherit(nullptr) , mLoadingContext(do_GetWeakReference(aLoadingContext)) + , mContextForTopLevelLoad(nullptr) , mSecurityFlags(aSecurityFlags) , mInternalContentPolicyType(aContentPolicyType) , mTainting(LoadTainting::Basic) , mUpgradeInsecureRequests(false) , mVerifySignedContent(false) , mEnforceSRI(false) + , mForceAllowDataURI(false) , mForceInheritPrincipalDropped(false) , mInnerWindowID(0) , mOuterWindowID(0) @@ -63,6 +66,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mIsThirdPartyContext(false) , mForcePreflight(false) , mIsPreflight(false) + , mLoadTriggeredFromExternal(false) , mForceHSTSPriming(false) , mMixedContentWouldBlock(false) { @@ -215,16 +219,19 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, */ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow, nsIPrincipal* aTriggeringPrincipal, + nsISupports* aContextForTopLevelLoad, nsSecurityFlags aSecurityFlags) : mLoadingPrincipal(nullptr) , mTriggeringPrincipal(aTriggeringPrincipal) , mPrincipalToInherit(nullptr) + , mContextForTopLevelLoad(do_GetWeakReference(aContextForTopLevelLoad)) , mSecurityFlags(aSecurityFlags) , mInternalContentPolicyType(nsIContentPolicy::TYPE_DOCUMENT) , mTainting(LoadTainting::Basic) , mUpgradeInsecureRequests(false) , mVerifySignedContent(false) , mEnforceSRI(false) + , mForceAllowDataURI(false) , mForceInheritPrincipalDropped(false) , mInnerWindowID(0) , mOuterWindowID(0) @@ -235,6 +242,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow, , mIsThirdPartyContext(false) // NB: TYPE_DOCUMENT implies not third-party. , mForcePreflight(false) , mIsPreflight(false) + , mLoadTriggeredFromExternal(false) , mForceHSTSPriming(false) , mMixedContentWouldBlock(false) { @@ -276,12 +284,14 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) , mTriggeringPrincipal(rhs.mTriggeringPrincipal) , mPrincipalToInherit(rhs.mPrincipalToInherit) , mLoadingContext(rhs.mLoadingContext) + , mContextForTopLevelLoad(rhs.mContextForTopLevelLoad) , mSecurityFlags(rhs.mSecurityFlags) , mInternalContentPolicyType(rhs.mInternalContentPolicyType) , mTainting(rhs.mTainting) , mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests) , mVerifySignedContent(rhs.mVerifySignedContent) , mEnforceSRI(rhs.mEnforceSRI) + , mForceAllowDataURI(rhs.mForceAllowDataURI) , mForceInheritPrincipalDropped(rhs.mForceInheritPrincipalDropped) , mInnerWindowID(rhs.mInnerWindowID) , mOuterWindowID(rhs.mOuterWindowID) @@ -297,6 +307,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) , mCorsUnsafeHeaders(rhs.mCorsUnsafeHeaders) , mForcePreflight(rhs.mForcePreflight) , mIsPreflight(rhs.mIsPreflight) + , mLoadTriggeredFromExternal(rhs.mLoadTriggeredFromExternal) , mForceHSTSPriming(rhs.mForceHSTSPriming) , mMixedContentWouldBlock(rhs.mMixedContentWouldBlock) { @@ -311,6 +322,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, bool aUpgradeInsecureRequests, bool aVerifySignedContent, bool aEnforceSRI, + bool aForceAllowDataURI, bool aForceInheritPrincipalDropped, uint64_t aInnerWindowID, uint64_t aOuterWindowID, @@ -325,6 +337,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, const nsTArray<nsCString>& aCorsUnsafeHeaders, bool aForcePreflight, bool aIsPreflight, + bool aLoadTriggeredFromExternal, bool aForceHSTSPriming, bool aMixedContentWouldBlock) : mLoadingPrincipal(aLoadingPrincipal) @@ -336,6 +349,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mUpgradeInsecureRequests(aUpgradeInsecureRequests) , mVerifySignedContent(aVerifySignedContent) , mEnforceSRI(aEnforceSRI) + , mForceAllowDataURI(aForceAllowDataURI) , mForceInheritPrincipalDropped(aForceInheritPrincipalDropped) , mInnerWindowID(aInnerWindowID) , mOuterWindowID(aOuterWindowID) @@ -348,6 +362,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mCorsUnsafeHeaders(aCorsUnsafeHeaders) , mForcePreflight(aForcePreflight) , mIsPreflight(aIsPreflight) + , mLoadTriggeredFromExternal(aLoadTriggeredFromExternal) , mForceHSTSPriming (aForceHSTSPriming) , mMixedContentWouldBlock(aMixedContentWouldBlock) { @@ -477,6 +492,17 @@ LoadInfo::LoadingNode() return node; } +nsISupports* +LoadInfo::ContextForTopLevelLoad() +{ + // Most likely you want to query LoadingNode() instead of + // ContextForTopLevelLoad() if this assertion fires. + MOZ_ASSERT(mInternalContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT, + "should only query this context for top level document loads"); + nsCOMPtr<nsISupports> context = do_QueryReferent(mContextForTopLevelLoad); + return context; +} + NS_IMETHODIMP LoadInfo::GetSecurityFlags(nsSecurityFlags* aResult) { @@ -648,6 +674,23 @@ LoadInfo::GetEnforceSRI(bool* aResult) } NS_IMETHODIMP +LoadInfo::SetForceAllowDataURI(bool aForceAllowDataURI) +{ + MOZ_ASSERT(!mForceAllowDataURI || + mInternalContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT, + "can only allow data URI navigation for TYPE_DOCUMENT"); + mForceAllowDataURI = aForceAllowDataURI; + return NS_OK; +} + +NS_IMETHODIMP +LoadInfo::GetForceAllowDataURI(bool* aForceAllowDataURI) +{ + *aForceAllowDataURI = mForceAllowDataURI; + return NS_OK; +} + +NS_IMETHODIMP LoadInfo::GetForceInheritPrincipalDropped(bool* aResult) { *aResult = mForceInheritPrincipalDropped; @@ -873,6 +916,23 @@ LoadInfo::GetIsPreflight(bool* aIsPreflight) } NS_IMETHODIMP +LoadInfo::SetLoadTriggeredFromExternal(bool aLoadTriggeredFromExternal) +{ + MOZ_ASSERT(!aLoadTriggeredFromExternal || + mInternalContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT, + "can only set load triggered from external for TYPE_DOCUMENT"); + mLoadTriggeredFromExternal = aLoadTriggeredFromExternal; + return NS_OK; +} + +NS_IMETHODIMP +LoadInfo::GetLoadTriggeredFromExternal(bool* aLoadTriggeredFromExternal) +{ + *aLoadTriggeredFromExternal = mLoadTriggeredFromExternal; + return NS_OK; +} + +NS_IMETHODIMP LoadInfo::GetForceHSTSPriming(bool* aForceHSTSPriming) { *aForceHSTSPriming = mForceHSTSPriming; diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index 3e1b92ff4..0ae6061b3 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -59,10 +59,12 @@ public: nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType); - // Constructor used for TYPE_DOCUMENT loads which have no reasonable - // loadingNode or loadingPrincipal + // Constructor used for TYPE_DOCUMENT loads which have a different + // loadingContext than other loads. This ContextForTopLevelLoad is + // only used for content policy checks. LoadInfo(nsPIDOMWindowOuter* aOuterWindow, nsIPrincipal* aTriggeringPrincipal, + nsISupports* aContextForTopLevelLoad, nsSecurityFlags aSecurityFlags); // create an exact copy of the loadinfo @@ -94,6 +96,7 @@ private: bool aUpgradeInsecureRequests, bool aVerifySignedContent, bool aEnforceSRI, + bool aForceAllowDataURI, bool aForceInheritPrincipalDropped, uint64_t aInnerWindowID, uint64_t aOuterWindowID, @@ -108,6 +111,7 @@ private: const nsTArray<nsCString>& aUnsafeHeaders, bool aForcePreflight, bool aIsPreflight, + bool aLoadTriggeredFromExternal, bool aForceHSTSPriming, bool aMixedContentWouldBlock); LoadInfo(const LoadInfo& rhs); @@ -132,12 +136,14 @@ private: nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; nsCOMPtr<nsIPrincipal> mPrincipalToInherit; nsWeakPtr mLoadingContext; + nsWeakPtr mContextForTopLevelLoad; nsSecurityFlags mSecurityFlags; nsContentPolicyType mInternalContentPolicyType; LoadTainting mTainting; bool mUpgradeInsecureRequests; bool mVerifySignedContent; bool mEnforceSRI; + bool mForceAllowDataURI; bool mForceInheritPrincipalDropped; uint64_t mInnerWindowID; uint64_t mOuterWindowID; @@ -152,6 +158,7 @@ private: nsTArray<nsCString> mCorsUnsafeHeaders; bool mForcePreflight; bool mIsPreflight; + bool mLoadTriggeredFromExternal; bool mForceHSTSPriming : 1; bool mMixedContentWouldBlock : 1; diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build index 3b731db10..5de1eea81 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -132,7 +132,6 @@ XPIDL_SOURCES += [ 'nsIURIClassifier.idl', 'nsIURIWithBlobImpl.idl', 'nsIURIWithPrincipal.idl', - 'nsIURIWithQuery.idl', 'nsIURL.idl', 'nsIURLParser.idl', 'nsPILoadGroupInternal.idl', diff --git a/netwerk/base/nsBufferedStreams.h b/netwerk/base/nsBufferedStreams.h index 93a770beb..fee55695a 100644 --- a/netwerk/base/nsBufferedStreams.h +++ b/netwerk/base/nsBufferedStreams.h @@ -88,10 +88,10 @@ protected: //////////////////////////////////////////////////////////////////////////////// -class nsBufferedOutputStream final : public nsBufferedStream, - public nsISafeOutputStream, - public nsIBufferedOutputStream, - public nsIStreamBufferAccess +class nsBufferedOutputStream : public nsBufferedStream, + public nsISafeOutputStream, + public nsIBufferedOutputStream, + public nsIStreamBufferAccess { public: NS_DECL_ISUPPORTS_INHERITED diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index 78433c8b8..4ec29b972 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -324,6 +324,16 @@ interface nsILoadInfo : nsISupports nsINode binaryLoadingNode(); /** + * A C++ friendly version of the loadingContext for toplevel loads. + * Most likely you want to query the ownerDocument or LoadingNode + * and not this context only available for TYPE_DOCUMENT loads. + * Please note that except for loads of TYPE_DOCUMENT, this + * ContextForTopLevelLoad will always return null. + */ + [noscript, notxpcom, nostdcall, binaryname(ContextForTopLevelLoad)] + nsISupports binaryContextForTopLevelLoad(); + + /** * The securityFlags of that channel. */ readonly attribute nsSecurityFlags securityFlags; @@ -470,6 +480,11 @@ interface nsILoadInfo : nsISupports [infallible] attribute boolean enforceSRI; /** + * If true, toplevel data: URI navigation is allowed + */ + [infallible] attribute boolean forceAllowDataURI; + + /** * The SEC_FORCE_INHERIT_PRINCIPAL flag may be dropped when a load info * object is created. Specifically, it will be dropped if the SEC_SANDBOXED * flag is also present. This flag is set if SEC_FORCE_INHERIT_PRINCIPAL was @@ -575,6 +590,13 @@ interface nsILoadInfo : nsISupports [infallible] attribute boolean initialSecurityCheckDone; /** + * Returns true if the load was triggered from an external application + * (e.g. Thunderbird). Please note that this flag will only ever be true + * if the load is of TYPE_DOCUMENT. + */ + [infallible] attribute boolean loadTriggeredFromExternal; + + /** * Whenever a channel gets redirected, append the principal of the * channel [before the channels got redirected] to the loadinfo, * so that at every point this array lets us reason about all the diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 0da79c18a..8b7f31f99 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -173,6 +173,8 @@ uint32_t nsIOService::gDefaultSegmentCount = 24; bool nsIOService::sTelemetryEnabled = false; +bool nsIOService::sBlockToplevelDataUriNavigations = false; + //////////////////////////////////////////////////////////////////////////////// nsIOService::nsIOService() @@ -251,6 +253,8 @@ nsIOService::Init() NS_WARNING("failed to get observer service"); Preferences::AddBoolVarCache(&sTelemetryEnabled, "toolkit.telemetry.enabled", false); + Preferences::AddBoolVarCache(&sBlockToplevelDataUriNavigations, + "security.data_uri.block_toplevel_data_uri_navigations", false); Preferences::AddBoolVarCache(&mOfflineMirrorsConnectivity, OFFLINE_MIRRORS_CONNECTIVITY, true); gIOService = this; @@ -1876,5 +1880,11 @@ nsIOService::SpeculativeAnonymousConnect2(nsIURI *aURI, return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, true); } +/*static*/ bool +nsIOService::BlockToplevelDataUriNavigations() +{ + return sBlockToplevelDataUriNavigations; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/base/nsIOService.h b/netwerk/base/nsIOService.h index 7ac23b791..e592c4d1c 100644 --- a/netwerk/base/nsIOService.h +++ b/netwerk/base/nsIOService.h @@ -95,6 +95,8 @@ public: bool IsLinkUp(); + static bool BlockToplevelDataUriNavigations(); + // Used to trigger a recheck of the captive portal status nsresult RecheckCaptivePortal(); private: @@ -176,6 +178,8 @@ private: static bool sTelemetryEnabled; + static bool sBlockToplevelDataUriNavigations; + // These timestamps are needed for collecting telemetry on PR_Connect, // PR_ConnectContinue and PR_Close blocking time. If we spend very long // time in any of these functions we want to know if and what network diff --git a/netwerk/base/nsIURI.idl b/netwerk/base/nsIURI.idl index 2384c5fd9..ef163813a 100644 --- a/netwerk/base/nsIURI.idl +++ b/netwerk/base/nsIURI.idl @@ -10,18 +10,18 @@ * provides accessors to set and query the most basic components of an URI. * Subclasses, including nsIURL, impose greater structure on the URI. * - * This interface follows Tim Berners-Lee's URI spec (RFC2396) [1], where the + * This interface follows Tim Berners-Lee's URI spec (RFC3986) [1], where the * basic URI components are defined as such: * <pre> - * ftp://username:password@hostname:portnumber/pathname#ref - * \ / \ / \ / \ /\ \ / - * - --------------- ------ -------- | - - * | | | | | | - * | | | | | Ref - * | | | Port \ / - * | | Host / -------- - * | UserPass / | - * Scheme / Path + * ftp://username:password@hostname:portnumber/pathname?query#ref + * \ / \ / \ / \ /\ / \ / \ / + * - --------------- ------ -------- ------- --- - + * | | | | | | | + * | | | | FilePath Query Ref + * | | | Port \ / + * | | Host / ------------ + * | UserPass / | + * Scheme / Path * \ / * -------------------------------- * | @@ -30,13 +30,9 @@ * The definition of the URI components has been extended to allow for * internationalized domain names [2] and the more generic IRI structure [3]. * - * Note also that the RFC defines #-separated fragment identifiers as being - * "not part of the URI". Despite this, we bundle them as part of the URI, for - * convenience. - * - * [1] http://www.ietf.org/rfc/rfc2396.txt - * [2] http://www.ietf.org/internet-drafts/draft-ietf-idn-idna-06.txt - * [3] http://www.ietf.org/internet-drafts/draft-masinter-url-i18n-08.txt + * [1] https://tools.ietf.org/html/rfc3986 + * [2] https://tools.ietf.org/html/rfc5890 + * [3] https://tools.ietf.org/html/rfc3987 */ %{C++ @@ -116,7 +112,7 @@ interface nsIURI : nsISupports /** * The Scheme is the protocol to which this URI refers. The scheme is - * restricted to the US-ASCII charset per RFC2396. Setting this is + * restricted to the US-ASCII charset per RFC3986. Setting this is * highly discouraged outside of a protocol handler implementation, since * that will generally lead to incorrect results. */ @@ -174,6 +170,9 @@ interface nsIURI : nsISupports * empty, depending on the protocol). * * Some characters may be escaped. + * + * This attribute contains query and ref parts for historical reasons. + * Use the 'filePath' attribute if you do not want those parts included. */ attribute AUTF8String path; @@ -281,10 +280,31 @@ interface nsIURI : nsISupports /** * returns a string for the current URI with the ref element cleared. */ - readonly attribute AUTF8String specIgnoringRef; + readonly attribute AUTF8String specIgnoringRef; /** * Returns if there is a reference portion (the part after the "#") of the URI. */ - readonly attribute boolean hasRef; + readonly attribute boolean hasRef; + + /************************************************************************ + * Additional attributes added for .query support: + */ + + /** + * Returns a path including the directory and file portions of a + * URL. For example, the filePath of "http://host/foo/bar.html#baz" + * is "/foo/bar.html". + * + * Some characters may be escaped. + */ + attribute AUTF8String filePath; + + /** + * Returns the query portion (the part after the "?") of the URL. + * If there isn't one, an empty string is returned. + * + * Some characters may be escaped. + */ + attribute AUTF8String query; }; diff --git a/netwerk/base/nsIURIWithQuery.idl b/netwerk/base/nsIURIWithQuery.idl deleted file mode 100644 index 749b2773d..000000000 --- a/netwerk/base/nsIURIWithQuery.idl +++ /dev/null @@ -1,30 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIURI.idl" - -/** - * nsIURIWithQuery is implemented by URIs which have a query parameter. - * This is useful for the URL API. - */ -[scriptable, uuid(367510ee-8556-435a-8f99-b5fd357e08cc)] -interface nsIURIWithQuery : nsIURI -{ - /** - * Returns a path including the directory and file portions of a - * URL. For example, the filePath of "http://host/foo/bar.html#baz" - * is "/foo/bar.html". - * - * Some characters may be escaped. - */ - attribute AUTF8String filePath; - - /** - * Returns the query portion (the part after the "?") of the URL. - * If there isn't one, an empty string is returned. - * - * Some characters may be escaped. - */ - attribute AUTF8String query; -}; diff --git a/netwerk/base/nsIURL.idl b/netwerk/base/nsIURL.idl index aeaa3f694..9ff6c3dcd 100644 --- a/netwerk/base/nsIURL.idl +++ b/netwerk/base/nsIURL.idl @@ -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/. */ -#include "nsIURIWithQuery.idl" +#include "nsIURI.idl" /** * The nsIURL interface provides convenience methods that further @@ -20,7 +20,7 @@ * filePath */ [scriptable, uuid(86adcd89-0b70-47a2-b0fe-5bb2c5f37e31)] -interface nsIURL : nsIURIWithQuery +interface nsIURL : nsIURI { /************************************************************************* * The URL path is broken down into the following principal components: @@ -28,7 +28,7 @@ interface nsIURL : nsIURIWithQuery * attribute AUTF8String filePath; * attribute AUTF8String query; * - * These are inherited from nsIURIWithQuery. + * These are inherited from nsIURI. */ /************************************************************************* diff --git a/netwerk/base/nsSimpleURI.cpp b/netwerk/base/nsSimpleURI.cpp index ae5c51a1e..dbc0dc817 100644 --- a/netwerk/base/nsSimpleURI.cpp +++ b/netwerk/base/nsSimpleURI.cpp @@ -48,7 +48,7 @@ nsSimpleURI::~nsSimpleURI() NS_IMPL_ADDREF(nsSimpleURI) NS_IMPL_RELEASE(nsSimpleURI) NS_INTERFACE_TABLE_HEAD(nsSimpleURI) -NS_INTERFACE_TABLE(nsSimpleURI, nsIURI, nsIURIWithQuery, nsISerializable, +NS_INTERFACE_TABLE(nsSimpleURI, nsIURI, nsISerializable, nsIClassInfo, nsIMutable, nsIIPCSerializableURI) NS_INTERFACE_TABLE_TO_MAP_SEGUE if (aIID.Equals(kThisSimpleURIImplementationCID)) @@ -784,10 +784,6 @@ nsSimpleURI::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } -//---------------------------------------------------------------------------- -// nsSimpleURI::nsIURIWithQuery -//---------------------------------------------------------------------------- - NS_IMETHODIMP nsSimpleURI::GetFilePath(nsACString& aFilePath) { diff --git a/netwerk/base/nsSimpleURI.h b/netwerk/base/nsSimpleURI.h index 29bc9b313..842136ed6 100644 --- a/netwerk/base/nsSimpleURI.h +++ b/netwerk/base/nsSimpleURI.h @@ -8,7 +8,6 @@ #include "mozilla/MemoryReporting.h" #include "nsIURI.h" -#include "nsIURIWithQuery.h" #include "nsISerializable.h" #include "nsString.h" #include "nsIClassInfo.h" @@ -28,7 +27,7 @@ namespace net { } class nsSimpleURI - : public nsIURIWithQuery + : public nsIURI , public nsISerializable , public nsIClassInfo , public nsIMutable @@ -41,7 +40,6 @@ protected: public: NS_DECL_ISUPPORTS NS_DECL_NSIURI - NS_DECL_NSIURIWITHQUERY NS_DECL_NSISERIALIZABLE NS_DECL_NSICLASSINFO NS_DECL_NSIMUTABLE diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp index 21c4cf7fd..e2a290e4d 100644 --- a/netwerk/base/nsStandardURL.cpp +++ b/netwerk/base/nsStandardURL.cpp @@ -1182,7 +1182,6 @@ NS_IMPL_RELEASE(nsStandardURL) NS_INTERFACE_MAP_BEGIN(nsStandardURL) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardURL) NS_INTERFACE_MAP_ENTRY(nsIURI) - NS_INTERFACE_MAP_ENTRY(nsIURIWithQuery) NS_INTERFACE_MAP_ENTRY(nsIURL) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileURL, mSupportsFileURL) NS_INTERFACE_MAP_ENTRY(nsIStandardURL) @@ -3442,10 +3441,29 @@ ToIPCSegment(const nsStandardURL::URLSegment& aSegment) } inline -nsStandardURL::URLSegment -FromIPCSegment(const ipc::StandardURLSegment& aSegment) +MOZ_MUST_USE bool +FromIPCSegment(const nsACString& aSpec, const ipc::StandardURLSegment& aSegment, nsStandardURL::URLSegment& aTarget) { - return nsStandardURL::URLSegment(aSegment.position(), aSegment.length()); + // This seems to be just an empty segment. + if (aSegment.length() == -1) { + aTarget = nsStandardURL::URLSegment(); + return true; + } + + // A value of -1 means an empty segment, but < -1 is undefined. + if (NS_WARN_IF(aSegment.length() < -1)) { + return false; + } + + // Make sure the segment does not extend beyond the spec. + if (NS_WARN_IF(aSegment.position() + aSegment.length() > aSpec.Length())) { + return false; + } + + aTarget.mPos = aSegment.position(); + aTarget.mLen = aSegment.length(); + + return true; } void @@ -3520,23 +3538,38 @@ nsStandardURL::Deserialize(const URIParams& aParams) mPort = params.port(); mDefaultPort = params.defaultPort(); mSpec = params.spec(); - mScheme = FromIPCSegment(params.scheme()); - mAuthority = FromIPCSegment(params.authority()); - mUsername = FromIPCSegment(params.username()); - mPassword = FromIPCSegment(params.password()); - mHost = FromIPCSegment(params.host()); - mPath = FromIPCSegment(params.path()); - mFilepath = FromIPCSegment(params.filePath()); - mDirectory = FromIPCSegment(params.directory()); - mBasename = FromIPCSegment(params.baseName()); - mExtension = FromIPCSegment(params.extension()); - mQuery = FromIPCSegment(params.query()); - mRef = FromIPCSegment(params.ref()); + + NS_ENSURE_TRUE(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.scheme(), mScheme), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.authority(), mAuthority), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.username(), mUsername), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.password(), mPassword), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.host(), mHost), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.path(), mPath), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.filePath(), mFilepath), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.directory(), mDirectory), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.baseName(), mBasename), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.extension(), mExtension), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.query(), mQuery), false); + NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.ref(), mRef), false); + mOriginCharset = params.originCharset(); mMutable = params.isMutable(); mSupportsFileURL = params.supportsFileURL(); mHostEncoding = params.hostEncoding(); + // Some sanity checks + NS_ENSURE_TRUE(mScheme.mPos == 0, false); + NS_ENSURE_TRUE(mScheme.mLen > 0, false); + // Make sure scheme is followed by :// (3 characters) + NS_ENSURE_TRUE(mScheme.mLen < INT32_MAX - 3, false); // avoid overflow + NS_ENSURE_TRUE(mSpec.Length() >= (uint32_t) mScheme.mLen + 3, false); + NS_ENSURE_TRUE(nsDependentCSubstring(mSpec, mScheme.mLen, 3).EqualsLiteral("://"), false); + NS_ENSURE_TRUE(mPath.mLen != -1 && mSpec.CharAt(mPath.mPos) == '/', false); + NS_ENSURE_TRUE(mPath.mPos == mFilepath.mPos, false); + NS_ENSURE_TRUE(mQuery.mLen == -1 || mSpec.CharAt(mQuery.mPos - 1) == '?', false); + NS_ENSURE_TRUE(mRef.mLen == -1 || mSpec.CharAt(mRef.mPos - 1) == '#', false); + // mSpecEncoding and mHostA are just caches that can be recovered as needed. return true; } diff --git a/netwerk/base/nsStandardURL.h b/netwerk/base/nsStandardURL.h index 90f7f7db2..0ca345572 100644 --- a/netwerk/base/nsStandardURL.h +++ b/netwerk/base/nsStandardURL.h @@ -54,7 +54,6 @@ protected: public: NS_DECL_ISUPPORTS NS_DECL_NSIURI - NS_DECL_NSIURIWITHQUERY NS_DECL_NSIURL NS_DECL_NSIFILEURL NS_DECL_NSISTANDARDURL diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 9365397d1..4f4dcf6a9 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -39,6 +39,7 @@ struct LoadInfoArgs bool upgradeInsecureRequests; bool verifySignedContent; bool enforceSRI; + bool forceAllowDataURI; bool forceInheritPrincipalDropped; uint64_t innerWindowID; uint64_t outerWindowID; @@ -53,6 +54,7 @@ struct LoadInfoArgs nsCString[] corsUnsafeHeaders; bool forcePreflight; bool isPreflight; + bool loadTriggeredFromExternal; bool forceHSTSPriming; bool mixedContentWouldBlock; }; diff --git a/old-configure.in b/old-configure.in index 6e2d743d6..511f40653 100644 --- a/old-configure.in +++ b/old-configure.in @@ -936,7 +936,7 @@ case "$target" in fi MOZ_GFX_OPTIMIZE_MOBILE=1 - MOZ_OPTIMIZE_FLAGS="-Os" + MOZ_OPTIMIZE_FLAGS="-O2" if test -z "$CLANG_CC"; then MOZ_OPTIMIZE_FLAGS="-freorder-blocks -fno-reorder-functions $MOZ_OPTIMIZE_FLAGS" fi @@ -945,7 +945,7 @@ case "$target" in *-*linux*) if test "$GNU_CC" -o "$GNU_CXX"; then MOZ_PGO_OPTIMIZE_FLAGS="-O3" - MOZ_OPTIMIZE_FLAGS="-Os" + MOZ_OPTIMIZE_FLAGS="-O2" if test -z "$CLANG_CC"; then MOZ_OPTIMIZE_FLAGS="-freorder-blocks $MOZ_OPTIMIZE_FLAGS" fi @@ -2411,15 +2411,6 @@ if test -n "$WITH_APP_BASENAME" ; then MOZ_APP_BASENAME="$WITH_APP_BASENAME" fi -# Special cases where we need to AC_DEFINE something. Also a holdover for apps -# that haven't made a confvars.sh yet. Don't add new stuff here, use -# MOZ_BUILD_APP. -case "$MOZ_BUILD_APP" in -xulrunner) - AC_DEFINE(MOZ_XULRUNNER) - ;; -esac - if test -n "$MOZ_B2G"; then AC_DEFINE(MOZ_B2G) fi @@ -2429,7 +2420,6 @@ if test -n "$MOZ_GRAPHENE"; then AC_DEFINE(MOZ_GRAPHENE) fi -AC_SUBST(MOZ_XULRUNNER) AC_SUBST(MOZ_B2G) AC_SUBST(MOZ_B2G_VERSION) diff --git a/security/certverifier/CertVerifier.cpp b/security/certverifier/CertVerifier.cpp index 61d8fcdb8..2957a269f 100644 --- a/security/certverifier/CertVerifier.cpp +++ b/security/certverifier/CertVerifier.cpp @@ -224,8 +224,7 @@ CertVerifier::VerifySignedCertificateTimestamps( CERTCertListNode* issuerNode = CERT_LIST_NEXT(endEntityNode); if (!issuerNode || CERT_LIST_END(issuerNode, builtChain)) { // Issuer certificate is required for SCT verification. - // TODO(bug 1294580): change this to Result::FATAL_ERROR_INVALID_ARGS - return Success; + return Result::FATAL_ERROR_INVALID_ARGS; } CERTCertificate* endEntity = endEntityNode->cert; diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index 1fe27b760..b4e12fe9c 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -245,7 +245,11 @@ NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA, // For TRUST, we only use the CERTDB_TRUSTED_CA bit, because Goanna hasn't // needed to consider end-entity certs to be their own trust anchors since // Goanna implemented nsICertOverrideService. - if (flags & CERTDB_TRUSTED_CA) { + // Of course, for this to work as expected, we need to make sure we're + // inquiring about the trust of a CA and not an end-entity. If an end-entity + // has the CERTDB_TRUSTED_CA bit set, Gecko does not consider it to be a + // trust anchor; it must inherit its trust. + if (flags & CERTDB_TRUSTED_CA && endEntityOrCA == EndEntityOrCA::MustBeCA) { if (policy.IsAnyPolicy()) { trustLevel = TrustLevel::TrustAnchor; return Success; diff --git a/security/manager/ssl/tests/unit/test_cert_trust.js b/security/manager/ssl/tests/unit/test_cert_trust.js index 622678c7a..bf081f1bd 100644 --- a/security/manager/ssl/tests/unit/test_cert_trust.js +++ b/security/manager/ssl/tests/unit/test_cert_trust.js @@ -208,9 +208,31 @@ function run_test() { setCertTrust(ca_cert, ",,"); setCertTrust(int_cert, ",,"); - // It turns out that if an end-entity certificate is manually trusted, it can - // be the root of its own verified chain. This will be removed in bug 1294580. - setCertTrust(ee_cert, "C,,"); + // If an end-entity certificate is manually trusted, it may not be the root of + // its own verified chain. In general this will cause "unknown issuer" errors + // unless a CA trust anchor can be found. + setCertTrust(ee_cert, "CTu,CTu,CTu"); + checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageSSLServer); + checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageSSLClient); + checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageEmailSigner); + checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageEmailRecipient); + checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageObjectSigner); + + // Now make a CA trust anchor available. + setCertTrust(ca_cert, "CTu,CTu,CTu"); checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, certificateUsageSSLServer); + checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLClient); + checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailSigner); + checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailRecipient); + checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageObjectSigner); } diff --git a/security/nss/lib/softoken/sftkpwd.c b/security/nss/lib/softoken/sftkpwd.c index e0d2df9ab..07b6922dc 100644 --- a/security/nss/lib/softoken/sftkpwd.c +++ b/security/nss/lib/softoken/sftkpwd.c @@ -273,7 +273,7 @@ sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey, RNG_GenerateGlobalRandomBytes(saltData, cipherValue.salt.len); param = nsspkcs5_NewParam(cipherValue.alg, HASH_AlgSHA1, &cipherValue.salt, - 1); + 30000); if (param == NULL) { rv = SECFailure; goto loser; @@ -444,7 +444,7 @@ sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey, RNG_GenerateGlobalRandomBytes(saltData, prfLength); /* initialize our pkcs5 parameter */ - param = nsspkcs5_NewParam(signValue.alg, HASH_AlgSHA1, &signValue.salt, 1); + param = nsspkcs5_NewParam(signValue.alg, HASH_AlgSHA1, &signValue.salt, 30000); if (param == NULL) { rv = SECFailure; goto loser; diff --git a/services/sync/tests/unit/test_service_login.js b/services/sync/tests/unit/test_service_login.js index 42c163915..2ecb0a377 100644 --- a/services/sync/tests/unit/test_service_login.js +++ b/services/sync/tests/unit/test_service_login.js @@ -206,7 +206,7 @@ add_test(function test_login_on_sync() { _("Old passphrase function is " + oldGetter); Service.identity.__defineGetter__("syncKey", function() { - throw "User canceled Master Password entry"; + throw "User canceled master password entry"; }); let oldClearSyncTriggers = Service.scheduler.clearSyncTriggers; diff --git a/services/sync/tests/unit/test_syncscheduler.js b/services/sync/tests/unit/test_syncscheduler.js index b066eae82..730a3f996 100644 --- a/services/sync/tests/unit/test_syncscheduler.js +++ b/services/sync/tests/unit/test_syncscheduler.js @@ -535,7 +535,7 @@ add_task(function* test_autoconnect_mp_locked() { delete Service.identity.syncKey; Service.identity.__defineGetter__("syncKey", function() { _("Faking Master Password entry cancelation."); - throw "User canceled Master Password entry"; + throw "User canceled master password entry"; }); let deferred = Promise.defer(); diff --git a/testing/marionette/element.js b/testing/marionette/element.js index 8e66ee6df..9687fb27d 100644 --- a/testing/marionette/element.js +++ b/testing/marionette/element.js @@ -953,6 +953,12 @@ element.getContainer = function (el) { * pointer-interactable, if it is found somewhere in the * |elementsFromPoint| list at |el|'s in-view centre coordinates. * + * Before running the check, we change |el|'s pointerEvents style property + * to "auto", since elements without pointer events enabled do not turn + * up in the paint tree we get from document.elementsFromPoint. This is + * a specialisation that is only relevant when checking if the element is + * in view. + * * @param {Element} el * Element to check if is in view. * @@ -960,8 +966,14 @@ element.getContainer = function (el) { * True if |el| is inside the viewport, or false otherwise. */ element.isInView = function (el) { - let tree = element.getPointerInteractablePaintTree(el); - return tree.includes(el); + let originalPointerEvents = el.style.pointerEvents; + try { + el.style.pointerEvents = "auto"; + const tree = element.getPointerInteractablePaintTree(el); + return tree.includes(el); + } finally { + el.style.pointerEvents = originalPointerEvents; + } }; /** diff --git a/testing/marionette/error.js b/testing/marionette/error.js index 97cc3fb25..c36dace25 100644 --- a/testing/marionette/error.js +++ b/testing/marionette/error.js @@ -260,10 +260,23 @@ class ElementClickInterceptedError extends WebDriverError { if (obscuredEl && coords) { const doc = obscuredEl.ownerDocument; const overlayingEl = doc.elementFromPoint(coords.x, coords.y); - msg = error.pprint`Element ${obscuredEl} is not clickable ` + - `at point (${coords.x},${coords.y}) ` + - error.pprint`because another element ${overlayingEl} ` + - `obscures it`; + + switch (obscuredEl.style.pointerEvents) { + case "none": + msg = error.pprint`Element ${obscuredEl} is not clickable ` + + `at point (${coords.x},${coords.y}) ` + + `because it does not have pointer events enabled, ` + + error.pprint`and element ${overlayingEl} ` + + `would receive the click instead`; + break; + + default: + msg = error.pprint`Element ${obscuredEl} is not clickable ` + + `at point (${coords.x},${coords.y}) ` + + error.pprint`because another element ${overlayingEl} ` + + `obscures it`; + break; + } } super(msg); diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_click.py b/testing/marionette/harness/marionette_harness/tests/unit/test_click.py index d03062e85..06019834a 100644 --- a/testing/marionette/harness/marionette_harness/tests/unit/test_click.py +++ b/testing/marionette/harness/marionette_harness/tests/unit/test_click.py @@ -252,3 +252,20 @@ class TestClick(TestLegacyClick): with self.assertRaises(errors.ElementClickInterceptedException): obscured.click() self.assertFalse(self.marionette.execute_script("return window.clicked", sandbox=None)) + + def test_pointer_events_none(self): + self.marionette.navigate(inline(""" + <button style="pointer-events: none">click me</button> + <script> + window.clicked = false; + let button = document.querySelector("button"); + button.addEventListener("click", () => window.clicked = true); + </script> + """)) + button = self.marionette.find_element(By.TAG_NAME, "button") + self.assertEqual("none", button.value_of_css_property("pointer-events")) + + with self.assertRaisesRegexp(errors.ElementClickInterceptedException, + "does not have pointer events enabled"): + button.click() + self.assertFalse(self.marionette.execute_script("return window.clicked", sandbox=None)) diff --git a/testing/marionette/test_error.js b/testing/marionette/test_error.js index f27212637..a905f02f0 100644 --- a/testing/marionette/test_error.js +++ b/testing/marionette/test_error.js @@ -209,15 +209,25 @@ add_test(function test_ElementClickInterceptedError() { return otherEl; }, }, + style: { + pointerEvents: "auto", + } }; - let err = new ElementClickInterceptedError(obscuredEl, {x: 1, y: 2}); - equal("ElementClickInterceptedError", err.name); + let err1 = new ElementClickInterceptedError(obscuredEl, {x: 1, y: 2}); + equal("ElementClickInterceptedError", err1.name); equal("Element <b> is not clickable at point (1,2) " + "because another element <a> obscures it", - err.message); - equal("element click intercepted", err.status); - ok(err instanceof WebDriverError); + err1.message); + equal("element click intercepted", err1.status); + ok(err1 instanceof WebDriverError); + + obscuredEl.style.pointerEvents = "none"; + let err2 = new ElementClickInterceptedError(obscuredEl, {x: 1, y: 2}); + equal("Element <b> is not clickable at point (1,2) " + + "because it does not have pointer events enabled, " + + "and element <a> would receive the click instead", + err2.message); run_next_test(); }); diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index ca574833b..3c7df67fa 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -38674,6 +38674,12 @@ "url": "/html/webappapis/idle-callbacks/callback-multiple-calls.html" } ], + "html/webappapis/idle-callbacks/callback-suspended.html": [ + { + "path": "html/webappapis/idle-callbacks/callback-suspended.html", + "url": "/html/webappapis/idle-callbacks/callback-suspended.html" + } + ], "html/webappapis/idle-callbacks/callback-timeout.html": [ { "path": "html/webappapis/idle-callbacks/callback-timeout.html", diff --git a/testing/web-platform/meta/dom/events/EventTarget-dispatchEvent.html.ini b/testing/web-platform/meta/dom/events/EventTarget-dispatchEvent.html.ini index d62b521c5..0d489b03d 100644 --- a/testing/web-platform/meta/dom/events/EventTarget-dispatchEvent.html.ini +++ b/testing/web-platform/meta/dom/events/EventTarget-dispatchEvent.html.ini @@ -12,10 +12,6 @@ expected: FAIL bug: https://github.com/whatwg/dom/issues/362, 1314303 - [If the event's initialized flag is not set, an InvalidStateError must be thrown (FocusEvent).] - expected: FAIL - bug: https://github.com/whatwg/dom/issues/362, 1314303 - [If the event's initialized flag is not set, an InvalidStateError must be thrown (IDBVersionChangeEvent).] expected: FAIL bug: https://github.com/whatwg/dom/issues/362, 1314303 diff --git a/testing/web-platform/meta/dom/nodes/Document-createEvent.html.ini b/testing/web-platform/meta/dom/nodes/Document-createEvent.html.ini index 1d92f01ae..a1c822113 100644 --- a/testing/web-platform/meta/dom/nodes/Document-createEvent.html.ini +++ b/testing/web-platform/meta/dom/nodes/Document-createEvent.html.ini @@ -76,30 +76,6 @@ expected: FAIL bug: https://github.com/whatwg/dom/issues/362, 1314303 - [FocusEvent should be an alias for FocusEvent.] - expected: FAIL - bug: https://github.com/whatwg/dom/issues/362, 1314303 - - [createEvent('FocusEvent') should be initialized correctly.] - expected: FAIL - bug: https://github.com/whatwg/dom/issues/362, 1314303 - - [focusevent should be an alias for FocusEvent.] - expected: FAIL - bug: https://github.com/whatwg/dom/issues/362, 1314303 - - [createEvent('focusevent') should be initialized correctly.] - expected: FAIL - bug: https://github.com/whatwg/dom/issues/362, 1314303 - - [FOCUSEVENT should be an alias for FocusEvent.] - expected: FAIL - bug: https://github.com/whatwg/dom/issues/362, 1314303 - - [createEvent('FOCUSEVENT') should be initialized correctly.] - expected: FAIL - bug: https://github.com/whatwg/dom/issues/362, 1314303 - [IDBVersionChangeEvent should be an alias for IDBVersionChangeEvent.] expected: FAIL bug: https://github.com/whatwg/dom/issues/362, 1314303 diff --git a/testing/web-platform/meta/selection/getSelection.html.ini b/testing/web-platform/meta/selection/getSelection.html.ini index 4db5721ae..672b83770 100644 --- a/testing/web-platform/meta/selection/getSelection.html.ini +++ b/testing/web-platform/meta/selection/getSelection.html.ini @@ -1,14 +1,5 @@ [getSelection.html] type: testharness - [getSelection() on HTML document with null defaultView must be null] - expected: FAIL - - [getSelection() on XML document with null defaultView must be null] - expected: FAIL - - [getSelection() on HTML document with null defaultView must be null inside an iframe onload] - expected: FAIL - [window.getSelection() instanceof Selection in an iframe immediately after appendChild] expected: FAIL diff --git a/testing/web-platform/tests/fetch/api/response/response-init-002.html b/testing/web-platform/tests/fetch/api/response/response-init-002.html index 0bb2e8d0b..a48af8336 100644 --- a/testing/web-platform/tests/fetch/api/response/response-init-002.html +++ b/testing/web-platform/tests/fetch/api/response/response-init-002.html @@ -65,6 +65,11 @@ }); }, "Testing empty Response Content-Type header"); + test(function() { + var response = new Response(null, {status: 204}); + assert_equals(response.body, null); + }, "Testing null Response body"); + </script> </body> </html> diff --git a/testing/web-platform/tests/html/webappapis/idle-callbacks/callback-suspended.html b/testing/web-platform/tests/html/webappapis/idle-callbacks/callback-suspended.html new file mode 100644 index 000000000..6040de922 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/idle-callbacks/callback-suspended.html @@ -0,0 +1,93 @@ +<!doctype html> +<meta charset=utf-8> +<title>Dispatching idle callbacks should be able to be suspended and then resumed</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="log"></div> +<script> + function withEventListener(target, event, handler) { + handler = handler || (e => e); + return new Promise(resolve => { + let wrapper = function(e) { + let result = handler(e); + if (!result) { + return; + } + + resolve(result); + } + target.addEventListener(event, wrapper, { once: true }); + }); + } + + function makePostBackUrl(name) { + return new URL('resources/post_name_on_load.html?name=' + name, + window.location).href; + } + + function waitForMessage(message, handler) { + return withEventListener(window, 'message', e => (e.data === message) && handler(e));; + } + + function withWindow(name) { + let win = window.open(makePostBackUrl(name)) + return waitForMessage(name, _ => win); + } + + function navigateWindow(win, name) { + win.location = makePostBackUrl(name); + return waitForMessage(name, _ => win); + } + + function waitDuration(delay) { + return new Promise(resolve => { + setTimeout(resolve, delay); + }) + } + + function goBack(win) { + var p = withEventListener(win, 'pagehide'); + win.history.back(); + return p; + } + + promise_test(t => { + let idleCalled = false; + let running = true; + return withWindow('foo') + .then(win => { + let callback = function(d) { + idleCalled = true; + if (running) { + win.requestIdleCallback(callback); + } + }; + + win.requestIdleCallback(callback); + + return navigateWindow(win, 'bar') + .then(_ => idleCalled = false) + .then(_ => waitDuration(2000)) + .then(_ => { + assert_false(idleCalled, "idle callback shouldn't have been called yet"); + return goBack(win); + }) + .then(_ => Promise.race([ + // At this point it's a matter of having bfcache ... + waitDuration(2000) + .then(_ => { + assert_true(idleCalled, "idle callback should've been called by now"); + running = false; + }), + // ... or not. If not, we expect a load event. + waitForMessage("foo") + ])) + .then(_ => win.close()) + .catch(e => { + win.close(); + throw e; + }) + }); + }); + +</script> diff --git a/testing/web-platform/tests/html/webappapis/idle-callbacks/callback-timeout.html b/testing/web-platform/tests/html/webappapis/idle-callbacks/callback-timeout.html index 823d5f5db..cc2660a19 100644 --- a/testing/web-platform/tests/html/webappapis/idle-callbacks/callback-timeout.html +++ b/testing/web-platform/tests/html/webappapis/idle-callbacks/callback-timeout.html @@ -25,4 +25,19 @@ } window.requestIdleCallback(t.step_func(f)); }, "requestIdleCallback callback should time out"); + + async_test(function (t) { + assert_false(document.hidden, "document.hidden must exist and be false to run this test properly"); + function g(deadline) { + assert_false(deadline.didTimeout) + t.done(); + } + + function f(deadline) { + assert_false(deadline.didTimeout); + window.requestIdleCallback(t.step_func(g), {timeout:100000}); + } + window.requestIdleCallback(t.step_func(f)); + }, "requestIdleCallback callback should not time out"); + </script> diff --git a/testing/web-platform/tests/html/webappapis/idle-callbacks/cancel-invoked.html b/testing/web-platform/tests/html/webappapis/idle-callbacks/cancel-invoked.html index 8956b8709..9fb77d65d 100644 --- a/testing/web-platform/tests/html/webappapis/idle-callbacks/cancel-invoked.html +++ b/testing/web-platform/tests/html/webappapis/idle-callbacks/cancel-invoked.html @@ -23,4 +23,10 @@ t.done(); }, 2000); }, "A cancelled callback is never invoked"); + + async_test(function (t) { + var handle = requestIdleCallback(t.step_func_done(function () { + cancelIdleCallback(handle); + })); + }, "Cancelling the currently executing idle callback should be allowed"); </script> diff --git a/testing/web-platform/tests/html/webappapis/idle-callbacks/resources/post_name_on_load.html b/testing/web-platform/tests/html/webappapis/idle-callbacks/resources/post_name_on_load.html new file mode 100644 index 000000000..4679a6e6e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/idle-callbacks/resources/post_name_on_load.html @@ -0,0 +1,7 @@ +<!doctype html> +<script> + addEventListener('load', _ => { + let params = new URLSearchParams(window.location.search); + window.opener.postMessage(params.get('name'), '*'); + }); +</script> diff --git a/toolkit/components/aboutcache/content/aboutCache.js b/toolkit/components/aboutcache/content/aboutCache.js index 07067cce3..e945d683e 100644 --- a/toolkit/components/aboutcache/content/aboutCache.js +++ b/toolkit/components/aboutcache/content/aboutCache.js @@ -40,5 +40,9 @@ function navigate() if ($('priv').checked) context += 'p,'; + if (storage == null) { + storage = ""; + } + window.location.href = 'about:cache?storage=' + storage + '&context=' + context; } diff --git a/toolkit/components/autocomplete/nsAutoCompleteController.cpp b/toolkit/components/autocomplete/nsAutoCompleteController.cpp index 5d69ea1a3..9ca382fe5 100644 --- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp +++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp @@ -1637,58 +1637,72 @@ nsAutoCompleteController::ProcessResult(int32_t aSearchIndex, nsIAutoCompleteRes MOZ_ASSERT(mResults.Count() >= aSearchIndex + 1, "aSearchIndex should always be valid for mResults"); - uint32_t oldRowCount = mRowCount; - // If the search failed, increase the match count to include the error - // description. - if (searchResult == nsIAutoCompleteResult::RESULT_FAILURE) { - nsAutoString error; - aResult->GetErrorDescription(error); - if (!error.IsEmpty()) { - ++mRowCount; - if (mTree) { - mTree->RowCountChanged(oldRowCount, 1); + bool isTypeAheadResult = false; + aResult->GetTypeAheadResult(&isTypeAheadResult); + + if (!isTypeAheadResult) { + uint32_t oldRowCount = mRowCount; + // If the search failed, increase the match count to include the error + // description. + if (searchResult == nsIAutoCompleteResult::RESULT_FAILURE) { + nsAutoString error; + aResult->GetErrorDescription(error); + if (!error.IsEmpty()) { + ++mRowCount; + if (mTree) { + mTree->RowCountChanged(oldRowCount, 1); + } } - } - } else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS || - searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) { - // Increase the match count for all matches in this result. - uint32_t totalMatchCount = 0; - for (uint32_t i = 0; i < mResults.Length(); i++) { - nsIAutoCompleteResult* result = mResults.SafeObjectAt(i); - if (result) { - uint32_t matchCount = 0; - result->GetMatchCount(&matchCount); - totalMatchCount += matchCount; + } else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS || + searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) { + // Increase the match count for all matches in this result. + uint32_t totalMatchCount = 0; + for (uint32_t i = 0; i < mResults.Length(); i++) { + nsIAutoCompleteResult* result = mResults.SafeObjectAt(i); + if (result) { + // not all results implement this, so it can likely fail. + bool typeAhead = false; + result->GetTypeAheadResult(&typeAhead); + if (!typeAhead) { + uint32_t matchCount = 0; + result->GetMatchCount(&matchCount); + totalMatchCount += matchCount; + } + } } - } - uint32_t delta = totalMatchCount - oldRowCount; + uint32_t delta = totalMatchCount - oldRowCount; - mRowCount += delta; - if (mTree) { - mTree->RowCountChanged(oldRowCount, delta); + mRowCount += delta; + if (mTree) { + mTree->RowCountChanged(oldRowCount, delta); + } } - } - // Try to autocomplete the default index for this search. - // Do this before invalidating so the binding knows about it. - CompleteDefaultIndex(aSearchIndex); + // Try to autocomplete the default index for this search. + // Do this before invalidating so the binding knows about it. + CompleteDefaultIndex(aSearchIndex); - // Refresh the popup view to display the new search results - nsCOMPtr<nsIAutoCompletePopup> popup; - input->GetPopup(getter_AddRefs(popup)); - NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE); - popup->Invalidate(nsIAutoCompletePopup::INVALIDATE_REASON_NEW_RESULT); + // Refresh the popup view to display the new search results + nsCOMPtr<nsIAutoCompletePopup> popup; + input->GetPopup(getter_AddRefs(popup)); + NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE); + popup->Invalidate(nsIAutoCompletePopup::INVALIDATE_REASON_NEW_RESULT); - uint32_t minResults; - input->GetMinResultsForPopup(&minResults); + uint32_t minResults; + input->GetMinResultsForPopup(&minResults); - // Make sure the popup is open, if necessary, since we now have at least one - // search result ready to display. Don't force the popup closed if we might - // get results in the future to avoid unnecessarily canceling searches. - if (mRowCount || !minResults) { - OpenPopup(); - } else if (mSearchesOngoing == 0) { - ClosePopup(); + // Make sure the popup is open, if necessary, since we now have at least one + // search result ready to display. Don't force the popup closed if we might + // get results in the future to avoid unnecessarily canceling searches. + if (mRowCount || !minResults) { + OpenPopup(); + } else if (mSearchesOngoing == 0) { + ClosePopup(); + } + } else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS || + searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) { + // Try to autocomplete the default index for this search. + CompleteDefaultIndex(aSearchIndex); } return NS_OK; @@ -2033,14 +2047,20 @@ nsAutoCompleteController::RowIndexToSearch(int32_t aRowIndex, int32_t *aSearchIn uint32_t rowCount = 0; - uint16_t searchResult; - result->GetSearchResult(&searchResult); + // Skip past the result completely if it is marked as hidden + bool isTypeAheadResult = false; + result->GetTypeAheadResult(&isTypeAheadResult); - // Find out how many results were provided by the - // current nsIAutoCompleteSearch. - if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS || - searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) { - result->GetMatchCount(&rowCount); + if (!isTypeAheadResult) { + uint16_t searchResult; + result->GetSearchResult(&searchResult); + + // Find out how many results were provided by the + // current nsIAutoCompleteSearch. + if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS || + searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) { + result->GetMatchCount(&rowCount); + } } // If the given row index is within the results range diff --git a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp index 9fd2c0022..683ac462a 100644 --- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp +++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp @@ -43,7 +43,8 @@ struct AutoCompleteSimpleResultMatch nsAutoCompleteSimpleResult::nsAutoCompleteSimpleResult() : mDefaultIndex(-1), - mSearchResult(RESULT_NOMATCH) + mSearchResult(RESULT_NOMATCH), + mTypeAheadResult(false) { } @@ -66,6 +67,12 @@ nsAutoCompleteSimpleResult::AppendResult(nsIAutoCompleteResult* aResult) mErrorDescription = errorDescription; } + bool typeAheadResult = false; + if (NS_SUCCEEDED(aResult->GetTypeAheadResult(&typeAheadResult)) && + typeAheadResult) { + mTypeAheadResult = typeAheadResult; + } + int32_t defaultIndex = -1; if (NS_SUCCEEDED(aResult->GetDefaultIndex(&defaultIndex)) && defaultIndex >= 0) { @@ -166,6 +173,20 @@ nsAutoCompleteSimpleResult::SetErrorDescription( return NS_OK; } +// typeAheadResult +NS_IMETHODIMP +nsAutoCompleteSimpleResult::GetTypeAheadResult(bool *aTypeAheadResult) +{ + *aTypeAheadResult = mTypeAheadResult; + return NS_OK; +} +NS_IMETHODIMP +nsAutoCompleteSimpleResult::SetTypeAheadResult(bool aTypeAheadResult) +{ + mTypeAheadResult = aTypeAheadResult; + return NS_OK; +} + NS_IMETHODIMP nsAutoCompleteSimpleResult::InsertMatchAt(int32_t aIndex, const nsAString& aValue, diff --git a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h index 28968aa57..61ee542e4 100644 --- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h +++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h @@ -38,6 +38,8 @@ protected: int32_t mDefaultIndex; uint32_t mSearchResult; + bool mTypeAheadResult; + nsCOMPtr<nsIAutoCompleteSimpleResultListener> mListener; }; diff --git a/toolkit/components/autocomplete/nsIAutoCompleteResult.idl b/toolkit/components/autocomplete/nsIAutoCompleteResult.idl index c719d9427..9ae22ade7 100644 --- a/toolkit/components/autocomplete/nsIAutoCompleteResult.idl +++ b/toolkit/components/autocomplete/nsIAutoCompleteResult.idl @@ -50,6 +50,13 @@ interface nsIAutoCompleteResult : nsISupports readonly attribute unsigned long matchCount; /** + * If true, the results will not be displayed in the popup. However, + * if a default index is specified, the default item will still be + * completed in the input. + */ + readonly attribute boolean typeAheadResult; + + /** * Get the value of the result at the given index */ AString getValueAt(in long index); diff --git a/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl b/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl index 5e92e037a..6a8827ab8 100644 --- a/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl +++ b/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl @@ -42,6 +42,12 @@ interface nsIAutoCompleteSimpleResult : nsIAutoCompleteResult void setSearchResult(in unsigned short aSearchResult); /** + * A writer for the readonly attribute 'typeAheadResult', typically set + * because a result is only intended for type-ahead completion. + */ + void setTypeAheadResult(in boolean aHidden); + + /** * Inserts a match consisting of the given value, comment, image, style and * the value to use for defaultIndex completion at a given position. * @param aIndex diff --git a/toolkit/components/autocomplete/tests/unit/head_autocomplete.js b/toolkit/components/autocomplete/tests/unit/head_autocomplete.js index 1443879f0..5a458bdf4 100644 --- a/toolkit/components/autocomplete/tests/unit/head_autocomplete.js +++ b/toolkit/components/autocomplete/tests/unit/head_autocomplete.js @@ -85,6 +85,11 @@ AutoCompleteResultBase.prototype = { defaultIndex: -1, + _typeAheadResult: false, + get typeAheadResult() { + return this._typeAheadResult; + }, + get matchCount() { return this._values.length; }, diff --git a/toolkit/components/autocomplete/tests/unit/test_hiddenResult.js b/toolkit/components/autocomplete/tests/unit/test_hiddenResult.js new file mode 100644 index 000000000..8e2485716 --- /dev/null +++ b/toolkit/components/autocomplete/tests/unit/test_hiddenResult.js @@ -0,0 +1,76 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function AutoCompleteResult(aValues) { + this._values = aValues; + this.defaultIndex = -1; + this._typeAheadResult = false; +} +AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype); + +function AutoCompleteTypeAheadResult(aValues) { + this._values = aValues; + this.defaultIndex = 0; + this._typeAheadResult = true; +} +AutoCompleteTypeAheadResult.prototype = Object.create(AutoCompleteResultBase.prototype); + + +/** + * Test AutoComplete with multiple AutoCompleteSearch sources, with one of them + * being hidden from the popup, but can still do typeahead completion. + */ +function run_test() { + do_test_pending(); + + var inputStr = "moz"; + + // Type ahead result + var searchTypeAhead = new AutoCompleteSearchBase("search1", + new AutoCompleteTypeAheadResult(["mozillaTest1"])); + // Regular result + var searchNormal = new AutoCompleteSearchBase("search2", + new AutoCompleteResult(["mozillaTest2"])); + + // Register searches so AutoCompleteController can find them + registerAutoCompleteSearch(searchNormal); + registerAutoCompleteSearch(searchTypeAhead); + + // Make an AutoCompleteInput that uses our searches + // and confirms results on search complete. + var input = new AutoCompleteInputBase([searchTypeAhead.name, searchNormal.name]); + input.completeDefaultIndex = true; + input.textValue = inputStr; + + // Caret must be at the end. Autofill doesn't happen unless you're typing + // characters at the end. + var strLen = inputStr.length; + input.selectTextRange(strLen, strLen); + do_check_eq(input.selectionStart, strLen); + do_check_eq(input.selectionEnd, strLen); + + var controller = Cc["@mozilla.org/autocomplete/controller;1"]. + getService(Ci.nsIAutoCompleteController); + + controller.input = input; + controller.startSearch(inputStr); + + input.onSearchComplete = function() { + // Hidden results should still be able to do inline autocomplete + do_check_eq(input.textValue, "mozillaTest1"); + + // Now, let's fill the textbox with the first result of the popup. + // The first search is marked as hidden, so we must always get the + // second search. + controller.handleEnter(true); + do_check_eq(input.textValue, "mozillaTest2"); + + // Only one item in the popup. + do_check_eq(controller.matchCount, 1); + + // Unregister searches + unregisterAutoCompleteSearch(searchNormal); + unregisterAutoCompleteSearch(searchTypeAhead); + do_test_finished(); + }; +} diff --git a/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js b/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js new file mode 100644 index 000000000..fb4153355 --- /dev/null +++ b/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js @@ -0,0 +1,71 @@ +/* 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/. */ + +function AutoCompleteTypeAheadResult(aValues, aFinalCompleteValues) { + this._values = aValues; + this._finalCompleteValues = aFinalCompleteValues; + this.defaultIndex = 0; + this._typeAheadResult = true; +} +AutoCompleteTypeAheadResult.prototype = Object.create(AutoCompleteResultBase.prototype); + +function AutoCompleteResult(aValues) { + this._values = aValues; +} +AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype); + +function AutoCompleteInput(aSearches) { + this.searches = aSearches; + this.popupOpen = true; + this.completeDefaultIndex = true; + this.completeSelectedIndex = true; +} +AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype); + +function run_test() { + run_next_test(); +} + +add_test(function test_handleEnter() { + doSearch("moz", function(aController) { + do_check_eq(aController.input.textValue, "mozilla.com"); + aController.handleEnter(true); + do_check_eq(aController.input.textValue, "mozilla.org"); + }); +}); + +function doSearch(aSearchString, aOnCompleteCallback) { + let typeAheadSearch = new AutoCompleteSearchBase( + "typeAheadSearch", + new AutoCompleteTypeAheadResult([ "mozilla.com" ], [ "http://www.mozilla.com" ]) + ); + registerAutoCompleteSearch(typeAheadSearch); + + let search = new AutoCompleteSearchBase( + "search", + new AutoCompleteResult([ "mozilla.org" ]) + ); + registerAutoCompleteSearch(search); + + let controller = Cc["@mozilla.org/autocomplete/controller;1"]. + getService(Ci.nsIAutoCompleteController); + + // Make an AutoCompleteInput that uses our searches and confirms results. + let input = new AutoCompleteInput([ typeAheadSearch.name, search.name ]); + input.textValue = aSearchString; + + // Caret must be at the end for autofill to happen. + let strLen = aSearchString.length; + input.selectTextRange(strLen, strLen); + controller.input = input; + controller.startSearch(aSearchString); + + input.onSearchComplete = function onSearchComplete() { + aOnCompleteCallback(controller); + + // Clean up. + unregisterAutoCompleteSearch(search); + run_next_test(); + }; +} diff --git a/toolkit/components/autocomplete/tests/unit/xpcshell.ini b/toolkit/components/autocomplete/tests/unit/xpcshell.ini index 4d193965c..daf89db17 100644 --- a/toolkit/components/autocomplete/tests/unit/xpcshell.ini +++ b/toolkit/components/autocomplete/tests/unit/xpcshell.ini @@ -18,7 +18,9 @@ tail = [test_finalCompleteValue_forceComplete.js] [test_finalCompleteValueSelectedIndex.js] [test_finalDefaultCompleteValue.js] +[test_hiddenResult.js] [test_immediate_search.js] [test_insertMatchAt.js] +[test_popupSelectionVsDefaultCompleteValue.js] [test_previousResult.js] [test_stopSearch.js] diff --git a/toolkit/components/filepicker/nsFileView.cpp b/toolkit/components/filepicker/nsFileView.cpp index ad4471e86..9a8278496 100644 --- a/toolkit/components/filepicker/nsFileView.cpp +++ b/toolkit/components/filepicker/nsFileView.cpp @@ -133,6 +133,13 @@ NS_IMETHODIMP nsFileResult::GetMatchCount(uint32_t *aMatchCount) return NS_OK; } +NS_IMETHODIMP nsFileResult::GetTypeAheadResult(bool *aTypeAheadResult) +{ + NS_ENSURE_ARG_POINTER(aTypeAheadResult); + *aTypeAheadResult = false; + return NS_OK; +} + NS_IMETHODIMP nsFileResult::GetValueAt(int32_t index, nsAString & aValue) { aValue = mValues[index]; diff --git a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm index 1c30599f5..7439d9d11 100644 --- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm +++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm @@ -530,20 +530,34 @@ this.DownloadIntegration = { * @return true if files should be marked */ _shouldSaveZoneInformation() { - let key = Cc["@mozilla.org/windows-registry-key;1"] - .createInstance(Ci.nsIWindowsRegKey); + let zonePref = 2; try { - key.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Attachments", - Ci.nsIWindowsRegKey.ACCESS_QUERY_VALUE); - try { - return key.readIntValue("SaveZoneInformation") != 1; - } finally { - key.close(); - } - } catch (ex) { - // If the key is not present, files should be marked by default. - return true; + zonePref = Services.prefs.getIntPref("browser.download.saveZoneInformation"); + } catch (ex) {} + + switch (zonePref) { + case 0: // Never + return false; + case 1: // Always + return true; + case 2: // System-defined + let key = Cc["@mozilla.org/windows-registry-key;1"] + .createInstance(Ci.nsIWindowsRegKey); + try { + key.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Attachments", + Ci.nsIWindowsRegKey.ACCESS_QUERY_VALUE); + try { + return key.readIntValue("SaveZoneInformation") != 1; + } finally { + key.close(); + } + } catch (ex) { + // If the key is not present, files should be marked by default. + return true; + } + default: // Invalid pref value defaults marking files. + return true; } }, #endif diff --git a/toolkit/components/places/moz.build b/toolkit/components/places/moz.build index adac79cba..85e1e93e1 100644 --- a/toolkit/components/places/moz.build +++ b/toolkit/components/places/moz.build @@ -78,6 +78,8 @@ if CONFIG['MOZ_PLACES']: EXTRA_COMPONENTS += [ 'ColorAnalyzer.js', 'nsLivemarkService.js', + 'nsPlacesAutoComplete.js', + 'nsPlacesAutoComplete.manifest', 'nsPlacesExpiration.js', 'nsTaggingService.js', 'PageIconProtocolHandler.js', diff --git a/toolkit/components/places/nsNavBookmarks.cpp b/toolkit/components/places/nsNavBookmarks.cpp index 74707be99..693aaf5db 100644 --- a/toolkit/components/places/nsNavBookmarks.cpp +++ b/toolkit/components/places/nsNavBookmarks.cpp @@ -2518,8 +2518,6 @@ nsNavBookmarks::GetURIForKeyword(const nsAString& aUserCasedKeyword, NS_ENSURE_TRUE(!aUserCasedKeyword.IsEmpty(), NS_ERROR_INVALID_ARG); *aURI = nullptr; - PLACES_WARN_DEPRECATED(); - // Shortcuts are always lowercased internally. nsAutoString keyword(aUserCasedKeyword); ToLowerCase(keyword); diff --git a/toolkit/components/places/nsNavHistory.cpp b/toolkit/components/places/nsNavHistory.cpp index 7f4007c1a..49d911d65 100644 --- a/toolkit/components/places/nsNavHistory.cpp +++ b/toolkit/components/places/nsNavHistory.cpp @@ -2796,8 +2796,6 @@ nsNavHistory::MarkPageAsFollowedLink(nsIURI *aURI) NS_IMETHODIMP nsNavHistory::GetPageTitle(nsIURI* aURI, nsAString& aTitle) { - PLACES_WARN_DEPRECATED(); - NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread"); NS_ENSURE_ARG(aURI); diff --git a/toolkit/components/places/nsPlacesAutoComplete.js b/toolkit/components/places/nsPlacesAutoComplete.js new file mode 100644 index 000000000..29bdae4c1 --- /dev/null +++ b/toolkit/components/places/nsPlacesAutoComplete.js @@ -0,0 +1,1778 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim: sw=2 ts=2 sts=2 expandtab + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch", + "resource://gre/modules/TelemetryStopwatch.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", + "resource://gre/modules/NetUtil.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", + "resource://gre/modules/Task.jsm"); + +//////////////////////////////////////////////////////////////////////////////// +//// Constants + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; + +// This SQL query fragment provides the following: +// - whether the entry is bookmarked (kQueryIndexBookmarked) +// - the bookmark title, if it is a bookmark (kQueryIndexBookmarkTitle) +// - the tags associated with a bookmarked entry (kQueryIndexTags) +const kBookTagSQLFragment = + `EXISTS(SELECT 1 FROM moz_bookmarks WHERE fk = h.id) AS bookmarked, + ( + SELECT title FROM moz_bookmarks WHERE fk = h.id AND title NOTNULL + ORDER BY lastModified DESC LIMIT 1 + ) AS btitle, + ( + SELECT GROUP_CONCAT(t.title, ',') + FROM moz_bookmarks b + JOIN moz_bookmarks t ON t.id = +b.parent AND t.parent = :parent + WHERE b.fk = h.id + ) AS tags`; + +// observer topics +const kTopicShutdown = "places-shutdown"; +const kPrefChanged = "nsPref:changed"; + +// Match type constants. These indicate what type of search function we should +// be using. +const MATCH_ANYWHERE = Ci.mozIPlacesAutoComplete.MATCH_ANYWHERE; +const MATCH_BOUNDARY_ANYWHERE = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY_ANYWHERE; +const MATCH_BOUNDARY = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY; +const MATCH_BEGINNING = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING; +const MATCH_BEGINNING_CASE_SENSITIVE = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING_CASE_SENSITIVE; + +// AutoComplete index constants. All AutoComplete queries will provide these +// columns in this order. +const kQueryIndexURL = 0; +const kQueryIndexTitle = 1; +const kQueryIndexFaviconURL = 2; +const kQueryIndexBookmarked = 3; +const kQueryIndexBookmarkTitle = 4; +const kQueryIndexTags = 5; +const kQueryIndexVisitCount = 6; +const kQueryIndexTyped = 7; +const kQueryIndexPlaceId = 8; +const kQueryIndexQueryType = 9; +const kQueryIndexOpenPageCount = 10; + +// AutoComplete query type constants. Describes the various types of queries +// that we can process. +const kQueryTypeKeyword = 0; +const kQueryTypeFiltered = 1; + +// This separator is used as an RTL-friendly way to split the title and tags. +// It can also be used by an nsIAutoCompleteResult consumer to re-split the +// "comment" back into the title and the tag. +const kTitleTagsSeparator = " \u2013 "; + +const kBrowserUrlbarBranch = "browser.urlbar."; +// Toggle autocomplete. +const kBrowserUrlbarAutocompleteEnabledPref = "autocomplete.enabled"; +// Toggle autoFill. +const kBrowserUrlbarAutofillPref = "autoFill"; +// Whether to search only typed entries. +const kBrowserUrlbarAutofillTypedPref = "autoFill.typed"; + +// The Telemetry histogram for urlInlineComplete query on domain +const DOMAIN_QUERY_TELEMETRY = "PLACES_AUTOCOMPLETE_URLINLINE_DOMAIN_QUERY_TIME_MS"; + +//////////////////////////////////////////////////////////////////////////////// +//// Globals + +XPCOMUtils.defineLazyServiceGetter(this, "gTextURIService", + "@mozilla.org/intl/texttosuburi;1", + "nsITextToSubURI"); + +//////////////////////////////////////////////////////////////////////////////// +//// Helpers + +/** + * Initializes our temporary table on a given database. + * + * @param aDatabase + * The mozIStorageConnection to set up the temp table on. + */ +function initTempTable(aDatabase) +{ + // Note: this should be kept up-to-date with the definition in + // nsPlacesTables.h. + let stmt = aDatabase.createAsyncStatement( + `CREATE TEMP TABLE moz_openpages_temp ( + url TEXT PRIMARY KEY + , open_count INTEGER + )` + ); + stmt.executeAsync(); + stmt.finalize(); + + // Note: this should be kept up-to-date with the definition in + // nsPlacesTriggers.h. + stmt = aDatabase.createAsyncStatement( + `CREATE TEMPORARY TRIGGER moz_openpages_temp_afterupdate_trigger + AFTER UPDATE OF open_count ON moz_openpages_temp FOR EACH ROW + WHEN NEW.open_count = 0 + BEGIN + DELETE FROM moz_openpages_temp + WHERE url = NEW.url; + END` + ); + stmt.executeAsync(); + stmt.finalize(); +} + +/** + * Used to unescape encoded URI strings, and drop information that we do not + * care about for searching. + * + * @param aURIString + * The text to unescape and modify. + * @return the modified uri. + */ +function fixupSearchText(aURIString) +{ + let uri = stripPrefix(aURIString); + return gTextURIService.unEscapeURIForUI("UTF-8", uri); +} + +/** + * Strip prefixes from the URI that we don't care about for searching. + * + * @param aURIString + * The text to modify. + * @return the modified uri. + */ +function stripPrefix(aURIString) +{ + let uri = aURIString; + + if (uri.indexOf("http://") == 0) { + uri = uri.slice(7); + } + else if (uri.indexOf("https://") == 0) { + uri = uri.slice(8); + } + else if (uri.indexOf("ftp://") == 0) { + uri = uri.slice(6); + } + + if (uri.indexOf("www.") == 0) { + uri = uri.slice(4); + } + return uri; +} + +/** + * safePrefGetter get the pref with type safety. + * This will return the default value provided if no pref is set. + * + * @param aPrefBranch + * The nsIPrefBranch containing the required preference + * @param aName + * A preference name + * @param aDefault + * The preference's default value + * @return the preference value or provided default + */ + +function safePrefGetter(aPrefBranch, aName, aDefault) { + let types = { + boolean: "Bool", + number: "Int", + string: "Char" + }; + let type = types[typeof(aDefault)]; + if (!type) { + throw "Unknown type!"; + } + + // If the pref isn't set, we want to use the default. + if (aPrefBranch.getPrefType(aName) == Ci.nsIPrefBranch.PREF_INVALID) { + return aDefault; + } + try { + return aPrefBranch["get" + type + "Pref"](aName); + } + catch (e) { + return aDefault; + } +} + +/** + * Whether UnifiedComplete is alive. + */ +function isUnifiedCompleteInstantiated() { + try { + return Components.manager.QueryInterface(Ci.nsIServiceManager) + .isServiceInstantiated(Cc["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"], + Ci.mozIPlacesAutoComplete); + } catch (ex) { + return false; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//// AutoCompleteStatementCallbackWrapper class + +/** + * Wraps a callback and ensures that handleCompletion is not dispatched if the + * query is no longer tracked. + * + * @param aAutocomplete + * A reference to a nsPlacesAutoComplete. + * @param aCallback + * A reference to a mozIStorageStatementCallback + * @param aDBConnection + * The database connection to execute the queries on. + */ +function AutoCompleteStatementCallbackWrapper(aAutocomplete, aCallback, + aDBConnection) +{ + this._autocomplete = aAutocomplete; + this._callback = aCallback; + this._db = aDBConnection; +} + +AutoCompleteStatementCallbackWrapper.prototype = { + ////////////////////////////////////////////////////////////////////////////// + //// mozIStorageStatementCallback + + handleResult: function ACSCW_handleResult(aResultSet) + { + this._callback.handleResult.apply(this._callback, arguments); + }, + + handleError: function ACSCW_handleError(aError) + { + this._callback.handleError.apply(this._callback, arguments); + }, + + handleCompletion: function ACSCW_handleCompletion(aReason) + { + // Only dispatch handleCompletion if we are not done searching and are a + // pending search. + if (!this._autocomplete.isSearchComplete() && + this._autocomplete.isPendingSearch(this._handle)) { + this._callback.handleCompletion.apply(this._callback, arguments); + } + }, + + ////////////////////////////////////////////////////////////////////////////// + //// AutoCompleteStatementCallbackWrapper + + /** + * Executes the specified query asynchronously. This object will notify + * this._callback if we should notify (logic explained in handleCompletion). + * + * @param aQueries + * The queries to execute asynchronously. + * @return a mozIStoragePendingStatement that can be used to cancel the + * queries. + */ + executeAsync: function ACSCW_executeAsync(aQueries) + { + return this._handle = this._db.executeAsync(aQueries, aQueries.length, + this); + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsISupports + + QueryInterface: XPCOMUtils.generateQI([ + Ci.mozIStorageStatementCallback, + ]) +}; + +//////////////////////////////////////////////////////////////////////////////// +//// nsPlacesAutoComplete class +//// @mozilla.org/autocomplete/search;1?name=history + +function nsPlacesAutoComplete() +{ + ////////////////////////////////////////////////////////////////////////////// + //// Shared Constants for Smart Getters + + // TODO bug 412736 in case of a frecency tie, break it with h.typed and + // h.visit_count which is better than nothing. This is slow, so not doing it + // yet... + function baseQuery(conditions = "") { + let query = `SELECT h.url, h.title, f.url, ${kBookTagSQLFragment}, + h.visit_count, h.typed, h.id, :query_type, + t.open_count + FROM moz_places h + LEFT JOIN moz_favicons f ON f.id = h.favicon_id + LEFT JOIN moz_openpages_temp t ON t.url = h.url + WHERE h.frecency <> 0 + AND AUTOCOMPLETE_MATCH(:searchString, h.url, + IFNULL(btitle, h.title), tags, + h.visit_count, h.typed, + bookmarked, t.open_count, + :matchBehavior, :searchBehavior) + ${conditions} + ORDER BY h.frecency DESC, h.id DESC + LIMIT :maxResults`; + return query; + } + + ////////////////////////////////////////////////////////////////////////////// + //// Smart Getters + + XPCOMUtils.defineLazyGetter(this, "_db", function() { + // Get a cloned, read-only version of the database. We'll only ever write + // to our own in-memory temp table, and having a cloned copy means we do not + // run the risk of our queries taking longer due to the main database + // connection performing a long-running task. + let db = PlacesUtils.history.DBConnection.clone(true); + + // Autocomplete often fallbacks to a table scan due to lack of text indices. + // In such cases a larger cache helps reducing IO. The default Storage + // value is MAX_CACHE_SIZE_BYTES in storage/mozStorageConnection.cpp. + let stmt = db.createAsyncStatement("PRAGMA cache_size = -6144"); // 6MiB + stmt.executeAsync(); + stmt.finalize(); + + // Create our in-memory tables for tab tracking. + initTempTable(db); + + // Populate the table with current open pages cache contents. + if (this._openPagesCache.length > 0) { + // Avoid getter re-entrance from the _registerOpenPageQuery lazy getter. + let stmt = this._registerOpenPageQuery = + db.createAsyncStatement(this._registerOpenPageQuerySQL); + let params = stmt.newBindingParamsArray(); + for (let i = 0; i < this._openPagesCache.length; i++) { + let bp = params.newBindingParams(); + bp.bindByName("page_url", this._openPagesCache[i]); + params.addParams(bp); + } + stmt.bindParameters(params); + stmt.executeAsync(); + stmt.finalize(); + delete this._openPagesCache; + } + + return db; + }); + + this._customQuery = (conditions = "") => { + return this._db.createAsyncStatement(baseQuery(conditions)); + }; + + XPCOMUtils.defineLazyGetter(this, "_defaultQuery", function() { + return this._db.createAsyncStatement(baseQuery()); + }); + + XPCOMUtils.defineLazyGetter(this, "_historyQuery", function() { + // Enforce ignoring the visit_count index, since the frecency one is much + // faster in this case. ANALYZE helps the query planner to figure out the + // faster path, but it may not have run yet. + return this._db.createAsyncStatement(baseQuery("AND +h.visit_count > 0")); + }); + + XPCOMUtils.defineLazyGetter(this, "_bookmarkQuery", function() { + return this._db.createAsyncStatement(baseQuery("AND bookmarked")); + }); + + XPCOMUtils.defineLazyGetter(this, "_tagsQuery", function() { + return this._db.createAsyncStatement(baseQuery("AND tags IS NOT NULL")); + }); + + XPCOMUtils.defineLazyGetter(this, "_openPagesQuery", function() { + return this._db.createAsyncStatement( + `SELECT t.url, t.url, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + :query_type, t.open_count, NULL + FROM moz_openpages_temp t + LEFT JOIN moz_places h ON h.url = t.url + WHERE h.id IS NULL + AND AUTOCOMPLETE_MATCH(:searchString, t.url, t.url, NULL, + NULL, NULL, NULL, t.open_count, + :matchBehavior, :searchBehavior) + ORDER BY t.ROWID DESC + LIMIT :maxResults` + ); + }); + + XPCOMUtils.defineLazyGetter(this, "_typedQuery", function() { + return this._db.createAsyncStatement(baseQuery("AND h.typed = 1")); + }); + + XPCOMUtils.defineLazyGetter(this, "_adaptiveQuery", function() { + return this._db.createAsyncStatement( + `/* do not warn (bug 487789) */ + SELECT h.url, h.title, f.url, ${kBookTagSQLFragment}, + h.visit_count, h.typed, h.id, :query_type, t.open_count + FROM ( + SELECT ROUND( + MAX(use_count) * (1 + (input = :search_string)), 1 + ) AS rank, place_id + FROM moz_inputhistory + WHERE input BETWEEN :search_string AND :search_string || X'FFFF' + GROUP BY place_id + ) AS i + JOIN moz_places h ON h.id = i.place_id + LEFT JOIN moz_favicons f ON f.id = h.favicon_id + LEFT JOIN moz_openpages_temp t ON t.url = h.url + WHERE AUTOCOMPLETE_MATCH(NULL, h.url, + IFNULL(btitle, h.title), tags, + h.visit_count, h.typed, bookmarked, + t.open_count, + :matchBehavior, :searchBehavior) + ORDER BY rank DESC, h.frecency DESC` + ); + }); + + XPCOMUtils.defineLazyGetter(this, "_keywordQuery", function() { + return this._db.createAsyncStatement( + `/* do not warn (bug 487787) */ + SELECT REPLACE(h.url, '%s', :query_string) AS search_url, h.title, + IFNULL(f.url, (SELECT f.url + FROM moz_places + JOIN moz_favicons f ON f.id = favicon_id + WHERE rev_host = h.rev_host + ORDER BY frecency DESC + LIMIT 1) + ), 1, NULL, NULL, h.visit_count, h.typed, h.id, + :query_type, t.open_count + FROM moz_keywords k + JOIN moz_places h ON k.place_id = h.id + LEFT JOIN moz_favicons f ON f.id = h.favicon_id + LEFT JOIN moz_openpages_temp t ON t.url = search_url + WHERE k.keyword = LOWER(:keyword)` + ); + }); + + this._registerOpenPageQuerySQL = + `INSERT OR REPLACE INTO moz_openpages_temp (url, open_count) + VALUES (:page_url, + IFNULL( + ( + SELECT open_count + 1 + FROM moz_openpages_temp + WHERE url = :page_url + ), + 1 + ) + )`; + XPCOMUtils.defineLazyGetter(this, "_registerOpenPageQuery", function() { + return this._db.createAsyncStatement(this._registerOpenPageQuerySQL); + }); + + XPCOMUtils.defineLazyGetter(this, "_unregisterOpenPageQuery", function() { + return this._db.createAsyncStatement( + `UPDATE moz_openpages_temp + SET open_count = open_count - 1 + WHERE url = :page_url` + ); + }); + + ////////////////////////////////////////////////////////////////////////////// + //// Initialization + + // load preferences + this._prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch(kBrowserUrlbarBranch); + this._syncEnabledPref(); + this._loadPrefs(true); + + // register observers + this._os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); + this._os.addObserver(this, kTopicShutdown, false); + +} + +nsPlacesAutoComplete.prototype = { + ////////////////////////////////////////////////////////////////////////////// + //// nsIAutoCompleteSearch + + startSearch: function PAC_startSearch(aSearchString, aSearchParam, + aPreviousResult, aListener) + { + // Stop the search in case the controller has not taken care of it. + this.stopSearch(); + + // Note: We don't use aPreviousResult to make sure ordering of results are + // consistent. See bug 412730 for more details. + + // We want to store the original string with no leading or trailing + // whitespace for case sensitive searches. + this._originalSearchString = aSearchString.trim(); + + this._currentSearchString = + fixupSearchText(this._originalSearchString.toLowerCase()); + + let params = new Set(aSearchParam.split(" ")); + this._enableActions = params.has("enable-actions"); + this._disablePrivateActions = params.has("disable-private-actions"); + + this._listener = aListener; + let result = Cc["@mozilla.org/autocomplete/simple-result;1"]. + createInstance(Ci.nsIAutoCompleteSimpleResult); + result.setSearchString(aSearchString); + result.setListener(this); + this._result = result; + + // If we are not enabled, we need to return now. + if (!this._enabled) { + this._finishSearch(true); + return; + } + + // Reset our search behavior to the default. + if (this._currentSearchString) { + this._behavior = this._defaultBehavior; + } + else { + this._behavior = this._emptySearchDefaultBehavior; + } + // For any given search, we run up to four queries: + // 1) keywords (this._keywordQuery) + // 2) adaptive learning (this._adaptiveQuery) + // 3) open pages not supported by history (this._openPagesQuery) + // 4) query from this._getSearch + // (1) only gets ran if we get any filtered tokens from this._getSearch, + // since if there are no tokens, there is nothing to match, so there is no + // reason to run the query). + let {query, tokens} = + this._getSearch(this._getUnfilteredSearchTokens(this._currentSearchString)); + let queries = tokens.length ? + [this._getBoundKeywordQuery(tokens), this._getBoundAdaptiveQuery()] : + [this._getBoundAdaptiveQuery()]; + + if (this._hasBehavior("openpage")) { + queries.push(this._getBoundOpenPagesQuery(tokens)); + } + queries.push(query); + + // Start executing our queries. + this._telemetryStartTime = Date.now(); + this._executeQueries(queries); + + // Set up our persistent state for the duration of the search. + this._searchTokens = tokens; + this._usedPlaces = {}; + }, + + stopSearch: function PAC_stopSearch() + { + // We need to cancel our searches so we do not get any [more] results. + // However, it's possible we haven't actually started any searches, so this + // method may throw because this._pendingQuery may be undefined. + if (this._pendingQuery) { + this._stopActiveQuery(); + } + + this._finishSearch(false); + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsIAutoCompleteSimpleResultListener + + onValueRemoved: function PAC_onValueRemoved(aResult, aURISpec, aRemoveFromDB) + { + if (aRemoveFromDB) { + PlacesUtils.history.removePage(NetUtil.newURI(aURISpec)); + } + }, + + ////////////////////////////////////////////////////////////////////////////// + //// mozIPlacesAutoComplete + + // If the connection has not yet been started, use this local cache. This + // prevents autocomplete from initing the database till the first search. + _openPagesCache: [], + registerOpenPage: function PAC_registerOpenPage(aURI) + { + if (!this._databaseInitialized) { + this._openPagesCache.push(aURI.spec); + return; + } + + let stmt = this._registerOpenPageQuery; + stmt.params.page_url = aURI.spec; + stmt.executeAsync(); + }, + + unregisterOpenPage: function PAC_unregisterOpenPage(aURI) + { + if (!this._databaseInitialized) { + let index = this._openPagesCache.indexOf(aURI.spec); + if (index != -1) { + this._openPagesCache.splice(index, 1); + } + return; + } + + let stmt = this._unregisterOpenPageQuery; + stmt.params.page_url = aURI.spec; + stmt.executeAsync(); + }, + + ////////////////////////////////////////////////////////////////////////////// + //// mozIStorageStatementCallback + + handleResult: function PAC_handleResult(aResultSet) + { + let row, haveMatches = false; + while ((row = aResultSet.getNextRow())) { + let match = this._processRow(row); + haveMatches = haveMatches || match; + + if (this._result.matchCount == this._maxRichResults) { + // We have enough results, so stop running our search. + this._stopActiveQuery(); + + // And finish our search. + this._finishSearch(true); + return; + } + + } + + // Notify about results if we've gotten them. + if (haveMatches) { + this._notifyResults(true); + } + }, + + handleError: function PAC_handleError(aError) + { + Components.utils.reportError("Places AutoComplete: An async statement encountered an " + + "error: " + aError.result + ", '" + aError.message + "'"); + }, + + handleCompletion: function PAC_handleCompletion(aReason) + { + // If we have already finished our search, we should bail out early. + if (this.isSearchComplete()) { + return; + } + + // If we do not have enough results, and our match type is + // MATCH_BOUNDARY_ANYWHERE, search again with MATCH_ANYWHERE to get more + // results. + if (this._matchBehavior == MATCH_BOUNDARY_ANYWHERE && + this._result.matchCount < this._maxRichResults && !this._secondPass) { + this._secondPass = true; + let queries = [ + this._getBoundAdaptiveQuery(MATCH_ANYWHERE), + this._getBoundSearchQuery(MATCH_ANYWHERE, this._searchTokens), + ]; + this._executeQueries(queries); + return; + } + + this._finishSearch(true); + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsIObserver + + observe: function PAC_observe(aSubject, aTopic, aData) + { + if (aTopic == kTopicShutdown) { + this._os.removeObserver(this, kTopicShutdown); + + // Remove our preference observer. + this._prefs.removeObserver("", this); + delete this._prefs; + + // Finalize the statements that we have used. + let stmts = [ + "_defaultQuery", + "_historyQuery", + "_bookmarkQuery", + "_tagsQuery", + "_openPagesQuery", + "_typedQuery", + "_adaptiveQuery", + "_keywordQuery", + "_registerOpenPageQuery", + "_unregisterOpenPageQuery", + ]; + for (let i = 0; i < stmts.length; i++) { + // We do not want to create any query we haven't already created, so + // see if it is a getter first. + if (Object.getOwnPropertyDescriptor(this, stmts[i]).value !== undefined) { + this[stmts[i]].finalize(); + } + } + + if (this._databaseInitialized) { + this._db.asyncClose(); + } + } + else if (aTopic == kPrefChanged) { + // Avoid re-entrancy when flipping linked preferences. + if (this._ignoreNotifications) + return; + this._ignoreNotifications = true; + this._loadPrefs(false, aTopic, aData); + this._ignoreNotifications = false; + } + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsPlacesAutoComplete + + get _databaseInitialized() { + return Object.getOwnPropertyDescriptor(this, "_db").value !== undefined; + }, + + /** + * Generates the tokens used in searching from a given string. + * + * @param aSearchString + * The string to generate tokens from. + * @return an array of tokens. + */ + _getUnfilteredSearchTokens: function PAC_unfilteredSearchTokens(aSearchString) + { + // Calling split on an empty string will return an array containing one + // empty string. We don't want that, as it'll break our logic, so return an + // empty array then. + return aSearchString.length ? aSearchString.split(" ") : []; + }, + + /** + * Properly cleans up when searching is completed. + * + * @param aNotify + * Indicates if we should notify the AutoComplete listener about our + * results or not. + */ + _finishSearch: function PAC_finishSearch(aNotify) + { + // Notify about results if we are supposed to. + if (aNotify) { + this._notifyResults(false); + } + + // Clear our state + delete this._originalSearchString; + delete this._currentSearchString; + delete this._strippedPrefix; + delete this._searchTokens; + delete this._listener; + delete this._result; + delete this._usedPlaces; + delete this._pendingQuery; + this._secondPass = false; + this._enableActions = false; + }, + + /** + * Executes the given queries asynchronously. + * + * @param aQueries + * The queries to execute. + */ + _executeQueries: function PAC_executeQueries(aQueries) + { + // Because we might get a handleCompletion for canceled queries, we want to + // filter out queries we no longer care about (described in the + // handleCompletion implementation of AutoCompleteStatementCallbackWrapper). + + // Create our wrapper object and execute the queries. + let wrapper = new AutoCompleteStatementCallbackWrapper(this, this, this._db); + this._pendingQuery = wrapper.executeAsync(aQueries); + }, + + /** + * Stops executing our active query. + */ + _stopActiveQuery: function PAC_stopActiveQuery() + { + this._pendingQuery.cancel(); + delete this._pendingQuery; + }, + + /** + * Notifies the listener about results. + * + * @param aSearchOngoing + * Indicates if the search is ongoing or not. + */ + _notifyResults: function PAC_notifyResults(aSearchOngoing) + { + let result = this._result; + let resultCode = result.matchCount ? "RESULT_SUCCESS" : "RESULT_NOMATCH"; + if (aSearchOngoing) { + resultCode += "_ONGOING"; + } + result.setSearchResult(Ci.nsIAutoCompleteResult[resultCode]); + this._listener.onSearchResult(this, result); + if (this._telemetryStartTime) { + let elapsed = Date.now() - this._telemetryStartTime; + if (elapsed > 50) { + try { + Services.telemetry + .getHistogramById("PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS") + .add(elapsed); + } catch (ex) { + Components.utils.reportError("Unable to report telemetry."); + } + } + this._telemetryStartTime = null; + } + }, + + /** + * Synchronize suggest.* prefs with autocomplete.enabled. + */ + _syncEnabledPref: function PAC_syncEnabledPref() + { + let suggestPrefs = ["suggest.history", "suggest.bookmark", "suggest.openpage"]; + let types = ["History", "Bookmark", "Openpage"]; + + this._enabled = safePrefGetter(this._prefs, kBrowserUrlbarAutocompleteEnabledPref, + true); + this._suggestHistory = safePrefGetter(this._prefs, "suggest.history", true); + this._suggestBookmark = safePrefGetter(this._prefs, "suggest.bookmark", true); + this._suggestOpenpage = safePrefGetter(this._prefs, "suggest.openpage", true); + + if (this._enabled) { + // If the autocomplete preference is active, activate all suggest + // preferences only if all of them are false. + if (types.every(type => this["_suggest" + type] == false)) { + for (let type of suggestPrefs) { + this._prefs.setBoolPref(type, true); + } + } + } else { + // If the preference was deactivated, deactivate all suggest preferences. + for (let type of suggestPrefs) { + this._prefs.setBoolPref(type, false); + } + } + }, + + /** + * Loads the preferences that we care about. + * + * @param [optional] aRegisterObserver + * Indicates if the preference observer should be added or not. The + * default value is false. + * @param [optional] aTopic + * Observer's topic, if any. + * @param [optional] aSubject + * Observer's subject, if any. + */ + _loadPrefs: function PAC_loadPrefs(aRegisterObserver, aTopic, aData) + { + // Avoid race conditions with UnifiedComplete component. + if (aData && !isUnifiedCompleteInstantiated()) { + // Synchronize suggest.* prefs with autocomplete.enabled. + if (aData == kBrowserUrlbarAutocompleteEnabledPref) { + this._syncEnabledPref(); + } else if (aData.startsWith("suggest.")) { + let suggestPrefs = ["suggest.history", "suggest.bookmark", "suggest.openpage"]; + this._prefs.setBoolPref(kBrowserUrlbarAutocompleteEnabledPref, + suggestPrefs.some(pref => safePrefGetter(this._prefs, pref, true))); + } + } + + this._enabled = safePrefGetter(this._prefs, + kBrowserUrlbarAutocompleteEnabledPref, + true); + this._matchBehavior = safePrefGetter(this._prefs, + "matchBehavior", + MATCH_BOUNDARY_ANYWHERE); + this._filterJavaScript = safePrefGetter(this._prefs, "filter.javascript", true); + this._maxRichResults = safePrefGetter(this._prefs, "maxRichResults", 25); + this._restrictHistoryToken = safePrefGetter(this._prefs, + "restrict.history", "^"); + this._restrictBookmarkToken = safePrefGetter(this._prefs, + "restrict.bookmark", "*"); + this._restrictTypedToken = safePrefGetter(this._prefs, "restrict.typed", "~"); + this._restrictTagToken = safePrefGetter(this._prefs, "restrict.tag", "+"); + this._restrictOpenPageToken = safePrefGetter(this._prefs, + "restrict.openpage", "%"); + this._matchTitleToken = safePrefGetter(this._prefs, "match.title", "#"); + this._matchURLToken = safePrefGetter(this._prefs, "match.url", "@"); + + this._suggestHistory = safePrefGetter(this._prefs, "suggest.history", true); + this._suggestBookmark = safePrefGetter(this._prefs, "suggest.bookmark", true); + this._suggestOpenpage = safePrefGetter(this._prefs, "suggest.openpage", true); + this._suggestTyped = safePrefGetter(this._prefs, "suggest.history.onlyTyped", false); + + // If history is not set, onlyTyped value should be ignored. + if (!this._suggestHistory) { + this._suggestTyped = false; + } + let types = ["History", "Bookmark", "Openpage", "Typed"]; + this._defaultBehavior = types.reduce((memo, type) => { + let prefValue = this["_suggest" + type]; + return memo | (prefValue && + Ci.mozIPlacesAutoComplete["BEHAVIOR_" + type.toUpperCase()]); + }, 0); + + // Further restrictions to apply for "empty searches" (i.e. searches for ""). + // The empty behavior is typed history, if history is enabled. Otherwise, + // it is bookmarks, if they are enabled. If both history and bookmarks are disabled, + // it defaults to open pages. + this._emptySearchDefaultBehavior = Ci.mozIPlacesAutoComplete.BEHAVIOR_RESTRICT; + if (this._suggestHistory) { + this._emptySearchDefaultBehavior |= Ci.mozIPlacesAutoComplete.BEHAVIOR_HISTORY | + Ci.mozIPlacesAutoComplete.BEHAVIOR_TYPED; + } else if (this._suggestBookmark) { + this._emptySearchDefaultBehavior |= Ci.mozIPlacesAutoComplete.BEHAVIOR_BOOKMARK; + } else { + this._emptySearchDefaultBehavior |= Ci.mozIPlacesAutoComplete.BEHAVIOR_OPENPAGE; + } + + // Validate matchBehavior; default to MATCH_BOUNDARY_ANYWHERE. + if (this._matchBehavior != MATCH_ANYWHERE && + this._matchBehavior != MATCH_BOUNDARY && + this._matchBehavior != MATCH_BEGINNING) { + this._matchBehavior = MATCH_BOUNDARY_ANYWHERE; + } + // register observer + if (aRegisterObserver) { + this._prefs.addObserver("", this, false); + } + }, + + /** + * Given an array of tokens, this function determines which query should be + * ran. It also removes any special search tokens. + * + * @param aTokens + * An array of search tokens. + * @return an object with two properties: + * query: the correctly optimized, bound query to search the database + * with. + * tokens: the filtered list of tokens to search with. + */ + _getSearch: function PAC_getSearch(aTokens) + { + let foundToken = false; + let restrict = (behavior) => { + if (!foundToken) { + this._behavior = 0; + this._setBehavior("restrict"); + foundToken = true; + } + this._setBehavior(behavior); + }; + + // Set the proper behavior so our call to _getBoundSearchQuery gives us the + // correct query. + for (let i = aTokens.length - 1; i >= 0; i--) { + switch (aTokens[i]) { + case this._restrictHistoryToken: + restrict("history"); + break; + case this._restrictBookmarkToken: + restrict("bookmark"); + break; + case this._restrictTagToken: + restrict("tag"); + break; + case this._restrictOpenPageToken: + if (!this._enableActions) { + continue; + } + restrict("openpage"); + break; + case this._matchTitleToken: + restrict("title"); + break; + case this._matchURLToken: + restrict("url"); + break; + case this._restrictTypedToken: + restrict("typed"); + break; + default: + // We do not want to remove the token if we did not match. + continue; + } + + aTokens.splice(i, 1); + } + + // Set the right JavaScript behavior based on our preference. Note that the + // preference is whether or not we should filter JavaScript, and the + // behavior is if we should search it or not. + if (!this._filterJavaScript) { + this._setBehavior("javascript"); + } + + return { + query: this._getBoundSearchQuery(this._matchBehavior, aTokens), + tokens: aTokens + }; + }, + + /** + * @return a string consisting of the search query to be used based on the + * previously set urlbar suggestion preferences. + */ + _getSuggestionPrefQuery: function PAC_getSuggestionPrefQuery() + { + if (!this._hasBehavior("restrict") && this._hasBehavior("history") && + this._hasBehavior("bookmark")) { + return this._hasBehavior("typed") ? this._customQuery("AND h.typed = 1") + : this._defaultQuery; + } + let conditions = []; + if (this._hasBehavior("history")) { + // Enforce ignoring the visit_count index, since the frecency one is much + // faster in this case. ANALYZE helps the query planner to figure out the + // faster path, but it may not have up-to-date information yet. + conditions.push("+h.visit_count > 0"); + } + if (this._hasBehavior("typed")) { + conditions.push("h.typed = 1"); + } + if (this._hasBehavior("bookmark")) { + conditions.push("bookmarked"); + } + if (this._hasBehavior("tag")) { + conditions.push("tags NOTNULL"); + } + + return conditions.length ? this._customQuery("AND " + conditions.join(" AND ")) + : this._defaultQuery; + }, + + /** + * Obtains the search query to be used based on the previously set search + * behaviors (accessed by this._hasBehavior). The query is bound and ready to + * execute. + * + * @param aMatchBehavior + * How this query should match its tokens to the search string. + * @param aTokens + * An array of search tokens. + * @return the correctly optimized query to search the database with and the + * new list of tokens to search with. The query has all the needed + * parameters bound, so consumers can execute it without doing any + * additional work. + */ + _getBoundSearchQuery: function PAC_getBoundSearchQuery(aMatchBehavior, + aTokens) + { + let query = this._getSuggestionPrefQuery(); + + // Bind the needed parameters to the query so consumers can use it. + let params = query.params; + params.parent = PlacesUtils.tagsFolderId; + params.query_type = kQueryTypeFiltered; + params.matchBehavior = aMatchBehavior; + params.searchBehavior = this._behavior; + + // We only want to search the tokens that we are left with - not the + // original search string. + params.searchString = aTokens.join(" "); + + // Limit the query to the the maximum number of desired results. + // This way we can avoid doing more work than needed. + params.maxResults = this._maxRichResults; + + return query; + }, + + _getBoundOpenPagesQuery: function PAC_getBoundOpenPagesQuery(aTokens) + { + let query = this._openPagesQuery; + + // Bind the needed parameters to the query so consumers can use it. + let params = query.params; + params.query_type = kQueryTypeFiltered; + params.matchBehavior = this._matchBehavior; + params.searchBehavior = this._behavior; + + // We only want to search the tokens that we are left with - not the + // original search string. + params.searchString = aTokens.join(" "); + params.maxResults = this._maxRichResults; + + return query; + }, + + /** + * Obtains the keyword query with the properly bound parameters. + * + * @param aTokens + * The array of search tokens to check against. + * @return the bound keyword query. + */ + _getBoundKeywordQuery: function PAC_getBoundKeywordQuery(aTokens) + { + // The keyword is the first word in the search string, with the parameters + // following it. + let searchString = this._originalSearchString; + let queryString = ""; + let queryIndex = searchString.indexOf(" "); + if (queryIndex != -1) { + queryString = searchString.substring(queryIndex + 1); + } + // We need to escape the parameters as if they were the query in a URL + queryString = encodeURIComponent(queryString).replace(/%20/g, "+"); + + // The first word could be a keyword, so that's what we'll search. + let keyword = aTokens[0]; + + let query = this._keywordQuery; + let params = query.params; + params.keyword = keyword; + params.query_string = queryString; + params.query_type = kQueryTypeKeyword; + + return query; + }, + + /** + * Obtains the adaptive query with the properly bound parameters. + * + * @return the bound adaptive query. + */ + _getBoundAdaptiveQuery: function PAC_getBoundAdaptiveQuery(aMatchBehavior) + { + // If we were not given a match behavior, use the stored match behavior. + if (arguments.length == 0) { + aMatchBehavior = this._matchBehavior; + } + + let query = this._adaptiveQuery; + let params = query.params; + params.parent = PlacesUtils.tagsFolderId; + params.search_string = this._currentSearchString; + params.query_type = kQueryTypeFiltered; + params.matchBehavior = aMatchBehavior; + params.searchBehavior = this._behavior; + + return query; + }, + + /** + * Processes a mozIStorageRow to generate the proper data for the AutoComplete + * result. This will add an entry to the current result if it matches the + * criteria. + * + * @param aRow + * The row to process. + * @return true if the row is accepted, and false if not. + */ + _processRow: function PAC_processRow(aRow) + { + // Before we do any work, make sure this entry isn't already in our results. + let entryId = aRow.getResultByIndex(kQueryIndexPlaceId); + let escapedEntryURL = aRow.getResultByIndex(kQueryIndexURL); + let openPageCount = aRow.getResultByIndex(kQueryIndexOpenPageCount) || 0; + + // If actions are enabled and the page is open, add only the switch-to-tab + // result. Otherwise, add the normal result. + let [url, action] = this._enableActions && openPageCount > 0 && this._hasBehavior("openpage") ? + ["moz-action:switchtab," + escapedEntryURL, "action "] : + [escapedEntryURL, ""]; + + if (this._inResults(entryId, url)) { + return false; + } + + let entryTitle = aRow.getResultByIndex(kQueryIndexTitle) || ""; + let entryFavicon = aRow.getResultByIndex(kQueryIndexFaviconURL) || ""; + let entryBookmarked = aRow.getResultByIndex(kQueryIndexBookmarked); + let entryBookmarkTitle = entryBookmarked ? + aRow.getResultByIndex(kQueryIndexBookmarkTitle) : null; + let entryTags = aRow.getResultByIndex(kQueryIndexTags) || ""; + + // Always prefer the bookmark title unless it is empty + let title = entryBookmarkTitle || entryTitle; + + let style; + if (aRow.getResultByIndex(kQueryIndexQueryType) == kQueryTypeKeyword) { + style = "keyword"; + title = NetUtil.newURI(escapedEntryURL).host; + } + + // We will always prefer to show tags if we have them. + let showTags = !!entryTags; + + // However, we'll act as if a page is not bookmarked if the user wants + // only history and not bookmarks and there are no tags. + if (this._hasBehavior("history") && !this._hasBehavior("bookmark") && + !showTags) { + showTags = false; + style = "favicon"; + } + + // If we have tags and should show them, we need to add them to the title. + if (showTags) { + title += kTitleTagsSeparator + entryTags; + } + // We have to determine the right style to display. Tags show the tag icon, + // bookmarks get the bookmark icon, and keywords get the keyword icon. If + // the result does not fall into any of those, it just gets the favicon. + if (!style) { + // It is possible that we already have a style set (from a keyword + // search or because of the user's preferences), so only set it if we + // haven't already done so. + if (showTags) { + style = "tag"; + } + else if (entryBookmarked) { + style = "bookmark"; + } + else { + style = "favicon"; + } + } + + this._addToResults(entryId, url, title, entryFavicon, action + style); + return true; + }, + + /** + * Checks to see if the given place has already been added to the results. + * + * @param aPlaceId + * The place id to check for, may be null. + * @param aUrl + * The url to check for. + * @return true if the place has been added, false otherwise. + * + * @note Must check both the id and the url for a negative match, since + * autocomplete may run in the middle of a new page addition. In such + * a case the switch-to-tab query would hash the page by url, then a + * next query, running after the page addition, would hash it by id. + * It's not possible to just rely on url though, since keywords + * dynamically modify the url to include their search string. + */ + _inResults: function PAC_inResults(aPlaceId, aUrl) + { + if (aPlaceId && aPlaceId in this._usedPlaces) { + return true; + } + return aUrl in this._usedPlaces; + }, + + /** + * Adds a result to the AutoComplete results. Also tracks that we've added + * this place_id into the result set. + * + * @param aPlaceId + * The place_id of the item to be added to the result set. This is + * used by _inResults. + * @param aURISpec + * The URI spec for the entry. + * @param aTitle + * The title to give the entry. + * @param aFaviconSpec + * The favicon to give to the entry. + * @param aStyle + * Indicates how the entry should be styled when displayed. + */ + _addToResults: function PAC_addToResults(aPlaceId, aURISpec, aTitle, + aFaviconSpec, aStyle) + { + // Add this to our internal tracker to ensure duplicates do not end up in + // the result. _usedPlaces is an Object that is being used as a set. + // Not all entries have a place id, thus we fallback to the url for them. + // We cannot use only the url since keywords entries are modified to + // include the search string, and would be returned multiple times. Ids + // are faster too. + this._usedPlaces[aPlaceId || aURISpec] = true; + + // Obtain the favicon for this URI. + let favicon; + if (aFaviconSpec) { + let uri = NetUtil.newURI(aFaviconSpec); + favicon = PlacesUtils.favicons.getFaviconLinkForIcon(uri).spec; + } + favicon = favicon || PlacesUtils.favicons.defaultFavicon.spec; + + this._result.appendMatch(aURISpec, aTitle, favicon, aStyle); + }, + + /** + * Determines if the specified AutoComplete behavior is set. + * + * @param aType + * The behavior type to test for. + * @return true if the behavior is set, false otherwise. + */ + _hasBehavior: function PAC_hasBehavior(aType) + { + let behavior = Ci.mozIPlacesAutoComplete["BEHAVIOR_" + aType.toUpperCase()]; + + if (this._disablePrivateActions && + behavior == Ci.mozIPlacesAutoComplete.BEHAVIOR_OPENPAGE) { + return false; + } + + return this._behavior & behavior; + }, + + /** + * Enables the desired AutoComplete behavior. + * + * @param aType + * The behavior type to set. + */ + _setBehavior: function PAC_setBehavior(aType) + { + this._behavior |= + Ci.mozIPlacesAutoComplete["BEHAVIOR_" + aType.toUpperCase()]; + }, + + /** + * Determines if we are done searching or not. + * + * @return true if we have completed searching, false otherwise. + */ + isSearchComplete: function PAC_isSearchComplete() + { + // If _pendingQuery is null, we should no longer do any work since we have + // already called _finishSearch. This means we completed our search. + return this._pendingQuery == null; + }, + + /** + * Determines if the given handle of a pending statement is a pending search + * or not. + * + * @param aHandle + * A mozIStoragePendingStatement to check and see if we are waiting for + * results from it still. + * @return true if it is a pending query, false otherwise. + */ + isPendingSearch: function PAC_isPendingSearch(aHandle) + { + return this._pendingQuery == aHandle; + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsISupports + + classID: Components.ID("d0272978-beab-4adc-a3d4-04b76acfa4e7"), + + _xpcom_factory: XPCOMUtils.generateSingletonFactory(nsPlacesAutoComplete), + + QueryInterface: XPCOMUtils.generateQI([ + Ci.nsIAutoCompleteSearch, + Ci.nsIAutoCompleteSimpleResultListener, + Ci.mozIPlacesAutoComplete, + Ci.mozIStorageStatementCallback, + Ci.nsIObserver, + Ci.nsISupportsWeakReference, + ]) +}; + +//////////////////////////////////////////////////////////////////////////////// +//// urlInlineComplete class +//// component @mozilla.org/autocomplete/search;1?name=urlinline + +function urlInlineComplete() +{ + this._loadPrefs(true); + Services.obs.addObserver(this, kTopicShutdown, true); +} + +urlInlineComplete.prototype = { + +///////////////////////////////////////////////////////////////////////////////// +//// Database and query getters + + __db: null, + + get _db() + { + if (!this.__db && this._autofillEnabled) { + this.__db = PlacesUtils.history.DBConnection.clone(true); + } + return this.__db; + }, + + __hostQuery: null, + + get _hostQuery() + { + if (!this.__hostQuery) { + // Add a trailing slash at the end of the hostname, since we always + // want to complete up to and including a URL separator. + this.__hostQuery = this._db.createAsyncStatement( + `/* do not warn (bug no): could index on (typed,frecency) but not worth it */ + SELECT host || '/', prefix || host || '/' + FROM moz_hosts + WHERE host BETWEEN :search_string AND :search_string || X'FFFF' + AND frecency <> 0 + ${this._autofillTyped ? "AND typed = 1" : ""} + ORDER BY frecency DESC + LIMIT 1` + ); + } + return this.__hostQuery; + }, + + __urlQuery: null, + + get _urlQuery() + { + if (!this.__urlQuery) { + this.__urlQuery = this._db.createAsyncStatement( + `/* do not warn (bug no): can't use an index */ + SELECT h.url + FROM moz_places h + WHERE h.frecency <> 0 + ${this._autofillTyped ? "AND h.typed = 1 " : ""} + AND AUTOCOMPLETE_MATCH(:searchString, h.url, + h.title, '', + h.visit_count, h.typed, 0, 0, + :matchBehavior, :searchBehavior) + ORDER BY h.frecency DESC, h.id DESC + LIMIT 1` + ); + } + return this.__urlQuery; + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsIAutoCompleteSearch + + startSearch: function UIC_startSearch(aSearchString, aSearchParam, + aPreviousResult, aListener) + { + // Stop the search in case the controller has not taken care of it. + if (this._pendingQuery) { + this.stopSearch(); + } + + let pendingSearch = this._pendingSearch = {}; + + // We want to store the original string with no leading or trailing + // whitespace for case sensitive searches. + this._originalSearchString = aSearchString; + this._currentSearchString = + fixupSearchText(this._originalSearchString.toLowerCase()); + // The protocol and the host are lowercased by nsIURI, so it's fine to + // lowercase the typed prefix to add it back to the results later. + this._strippedPrefix = this._originalSearchString.slice( + 0, this._originalSearchString.length - this._currentSearchString.length + ).toLowerCase(); + + this._result = Cc["@mozilla.org/autocomplete/simple-result;1"]. + createInstance(Ci.nsIAutoCompleteSimpleResult); + this._result.setSearchString(aSearchString); + this._result.setTypeAheadResult(true); + + this._listener = aListener; + + Task.spawn(function* () { + // Don't autoFill if the search term is recognized as a keyword, otherwise + // it will override default keywords behavior. Note that keywords are + // hashed on first use, so while the first query may delay a little bit, + // next ones will just hit the memory hash. + let dontAutoFill = this._currentSearchString.length == 0 || !this._db || + (yield PlacesUtils.keywords.fetch(this._currentSearchString)); + if (this._pendingSearch != pendingSearch) + return; + if (dontAutoFill) { + this._finishSearch(); + return; + } + + // Don't try to autofill if the search term includes any whitespace. + // This may confuse completeDefaultIndex cause the AUTOCOMPLETE_MATCH + // tokenizer ends up trimming the search string and returning a value + // that doesn't match it, or is even shorter. + if (/\s/.test(this._currentSearchString)) { + this._finishSearch(); + return; + } + + // Hosts have no "/" in them. + let lastSlashIndex = this._currentSearchString.lastIndexOf("/"); + + // Search only URLs if there's a slash in the search string... + if (lastSlashIndex != -1) { + // ...but not if it's exactly at the end of the search string. + if (lastSlashIndex < this._currentSearchString.length - 1) + this._queryURL(); + else + this._finishSearch(); + return; + } + + // Do a synchronous search on the table of hosts. + let query = this._hostQuery; + query.params.search_string = this._currentSearchString.toLowerCase(); + // This is just to measure the delay to reach the UI, not the query time. + TelemetryStopwatch.start(DOMAIN_QUERY_TELEMETRY); + let wrapper = new AutoCompleteStatementCallbackWrapper(this, { + handleResult: aResultSet => { + if (this._pendingSearch != pendingSearch) + return; + let row = aResultSet.getNextRow(); + let trimmedHost = row.getResultByIndex(0); + let untrimmedHost = row.getResultByIndex(1); + // If the untrimmed value doesn't preserve the user's input just + // ignore it and complete to the found host. + if (untrimmedHost && + !untrimmedHost.toLowerCase().includes(this._originalSearchString.toLowerCase())) { + untrimmedHost = null; + } + + this._result.appendMatch(this._strippedPrefix + trimmedHost, "", "", "", untrimmedHost); + + // handleCompletion() will cause the result listener to be called, and + // will display the result in the UI. + }, + + handleError: aError => { + Components.utils.reportError( + "URL Inline Complete: An async statement encountered an " + + "error: " + aError.result + ", '" + aError.message + "'"); + }, + + handleCompletion: aReason => { + if (this._pendingSearch != pendingSearch) + return; + TelemetryStopwatch.finish(DOMAIN_QUERY_TELEMETRY); + this._finishSearch(); + } + }, this._db); + this._pendingQuery = wrapper.executeAsync([query]); + }.bind(this)); + }, + + /** + * Execute an asynchronous search through places, and complete + * up to the next URL separator. + */ + _queryURL: function UIC__queryURL() + { + // The URIs in the database are fixed up, so we can match on a lowercased + // host, but the path must be matched in a case sensitive way. + let pathIndex = + this._originalSearchString.indexOf("/", this._strippedPrefix.length); + this._currentSearchString = fixupSearchText( + this._originalSearchString.slice(0, pathIndex).toLowerCase() + + this._originalSearchString.slice(pathIndex) + ); + + // Within the standard autocomplete query, we only search the beginning + // of URLs for 1 result. + let query = this._urlQuery; + let params = query.params; + params.matchBehavior = MATCH_BEGINNING_CASE_SENSITIVE; + params.searchBehavior |= Ci.mozIPlacesAutoComplete.BEHAVIOR_HISTORY | + Ci.mozIPlacesAutoComplete.BEHAVIOR_TYPED | + Ci.mozIPlacesAutoComplete.BEHAVIOR_URL; + params.searchString = this._currentSearchString; + + // Execute the query. + let wrapper = new AutoCompleteStatementCallbackWrapper(this, { + handleResult: aResultSet => { + let row = aResultSet.getNextRow(); + let value = row.getResultByIndex(0); + let url = fixupSearchText(value); + + let prefix = value.slice(0, value.length - stripPrefix(value).length); + + // We must complete the URL up to the next separator (which is /, ? or #). + let separatorIndex = url.slice(this._currentSearchString.length) + .search(/[\/\?\#]/); + if (separatorIndex != -1) { + separatorIndex += this._currentSearchString.length; + if (url[separatorIndex] == "/") { + separatorIndex++; // Include the "/" separator + } + url = url.slice(0, separatorIndex); + } + + // Add the result. + // If the untrimmed value doesn't preserve the user's input just + // ignore it and complete to the found url. + let untrimmedURL = prefix + url; + if (untrimmedURL && + !untrimmedURL.toLowerCase().includes(this._originalSearchString.toLowerCase())) { + untrimmedURL = null; + } + + this._result.appendMatch(this._strippedPrefix + url, "", "", "", untrimmedURL); + + // handleCompletion() will cause the result listener to be called, and + // will display the result in the UI. + }, + + handleError: aError => { + Components.utils.reportError( + "URL Inline Complete: An async statement encountered an " + + "error: " + aError.result + ", '" + aError.message + "'"); + }, + + handleCompletion: aReason => { + this._finishSearch(); + } + }, this._db); + this._pendingQuery = wrapper.executeAsync([query]); + }, + + stopSearch: function UIC_stopSearch() + { + delete this._originalSearchString; + delete this._currentSearchString; + delete this._result; + delete this._listener; + delete this._pendingSearch; + + if (this._pendingQuery) { + this._pendingQuery.cancel(); + delete this._pendingQuery; + } + }, + + /** + * Loads the preferences that we care about. + * + * @param [optional] aRegisterObserver + * Indicates if the preference observer should be added or not. The + * default value is false. + */ + _loadPrefs: function UIC_loadPrefs(aRegisterObserver) + { + let prefBranch = Services.prefs.getBranch(kBrowserUrlbarBranch); + let autocomplete = safePrefGetter(prefBranch, + kBrowserUrlbarAutocompleteEnabledPref, + true); + let autofill = safePrefGetter(prefBranch, + kBrowserUrlbarAutofillPref, + true); + this._autofillEnabled = autocomplete && autofill; + this._autofillTyped = safePrefGetter(prefBranch, + kBrowserUrlbarAutofillTypedPref, + true); + if (aRegisterObserver) { + Services.prefs.addObserver(kBrowserUrlbarBranch, this, true); + } + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsIAutoCompleteSearchDescriptor + + get searchType() { + return Ci.nsIAutoCompleteSearchDescriptor.SEARCH_TYPE_IMMEDIATE; + }, + + get clearingAutoFillSearchesAgain() { + return false; + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsIObserver + + observe: function UIC_observe(aSubject, aTopic, aData) + { + if (aTopic == kTopicShutdown) { + this._closeDatabase(); + } + else if (aTopic == kPrefChanged && + (aData.substr(kBrowserUrlbarBranch.length) == kBrowserUrlbarAutofillPref || + aData.substr(kBrowserUrlbarBranch.length) == kBrowserUrlbarAutocompleteEnabledPref || + aData.substr(kBrowserUrlbarBranch.length) == kBrowserUrlbarAutofillTypedPref)) { + let previousAutofillTyped = this._autofillTyped; + this._loadPrefs(); + if (!this._autofillEnabled) { + this.stopSearch(); + this._closeDatabase(); + } + else if (this._autofillTyped != previousAutofillTyped) { + // Invalidate the statements to update them for the new typed status. + this._invalidateStatements(); + } + } + }, + + /** + * Finalizes and invalidates cached statements. + */ + _invalidateStatements: function UIC_invalidateStatements() + { + // Finalize the statements that we have used. + let stmts = [ + "__hostQuery", + "__urlQuery", + ]; + for (let i = 0; i < stmts.length; i++) { + // We do not want to create any query we haven't already created, so + // see if it is a getter first. + if (this[stmts[i]]) { + this[stmts[i]].finalize(); + this[stmts[i]] = null; + } + } + }, + + /** + * Closes the database. + */ + _closeDatabase: function UIC_closeDatabase() + { + this._invalidateStatements(); + if (this.__db) { + this._db.asyncClose(); + this.__db = null; + } + }, + + ////////////////////////////////////////////////////////////////////////////// + //// urlInlineComplete + + _finishSearch: function UIC_finishSearch() + { + // Notify the result object + let result = this._result; + + if (result.matchCount) { + result.setDefaultIndex(0); + result.setSearchResult(Ci.nsIAutoCompleteResult["RESULT_SUCCESS"]); + } else { + result.setDefaultIndex(-1); + result.setSearchResult(Ci.nsIAutoCompleteResult["RESULT_NOMATCH"]); + } + + this._listener.onSearchResult(this, result); + this.stopSearch(); + }, + + isSearchComplete: function UIC_isSearchComplete() + { + return this._pendingQuery == null; + }, + + isPendingSearch: function UIC_isPendingSearch(aHandle) + { + return this._pendingQuery == aHandle; + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsISupports + + classID: Components.ID("c88fae2d-25cf-4338-a1f4-64a320ea7440"), + + _xpcom_factory: XPCOMUtils.generateSingletonFactory(urlInlineComplete), + + QueryInterface: XPCOMUtils.generateQI([ + Ci.nsIAutoCompleteSearch, + Ci.nsIAutoCompleteSearchDescriptor, + Ci.nsIObserver, + Ci.nsISupportsWeakReference, + ]) +}; + +var components = [nsPlacesAutoComplete, urlInlineComplete]; +this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/toolkit/components/places/nsPlacesAutoComplete.manifest b/toolkit/components/places/nsPlacesAutoComplete.manifest new file mode 100644 index 000000000..eb704f449 --- /dev/null +++ b/toolkit/components/places/nsPlacesAutoComplete.manifest @@ -0,0 +1,6 @@ +component {d0272978-beab-4adc-a3d4-04b76acfa4e7} nsPlacesAutoComplete.js +contract @mozilla.org/autocomplete/search;1?name=history {d0272978-beab-4adc-a3d4-04b76acfa4e7} + +component {c88fae2d-25cf-4338-a1f4-64a320ea7440} nsPlacesAutoComplete.js +contract @mozilla.org/autocomplete/search;1?name=urlinline {c88fae2d-25cf-4338-a1f4-64a320ea7440} + diff --git a/toolkit/components/places/nsTaggingService.js b/toolkit/components/places/nsTaggingService.js index 1fad67a82..e367e6cb3 100644 --- a/toolkit/components/places/nsTaggingService.js +++ b/toolkit/components/places/nsTaggingService.js @@ -528,6 +528,10 @@ TagAutoCompleteResult.prototype = { return this._results.length; }, + get typeAheadResult() { + return false; + }, + /** * Get the value of the result at the given index */ diff --git a/toolkit/components/url-classifier/HashStore.cpp b/toolkit/components/url-classifier/HashStore.cpp index c298612aa..77bf3cbd4 100644 --- a/toolkit/components/url-classifier/HashStore.cpp +++ b/toolkit/components/url-classifier/HashStore.cpp @@ -964,8 +964,7 @@ HashStore::WriteFile() NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIOutputStream> out; - rv = NS_NewCheckSummedOutputStream(getter_AddRefs(out), storeFile, - PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE); + rv = NS_NewCheckSummedOutputStream(getter_AddRefs(out), storeFile); NS_ENSURE_SUCCESS(rv, rv); uint32_t written; diff --git a/toolkit/components/url-classifier/nsCheckSummedOutputStream.cpp b/toolkit/components/url-classifier/nsCheckSummedOutputStream.cpp index 68f9f1f6f..0e89fd20c 100644 --- a/toolkit/components/url-classifier/nsCheckSummedOutputStream.cpp +++ b/toolkit/components/url-classifier/nsCheckSummedOutputStream.cpp @@ -13,14 +13,11 @@ // nsCheckSummedOutputStream NS_IMPL_ISUPPORTS_INHERITED(nsCheckSummedOutputStream, - nsSafeFileOutputStream, - nsISafeOutputStream, - nsIOutputStream, - nsIFileOutputStream) + nsBufferedOutputStream, + nsISafeOutputStream) NS_IMETHODIMP -nsCheckSummedOutputStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, - int32_t behaviorFlags) +nsCheckSummedOutputStream::Init(nsIOutputStream* stream, uint32_t bufferSize) { nsresult rv; mHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); @@ -29,7 +26,7 @@ nsCheckSummedOutputStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, rv = mHash->Init(nsICryptoHash::MD5); NS_ENSURE_SUCCESS(rv, rv); - return nsSafeFileOutputStream::Init(file, ioFlags, perm, behaviorFlags); + return nsBufferedOutputStream::Init(stream, bufferSize); } NS_IMETHODIMP @@ -39,12 +36,12 @@ nsCheckSummedOutputStream::Finish() NS_ENSURE_SUCCESS(rv, rv); uint32_t written; - rv = nsSafeFileOutputStream::Write(reinterpret_cast<const char*>(mCheckSum.BeginReading()), + rv = nsBufferedOutputStream::Write(reinterpret_cast<const char*>(mCheckSum.BeginReading()), mCheckSum.Length(), &written); NS_ASSERTION(written == mCheckSum.Length(), "Error writing stream checksum"); NS_ENSURE_SUCCESS(rv, rv); - return nsSafeFileOutputStream::Finish(); + return nsBufferedOutputStream::Finish(); } NS_IMETHODIMP @@ -53,7 +50,7 @@ nsCheckSummedOutputStream::Write(const char *buf, uint32_t count, uint32_t *resu nsresult rv = mHash->Update(reinterpret_cast<const uint8_t*>(buf), count); NS_ENSURE_SUCCESS(rv, rv); - return nsSafeFileOutputStream::Write(buf, count, result); + return nsBufferedOutputStream::Write(buf, count, result); } //////////////////////////////////////////////////////////////////////////////// diff --git a/toolkit/components/url-classifier/nsCheckSummedOutputStream.h b/toolkit/components/url-classifier/nsCheckSummedOutputStream.h index c2fe26b5f..b72c7da86 100644 --- a/toolkit/components/url-classifier/nsCheckSummedOutputStream.h +++ b/toolkit/components/url-classifier/nsCheckSummedOutputStream.h @@ -12,25 +12,27 @@ #include "nsICryptoHash.h" #include "nsNetCID.h" #include "nsString.h" -#include "../../../netwerk/base/nsFileStreams.h" #include "nsToolkitCompsCID.h" +#include "../../../netwerk/base/nsBufferedStreams.h" +#include "prio.h" -class nsCheckSummedOutputStream : public nsSafeFileOutputStream +class nsCheckSummedOutputStream : public nsBufferedOutputStream { public: NS_DECL_ISUPPORTS_INHERITED // Size of MD5 hash in bytes static const uint32_t CHECKSUM_SIZE = 16; + static const uint32_t MAX_BUFFER_SIZE = 64 * 1024; nsCheckSummedOutputStream() {} NS_IMETHOD Finish() override; NS_IMETHOD Write(const char *buf, uint32_t count, uint32_t *result) override; - NS_IMETHOD Init(nsIFile* file, int32_t ioFlags, int32_t perm, int32_t behaviorFlags) override; + NS_IMETHOD Init(nsIOutputStream* stream, uint32_t bufferSize) override; protected: - virtual ~nsCheckSummedOutputStream() { nsSafeFileOutputStream::Close(); } + virtual ~nsCheckSummedOutputStream() { nsBufferedOutputStream::Close(); } nsCOMPtr<nsICryptoHash> mHash; nsCString mCheckSum; @@ -39,13 +41,15 @@ protected: // returns a file output stream which can be QI'ed to nsIFileOutputStream. inline nsresult NS_NewCheckSummedOutputStream(nsIOutputStream **result, - nsIFile *file, - int32_t ioFlags = -1, - int32_t perm = -1, - int32_t behaviorFlags = 0) + nsIFile *file) { - nsCOMPtr<nsIFileOutputStream> out = new nsCheckSummedOutputStream(); - nsresult rv = out->Init(file, ioFlags, perm, behaviorFlags); + nsCOMPtr<nsIOutputStream> localOutFile; + nsresult rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(localOutFile), file, + PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIBufferedOutputStream> out = new nsCheckSummedOutputStream(); + rv = out->Init(localOutFile, nsCheckSummedOutputStream::CHECKSUM_SIZE); if (NS_SUCCEEDED(rv)) { out.forget(result); } diff --git a/toolkit/components/webextensions/ExtensionChild.jsm b/toolkit/components/webextensions/ExtensionChild.jsm index c953dd685..5dc4e2277 100644 --- a/toolkit/components/webextensions/ExtensionChild.jsm +++ b/toolkit/components/webextensions/ExtensionChild.jsm @@ -325,7 +325,7 @@ class Messenger { return this.sendMessage(messageManager, msg, recipient, responseCallback); } - onMessage(name) { + _onMessage(name, filter) { return new SingletonEventManager(this.context, name, callback => { let listener = { messageFilterPermissive: this.optionalFilter, @@ -333,7 +333,8 @@ class Messenger { filterMessage: (sender, recipient) => { // Ignore the message if it was sent by this Messenger. - return sender.contextId !== this.context.contextId; + return (sender.contextId !== this.context.contextId && + filter(sender, recipient)); }, receiveMessage: ({target, data: message, sender, recipient}) => { @@ -373,6 +374,14 @@ class Messenger { }).api(); } + onMessage(name) { + return this._onMessage(name, sender => sender.id === this.sender.id); + } + + onMessageExternal(name) { + return this._onMessage(name, sender => sender.id !== this.sender.id); + } + _connect(messageManager, port, recipient) { let msg = { name: port.name, @@ -407,7 +416,7 @@ class Messenger { return this._connect(messageManager, port, recipient); } - onConnect(name) { + _onConnect(name, filter) { return new SingletonEventManager(this.context, name, callback => { let listener = { messageFilterPermissive: this.optionalFilter, @@ -415,7 +424,8 @@ class Messenger { filterMessage: (sender, recipient) => { // Ignore the port if it was created by this Messenger. - return sender.contextId !== this.context.contextId; + return (sender.contextId !== this.context.contextId && + filter(sender, recipient)); }, receiveMessage: ({target, data: message, sender}) => { @@ -438,6 +448,14 @@ class Messenger { }; }).api(); } + + onConnect(name) { + return this._onConnect(name, sender => sender.id === this.sender.id); + } + + onConnectExternal(name) { + return this._onConnect(name, sender => sender.id !== this.sender.id); + } } var apiManager = new class extends SchemaAPIManager { @@ -745,7 +763,7 @@ class ExtensionPageContextChild extends BaseContext { // This is the MessageSender property passed to extension. // It can be augmented by the "page-open" hook. - let sender = {id: extension.uuid}; + let sender = {id: extension.id}; if (viewType == "tab") { sender.tabId = tabId; this.tabId = tabId; diff --git a/toolkit/components/webextensions/ExtensionCommon.jsm b/toolkit/components/webextensions/ExtensionCommon.jsm index a339fb27e..9ec84b5c7 100644 --- a/toolkit/components/webextensions/ExtensionCommon.jsm +++ b/toolkit/components/webextensions/ExtensionCommon.jsm @@ -197,10 +197,9 @@ class BaseContext { * @returns {Promise} */ sendMessage(target, messageName, data, options = {}) { - options.recipient = options.recipient || {}; + options.recipient = Object.assign({extensionId: this.extension.id}, options.recipient); options.sender = options.sender || {}; - options.recipient.extensionId = this.extension.id; options.sender.extensionId = this.extension.id; options.sender.contextId = this.contextId; diff --git a/toolkit/components/webextensions/ExtensionContent.jsm b/toolkit/components/webextensions/ExtensionContent.jsm index 9b9a02091..5f9b88f35 100644 --- a/toolkit/components/webextensions/ExtensionContent.jsm +++ b/toolkit/components/webextensions/ExtensionContent.jsm @@ -344,6 +344,7 @@ class ContentScriptContextChild extends BaseContext { // because it enables us to create the APIs object in this sandbox object and then copying it // into the iframe's window, see Bug 1214658 for rationale) this.sandbox = Cu.Sandbox(contentWindow, { + sandboxName: `Web-Accessible Extension Page ${this.extension.id}`, sandboxPrototype: contentWindow, sameZoneAs: contentWindow, wantXrays: false, @@ -360,6 +361,7 @@ class ContentScriptContextChild extends BaseContext { this.sandbox = Cu.Sandbox(principal, { metadata, + sandboxName: `Content Script ${this.extension.id}`, sandboxPrototype: contentWindow, sameZoneAs: contentWindow, wantXrays: true, @@ -456,7 +458,7 @@ class ContentScriptContextChild extends BaseContext { defineLazyGetter(ContentScriptContextChild.prototype, "messenger", function() { // The |sender| parameter is passed directly to the extension. - let sender = {id: this.extension.uuid, frameId: this.frameId, url: this.url}; + let sender = {id: this.extension.id, frameId: this.frameId, url: this.url}; let filter = {extensionId: this.extension.id}; let optionalFilter = {frameId: this.frameId}; diff --git a/toolkit/components/webextensions/LegacyExtensionsUtils.jsm b/toolkit/components/webextensions/LegacyExtensionsUtils.jsm index 7632548e3..e8d276fe9 100644 --- a/toolkit/components/webextensions/LegacyExtensionsUtils.jsm +++ b/toolkit/components/webextensions/LegacyExtensionsUtils.jsm @@ -64,7 +64,7 @@ var LegacyExtensionContext = class extends BaseContext { {value: cloneScope, enumerable: true, configurable: true, writable: true} ); - let sender = {id: targetExtension.uuid}; + let sender = {id: targetExtension.id}; let filter = {extensionId: targetExtension.id}; // Legacy addons live in the main process. Messages from other addons are // Messages from WebExtensions are sent to the main process and forwarded via diff --git a/toolkit/components/webextensions/ext-c-runtime.js b/toolkit/components/webextensions/ext-c-runtime.js index 8adca60ca..1dcac35da 100644 --- a/toolkit/components/webextensions/ext-c-runtime.js +++ b/toolkit/components/webextensions/ext-c-runtime.js @@ -9,6 +9,10 @@ function runtimeApiFactory(context) { onMessage: context.messenger.onMessage("runtime.onMessage"), + onConnectExternal: context.messenger.onConnectExternal("runtime.onConnectExternal"), + + onMessageExternal: context.messenger.onMessageExternal("runtime.onMessageExternal"), + connect: function(extensionId, connectInfo) { let name = connectInfo !== null && connectInfo.name || ""; extensionId = extensionId || extension.id; @@ -47,7 +51,6 @@ function runtimeApiFactory(context) { if (options != null && typeof options != "object") { return Promise.reject({message: "runtime.sendMessage's options argument is invalid"}); } - // TODO(robwu): Validate option keys and values when we support it. extensionId = extensionId || extension.id; let recipient = {extensionId}; diff --git a/toolkit/components/webextensions/schemas/runtime.json b/toolkit/components/webextensions/schemas/runtime.json index b3f12a768..575df7d27 100644 --- a/toolkit/components/webextensions/schemas/runtime.json +++ b/toolkit/components/webextensions/schemas/runtime.json @@ -535,7 +535,6 @@ }, { "name": "onConnectExternal", - "unsupported": true, "type": "function", "description": "Fired when a connection is made from another extension.", "parameters": [ @@ -560,7 +559,6 @@ }, { "name": "onMessageExternal", - "unsupported": true, "type": "function", "description": "Fired when a message is sent from another extension/app. Cannot be used in a content script.", "parameters": [ diff --git a/toolkit/components/webextensions/test/mochitest/mochitest.ini b/toolkit/components/webextensions/test/mochitest/mochitest.ini index 45586237e..1f61060ad 100644 --- a/toolkit/components/webextensions/test/mochitest/mochitest.ini +++ b/toolkit/components/webextensions/test/mochitest/mochitest.ini @@ -59,6 +59,7 @@ skip-if = os == 'android' # Android does not support tabs API. Bug 1260250 [test_ext_contentscript_teardown.html] skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250 [test_ext_exclude_include_globs.html] +[test_ext_external_messaging.html] [test_ext_i18n_css.html] [test_ext_generate.html] [test_ext_notifications.html] diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_all_apis.js b/toolkit/components/webextensions/test/mochitest/test_ext_all_apis.js index 0f617c37e..25d04b36b 100644 --- a/toolkit/components/webextensions/test/mochitest/test_ext_all_apis.js +++ b/toolkit/components/webextensions/test/mochitest/test_ext_all_apis.js @@ -75,7 +75,9 @@ let expectedBackgroundApis = [ "runtime.getBackgroundPage", "runtime.getBrowserInfo", "runtime.getPlatformInfo", + "runtime.onConnectExternal", "runtime.onInstalled", + "runtime.onMessageExternal", "runtime.onStartup", "runtime.onUpdateAvailable", "runtime.openOptionsPage", diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_external_messaging.html b/toolkit/components/webextensions/test/mochitest/test_ext_external_messaging.html new file mode 100644 index 000000000..dfc1f9427 --- /dev/null +++ b/toolkit/components/webextensions/test/mochitest/test_ext_external_messaging.html @@ -0,0 +1,111 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>WebExtension external messaging</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script> + <script type="text/javascript" src="head.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + +<script type="text/javascript"> +"use strict"; + +function backgroundScript(id, otherId) { + browser.runtime.onMessage.addListener((msg, sender) => { + browser.test.fail(`Got unexpected message: ${uneval(msg)} ${uneval(sender)}`); + }); + + browser.runtime.onConnect.addListener(port => { + browser.test.fail(`Got unexpected connection: ${uneval(port.sender)}`); + }); + + browser.runtime.onMessageExternal.addListener((msg, sender) => { + browser.test.assertEq(otherId, sender.id, `${id}: Got expected external sender ID`); + browser.test.assertEq(`helo-${id}`, msg, "Got expected message"); + + browser.test.sendMessage("onMessage-done"); + + return Promise.resolve(`ehlo-${otherId}`); + }); + + browser.runtime.onConnectExternal.addListener(port => { + browser.test.assertEq(otherId, port.sender.id, `${id}: Got expected external connecter ID`); + + port.onMessage.addListener(msg => { + browser.test.assertEq(`helo-${id}`, msg, "Got expected port message"); + + port.postMessage(`ehlo-${otherId}`); + + browser.test.sendMessage("onConnect-done"); + }); + }); + + browser.test.onMessage.addListener(msg => { + if (msg === "go") { + browser.runtime.sendMessage(otherId, `helo-${otherId}`).then(result => { + browser.test.assertEq(`ehlo-${id}`, result, "Got expected reply"); + browser.test.sendMessage("sendMessage-done"); + }); + + let port = browser.runtime.connect(otherId); + port.postMessage(`helo-${otherId}`); + + port.onMessage.addListener(msg => { + port.disconnect(); + + browser.test.assertEq(msg, `ehlo-${id}`, "Got expected port reply"); + browser.test.sendMessage("connect-done"); + }); + } + }); +} + +function makeExtension(id, otherId) { + let args = `${JSON.stringify(id)}, ${JSON.stringify(otherId)}`; + + let extensionData = { + background: `(${backgroundScript})(${args})`, + manifest: { + "applications": {"gecko": {id}}, + }, + }; + + return ExtensionTestUtils.loadExtension(extensionData); +} + +add_task(function* test_contentscript() { + const ID1 = "foo-message@mochitest.mozilla.org"; + const ID2 = "bar-message@mochitest.mozilla.org"; + + let extension1 = makeExtension(ID1, ID2); + let extension2 = makeExtension(ID2, ID1); + + yield Promise.all([extension1.startup(), extension2.startup()]); + + extension1.sendMessage("go"); + extension2.sendMessage("go"); + + yield Promise.all([ + extension1.awaitMessage("sendMessage-done"), + extension2.awaitMessage("sendMessage-done"), + + extension1.awaitMessage("onMessage-done"), + extension2.awaitMessage("onMessage-done"), + + extension1.awaitMessage("connect-done"), + extension2.awaitMessage("connect-done"), + + extension1.awaitMessage("onConnect-done"), + extension2.awaitMessage("onConnect-done"), + ]); + + yield extension1.unload(); + yield extension2.unload(); +}); +</script> + +</body> +</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply2.html b/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply2.html index 1ebc1b40f..5c350be2f 100644 --- a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply2.html +++ b/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply2.html @@ -13,48 +13,119 @@ <script type="text/javascript"> "use strict"; -function backgroundScript(token) { +function backgroundScript(token, id, otherId) { + browser.tabs.create({url: "tab.html"}); + browser.runtime.onMessage.addListener((msg, sender, sendReply) => { - browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), "sender url correct"); + browser.test.assertEq(id, sender.id, `${id}: Got expected sender ID`); - if (msg == "done") { - browser.test.notifyPass("sendmessage_reply"); - return; + if (msg === `content-${token}`) { + browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), + `${id}: sender url correct`); + + let tabId = sender.tab.id; + browser.tabs.sendMessage(tabId, `${token}-contentMessage`); + + sendReply(`${token}-done`); + } else if (msg === `tab-${token}`) { + browser.runtime.sendMessage(otherId, `${otherId}-tabMessage`); + browser.runtime.sendMessage(`${token}-tabMessage`); + + sendReply(`${token}-done`); + } else { + browser.test.fail(`${id}: Unexpected runtime message received: ${msg} ${uneval(sender)}`); } + }); + + browser.runtime.onMessageExternal.addListener((msg, sender, sendReply) => { + browser.test.assertEq(otherId, sender.id, `${id}: Got expected external sender ID`); + + if (msg === `content-${id}`) { + browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), + `${id}: external sender url correct`); + + sendReply(`${otherId}-done`); + } else if (msg === `tab-${id}`) { + sendReply(`${otherId}-done`); + } else if (msg !== `${id}-tabMessage`) { + browser.test.fail(`${id}: Unexpected runtime external message received: ${msg} ${uneval(sender)}`); + } + }); +} + +function contentScript(token, id, otherId) { + let gotContentMessage = false; + browser.runtime.onMessage.addListener((msg, sender, sendReply) => { + browser.test.assertEq(id, sender.id, `${id}: Got expected sender ID`); + + browser.test.assertEq(`${token}-contentMessage`, msg, + `${id}: Correct content script message`); + if (msg === `${token}-contentMessage`) { + gotContentMessage = true; + } + }); + + Promise.all([ + browser.runtime.sendMessage(otherId, `content-${otherId}`).then(resp => { + browser.test.assertEq(`${id}-done`, resp, `${id}: Correct content script external response token`); + }), - let tabId = sender.tab.id; - browser.tabs.sendMessage(tabId, `${token}-tabMessage`); + browser.runtime.sendMessage(`content-${token}`).then(resp => { + browser.test.assertEq(`${token}-done`, resp, `${id}: Correct content script response token`); + }), + ]).then(() => { + browser.test.assertTrue(gotContentMessage, `${id}: Got content script message`); - browser.test.assertEq(msg, token, "token matches"); - sendReply(`${token}-done`); + browser.test.sendMessage("content-script-done"); }); } -function contentScript(token) { +function tabScript(token, id, otherId) { let gotTabMessage = false; - let badTabMessage = false; browser.runtime.onMessage.addListener((msg, sender, sendReply) => { - if (msg == `${token}-tabMessage`) { + browser.test.assertEq(id, sender.id, `${id}: Got expected sender ID`); + + if (String(msg).startsWith("content-")) { + return; + } + + browser.test.assertEq(`${token}-tabMessage`, msg, + `${id}: Correct tab script message`); + if (msg === `${token}-tabMessage`) { gotTabMessage = true; - } else { - badTabMessage = true; } }); - browser.runtime.sendMessage(token, function(resp) { - if (resp != `${token}-done` || !gotTabMessage || badTabMessage) { - return; // test failed - } - browser.runtime.sendMessage("done"); + Promise.all([ + browser.runtime.sendMessage(otherId, `tab-${otherId}`).then(resp => { + browser.test.assertEq(`${id}-done`, resp, `${id}: Correct tab script external response token`); + }), + + browser.runtime.sendMessage(`tab-${token}`).then(resp => { + browser.test.assertEq(`${token}-done`, resp, `${id}: Correct tab script response token`); + }), + ]).then(() => { + browser.test.assertTrue(gotTabMessage, `${id}: Got tab script message`); + + window.close(); + + browser.test.sendMessage("tab-script-done"); }); } -function makeExtension() { +function makeExtension(id, otherId) { let token = Math.random(); + + let args = `${token}, ${JSON.stringify(id)}, ${JSON.stringify(otherId)}`; + let extensionData = { - background: `(${backgroundScript})(${token})`, + background: `(${backgroundScript})(${args})`, manifest: { + "applications": {"gecko": {id}}, + "permissions": ["tabs"], + + "content_scripts": [{ "matches": ["http://mochi.test/*/file_sample.html"], "js": ["content_script.js"], @@ -63,29 +134,46 @@ function makeExtension() { }, files: { - "content_script.js": `(${contentScript})(${token})`, + "tab.html": `<!DOCTYPE html> + <html> + <head> + <meta charset="utf-8"> + <script src="tab.js"><\/script> + </head> + </html>`, + + "tab.js": `(${tabScript})(${args})`, + + "content_script.js": `(${contentScript})(${args})`, }, }; return extensionData; } add_task(function* test_contentscript() { - let extension1 = ExtensionTestUtils.loadExtension(makeExtension()); - let extension2 = ExtensionTestUtils.loadExtension(makeExtension()); + const ID1 = "sendmessage1@mochitest.mozilla.org"; + const ID2 = "sendmessage2@mochitest.mozilla.org"; + + let extension1 = ExtensionTestUtils.loadExtension(makeExtension(ID1, ID2)); + let extension2 = ExtensionTestUtils.loadExtension(makeExtension(ID2, ID1)); yield Promise.all([extension1.startup(), extension2.startup()]); let win = window.open("file_sample.html"); - yield Promise.all([waitForLoad(win), - extension1.awaitFinish("sendmessage_reply"), - extension2.awaitFinish("sendmessage_reply")]); + yield waitForLoad(win); + + yield Promise.all([ + extension1.awaitMessage("content-script-done"), + extension2.awaitMessage("content-script-done"), + extension1.awaitMessage("tab-script-done"), + extension2.awaitMessage("tab-script-done"), + ]); win.close(); yield extension1.unload(); yield extension2.unload(); - info("extensions unloaded"); }); </script> diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_context.js b/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_context.js index 63d5361a1..770851472 100644 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_context.js +++ b/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_context.js @@ -108,7 +108,7 @@ add_task(function* test_legacy_extension_context() { "Got the expected message"); ok(msgSender, "Got a message sender object"); - equal(msgSender.id, extensionInfo.uuid, "The sender has the expected id property"); + equal(msgSender.id, extension.id, "The sender has the expected id property"); equal(msgSender.url, extensionInfo.bgURL, "The sender has the expected url property"); // Wait confirmation that the reply has been received. @@ -136,7 +136,7 @@ add_task(function* test_legacy_extension_context() { ok(port, "Got the Port API object"); ok(port.sender, "The port has a sender property"); - equal(port.sender.id, extensionInfo.uuid, + equal(port.sender.id, extension.id, "The port sender has the expected id property"); equal(port.sender.url, extensionInfo.bgURL, "The port sender has the expected url property"); diff --git a/toolkit/components/xulstore/XULStore.js b/toolkit/components/xulstore/XULStore.js index c2721327c..8b5bc1313 100644 --- a/toolkit/components/xulstore/XULStore.js +++ b/toolkit/components/xulstore/XULStore.js @@ -63,11 +63,21 @@ XULStore.prototype = { load: function () { Services.obs.addObserver(this, "profile-before-change", true); - this._storeFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + let profileType = "ProfD"; + try { + this._storeFile = Services.dirsvc.get(profileType, Ci.nsIFile); + } catch (ex) { + try { + profileType = "ProfDS"; + this._storeFile = Services.dirsvc.get(profileType, Ci.nsIFile); + } catch (ex) { + throw new Error("Can't find profile directory."); + } + } this._storeFile.append(STOREDB_FILENAME); if (!this._storeFile.exists()) { - this.import(); + this.import(profileType); } else { this.readFile(); } @@ -90,8 +100,8 @@ XULStore.prototype = { Services.console.logStringMessage("XULStore: " + message); }, - import: function() { - let localStoreFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + import(profileType) { + let localStoreFile = Services.dirsvc.get(profileType || "ProfD", Ci.nsIFile); localStoreFile.append("localstore.rdf"); if (!localStoreFile.exists()) { diff --git a/toolkit/content/plugins.html b/toolkit/content/plugins.html index d389f52dd..15bbed9bb 100644 --- a/toolkit/content/plugins.html +++ b/toolkit/content/plugins.html @@ -75,15 +75,6 @@ enabledplugins.appendChild(document.createTextNode(pluginsbundle.GetStringFromName(label))); fragment.appendChild(enabledplugins); - var deprecation = document.createElement("p"); - deprecation.setAttribute("class", "notice"); - deprecation.textContent = pluginsbundle.GetStringFromName("deprecation_description") + " \u00A0 "; - var deprecationLink = document.createElement("a"); - deprecationLink.textContent = pluginsbundle.GetStringFromName("deprecation_learn_more"); - deprecationLink.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "npapi"; - deprecation.appendChild(deprecationLink); - fragment.appendChild(deprecation); - var stateNames = {}; ["STATE_SOFTBLOCKED", "STATE_BLOCKED", diff --git a/toolkit/content/widgets/toolbar.xml b/toolkit/content/widgets/toolbar.xml index e1f58f7aa..55cef8244 100644 --- a/toolkit/content/widgets/toolbar.xml +++ b/toolkit/content/widgets/toolbar.xml @@ -54,7 +54,7 @@ // Look to see if there is a toolbarset. this.toolbarset = this.firstChild; while (this.toolbarset && this.toolbarset.localName != "toolbarset") { - this.toolbarset = toolbarset.nextSibling; + this.toolbarset = this.toolbarset.nextSibling; } if (this.toolbarset) { diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index 5250ca75d..8c7825392 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -45,175 +45,201 @@ const Ci = Components.interfaces; const Cu = Components.utils; this.ForgetAboutSite = { - removeDataFromDomain: function CRH_removeDataFromDomain(aDomain) + removeDataFromDomain: Task.async(function* (aDomain) { PlacesUtils.history.removePagesFromHost(aDomain, true); + let promises = []; // Cache - let cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"]. - getService(Ci.nsICacheStorageService); - // NOTE: there is no way to clear just that domain, so we clear out - // everything) - try { + promises.push(Task.spawn(function*() { + let cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"]. + getService(Ci.nsICacheStorageService); + // NOTE: there is no way to clear just that domain, so we clear out + // everything) cs.clear(); - } catch (ex) { - Cu.reportError("Exception thrown while clearing the cache: " + - ex.toString()); - } + }).catch(ex => { + throw new Error("Exception thrown while clearing the cache: " + ex); + })); // Image Cache - let imageCache = Cc["@mozilla.org/image/tools;1"]. - getService(Ci.imgITools).getImgCacheForDocument(null); - try { + promises.push(Task.spawn(function*() { + let imageCache = Cc["@mozilla.org/image/tools;1"]. + getService(Ci.imgITools).getImgCacheForDocument(null); imageCache.clearCache(false); // true=chrome, false=content - } catch (ex) { - Cu.reportError("Exception thrown while clearing the image cache: " + - ex.toString()); - } + }).catch(ex => { + throw new Error("Exception thrown while clearing the image cache: " + ex); + })); // Cookies - let cm = Cc["@mozilla.org/cookiemanager;1"]. - getService(Ci.nsICookieManager2); - let enumerator = cm.getCookiesWithOriginAttributes(JSON.stringify({}), aDomain); - while (enumerator.hasMoreElements()) { - let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); - cm.remove(cookie.host, cookie.name, cookie.path, false, cookie.originAttributes); - } + // Need to maximize the number of cookies cleaned here + promises.push(Task.spawn(function*() { + let cm = Cc["@mozilla.org/cookiemanager;1"]. + getService(Ci.nsICookieManager2); + let enumerator = cm.getCookiesWithOriginAttributes(JSON.stringify({}), aDomain); + while (enumerator.hasMoreElements()) { + let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); + cm.remove(cookie.host, cookie.name, cookie.path, false, cookie.originAttributes); + } + }).catch(ex => { + throw new Error("Exception thrown while clearning cookies: " + ex); + })); // EME - let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"]. - getService(Ci.mozIGeckoMediaPluginChromeService); - mps.forgetThisSite(aDomain, JSON.stringify({})); + promises.push(Task.spawn(function*() { + let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"]. + getService(Ci.mozIGeckoMediaPluginChromeService); + mps.forgetThisSite(aDomain, JSON.stringify({})); + }).catch(ex => { + throw new Error("Exception thrown while clearing Encrypted Media Extensions: " + ex); + })); // Plugin data const phInterface = Ci.nsIPluginHost; const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL; let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface); let tags = ph.getPluginTags(); - let promises = []; for (let i = 0; i < tags.length; i++) { - let promise = new Promise(resolve => { - let tag = tags[i]; + promises.push(new Promise(resolve => { try { - ph.clearSiteData(tags[i], aDomain, FLAG_CLEAR_ALL, -1, function(rv) { - resolve(); - }); + ph.clearSiteData(tags[i], aDomain, FLAG_CLEAR_ALL, -1, resolve); } catch (e) { // Ignore errors from the plugin, but resolve the promise + // We cannot check if something is a bailout or an error resolve(); } - }); - promises.push(promise); + })); } // Downloads - Task.spawn(function*() { + promises.push(Task.spawn(function*() { let list = yield Downloads.getList(Downloads.ALL); list.removeFinished(download => hasRootDomain( - NetUtil.newURI(download.source.url).host, aDomain)); - }).then(null, Cu.reportError); + NetUtil.newURI(download.source.url).host, aDomain)); + }).catch(ex => { + throw new Error("Exception in clearing Downloads: " + ex); + })); // Passwords - let lm = Cc["@mozilla.org/login-manager;1"]. - getService(Ci.nsILoginManager); - // Clear all passwords for domain - try { + promises.push(Task.spawn(function*() { + let lm = Cc["@mozilla.org/login-manager;1"]. + getService(Ci.nsILoginManager); + // Clear all passwords for domain let logins = lm.getAllLogins(); - for (let i = 0; i < logins.length; i++) - if (hasRootDomain(logins[i].hostname, aDomain)) + for (let i = 0; i < logins.length; i++) { + if (hasRootDomain(logins[i].hostname, aDomain)) { lm.removeLogin(logins[i]); - } - // XXXehsan: is there a better way to do this rather than this - // hacky comparison? - catch (ex) { - if (!ex.message.includes("User canceled Master Password entry")) { - throw ex; + } } - } + }).catch(ex => { + // XXX: + // Is there a better way to do this rather than this hacky comparison? + // Copied this from toolkit/components/passwordmgr/crypto-SDR.js + if (!ex.message.includes("User canceled master password entry")) { + throw new Error("Exception occured in clearing passwords: " + ex); + } + })); // Permissions let pm = Cc["@mozilla.org/permissionmanager;1"]. getService(Ci.nsIPermissionManager); // Enumerate all of the permissions, and if one matches, remove it - enumerator = pm.enumerator; + let enumerator = pm.enumerator; while (enumerator.hasMoreElements()) { let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission); - try { - if (hasRootDomain(perm.principal.URI.host, aDomain)) { - pm.removePermission(perm); + promises.push(new Promise((resolve, reject) => { + try { + if (hasRootDomain(perm.principal.URI.host, aDomain)) { + pm.removePermission(perm); + } + } catch (ex) { + // Ignore entry + } finally { + resolve(); } - } catch (e) { - /* Ignore entry */ - } + })); } // Offline Storages - let qms = Cc["@mozilla.org/dom/quota-manager-service;1"]. - getService(Ci.nsIQuotaManagerService); - // delete data from both HTTP and HTTPS sites - let caUtils = {}; - let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. - getService(Ci.mozIJSSubScriptLoader); - scriptLoader.loadSubScript("chrome://global/content/contentAreaUtils.js", - caUtils); - let httpURI = caUtils.makeURI("http://" + aDomain); - let httpsURI = caUtils.makeURI("https://" + aDomain); - // Following code section has been reverted to the state before Bug 1238183, - // but added a new argument to clearStoragesForPrincipal() for indicating - // clear all storages under a given origin. - let httpPrincipal = Services.scriptSecurityManager - .createCodebasePrincipal(httpURI, {}); - let httpsPrincipal = Services.scriptSecurityManager - .createCodebasePrincipal(httpsURI, {}); - qms.clearStoragesForPrincipal(httpPrincipal, null, true); - qms.clearStoragesForPrincipal(httpsPrincipal, null, true); - - - function onContentPrefsRemovalFinished() { - // Everybody else (including extensions) - Services.obs.notifyObservers(null, "browser:purge-domain-data", aDomain); - } + promises.push(Task.spawn(function*() { + let qms = Cc["@mozilla.org/dom/quota-manager-service;1"]. + getService(Ci.nsIQuotaManagerService); + // delete data from both HTTP and HTTPS sites + let httpURI = NetUtil.newURI("http://" + aDomain); + let httpsURI = NetUtil.newURI("https://" + aDomain); + // Following code section has been reverted to the state before Bug 1238183, + // but added a new argument to clearStoragesForPrincipal() for indicating + // clear all storages under a given origin. + let httpPrincipal = Services.scriptSecurityManager + .createCodebasePrincipal(httpURI, {}); + let httpsPrincipal = Services.scriptSecurityManager + .createCodebasePrincipal(httpsURI, {}); + qms.clearStoragesForPrincipal(httpPrincipal, null, true); + qms.clearStoragesForPrincipal(httpsPrincipal, null, true); + }).catch(ex => { + throw new Error("Exception occured while clearing offline storages: " + ex); + })); // Content Preferences - let cps2 = Cc["@mozilla.org/content-pref/service;1"]. - getService(Ci.nsIContentPrefService2); - cps2.removeBySubdomain(aDomain, null, { - handleCompletion: () => onContentPrefsRemovalFinished(), - handleError: function() {} - }); + promises.push(Task.spawn(function*() { + let cps2 = Cc["@mozilla.org/content-pref/service;1"]. + getService(Ci.nsIContentPrefService2); + cps2.removeBySubdomain(aDomain, null, { + handleCompletion: (reason) => { + // Notify other consumers, including extensions + Services.obs.notifyObservers(null, "browser:purge-domain-data", aDomain); + if (reason === cps2.COMPLETE_ERROR) { + throw new Error("Exception occured while clearing content preferences"); + } + }, + handleError() {} + }); + })); // Predictive network data - like cache, no way to clear this per // domain, so just trash it all - let np = Cc["@mozilla.org/network/predictor;1"]. - getService(Ci.nsINetworkPredictor); - np.reset(); - - // Push notifications. - promises.push(new Promise(resolve => { - var push = Cc["@mozilla.org/push/Service;1"] - .getService(Ci.nsIPushService); + promises.push(Task.spawn(function*() { + let np = Cc["@mozilla.org/network/predictor;1"]. + getService(Ci.nsINetworkPredictor); + np.reset(); + }).catch(ex => { + throw new Error("Exception occured while clearing predictive network data: " + ex); + })); + + // Push notifications + promises.push(Task.spawn(function*() { + var push = Cc["@mozilla.org/push/Service;1"]. + getService(Ci.nsIPushService); push.clearForDomain(aDomain, status => { - (Components.isSuccessCode(status) ? resolve : reject)(status); + if (!Components.isSuccessCode(status)) { + throw new Error("Exception occured while clearing push notifications: " + status); + } }); - }).catch(e => { - Cu.reportError("Exception thrown while clearing Push notifications: " + - e.toString()); })); // HSTS and HPKP // TODO (bug 1290529): also remove HSTS/HPKP information for subdomains. // Since we can't enumerate the information in the site security service // (bug 1115712), we can't implement this right now. - try { + promises.push(Task.spawn(function*() { let sss = Cc["@mozilla.org/ssservice;1"]. getService(Ci.nsISiteSecurityService); + let httpsURI = NetUtil.newURI("https://" + aDomain); sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, httpsURI, 0); sss.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, httpsURI, 0); - } catch (e) { - Cu.reportError("Exception thrown while clearing HSTS/HPKP: " + - e.toString()); - } + }).catch(ex => { + throw new Error("Exception thrown while clearing HSTS/HPKP: " + ex); + })); - return Promise.all(promises); - } -}; + let ErrorCount = 0; + for (let promise of promises) { + try { + yield promise; + } catch (ex) { + Cu.reportError(ex); + ErrorCount++; + } + } + if (ErrorCount !== 0) + throw new Error(`There were a total of ${ErrorCount} errors during removal`); + }) +} diff --git a/toolkit/forgetaboutsite/test/browser/browser_clearplugindata.js b/toolkit/forgetaboutsite/test/browser/browser_clearplugindata.js index ec0a70228..ca0d394c3 100644 --- a/toolkit/forgetaboutsite/test/browser/browser_clearplugindata.js +++ b/toolkit/forgetaboutsite/test/browser/browser_clearplugindata.js @@ -37,7 +37,7 @@ function setTestPluginEnabledState(newEnabledState, plugin) { }); } -add_task(function* setup() { +add_task(function* () { var tags = pluginHost.getPluginTags(); // Find the test plugin @@ -50,12 +50,9 @@ add_task(function* setup() { } if (!pluginTag) { ok(false, "Test Plug-in not available, can't run test"); - finish(); + return; } setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, pluginTag); -}); - -add_task(function* () { yield BrowserTestUtils.openNewForegroundTab(gBrowser, testURL); // Set data for the plugin after the page load. @@ -87,5 +84,3 @@ add_task(function* () { gBrowser.removeCurrentTab(); }); - - diff --git a/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js b/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js index f6ace1e64..d2db95e6a 100644 --- a/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js +++ b/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js @@ -257,7 +257,7 @@ function* test_history_cleared_with_direct_match() do_check_false(yield promiseIsURIVisited(TEST_URI)); yield PlacesTestUtils.addVisits(TEST_URI); do_check_true(yield promiseIsURIVisited(TEST_URI)); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); do_check_false(yield promiseIsURIVisited(TEST_URI)); } @@ -267,7 +267,7 @@ function* test_history_cleared_with_subdomain() do_check_false(yield promiseIsURIVisited(TEST_URI)); yield PlacesTestUtils.addVisits(TEST_URI); do_check_true(yield promiseIsURIVisited(TEST_URI)); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); do_check_false(yield promiseIsURIVisited(TEST_URI)); } @@ -277,7 +277,7 @@ function* test_history_not_cleared_with_uri_contains_domain() do_check_false(yield promiseIsURIVisited(TEST_URI)); yield PlacesTestUtils.addVisits(TEST_URI); do_check_true(yield promiseIsURIVisited(TEST_URI)); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); do_check_true(yield promiseIsURIVisited(TEST_URI)); // Clear history since we left something there from this test. @@ -285,52 +285,52 @@ function* test_history_not_cleared_with_uri_contains_domain() } // Cookie Service -function test_cookie_cleared_with_direct_match() +function* test_cookie_cleared_with_direct_match() { const TEST_DOMAIN = "mozilla.org"; add_cookie(TEST_DOMAIN); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_cookie_exists(TEST_DOMAIN, false); } -function test_cookie_cleared_with_subdomain() +function* test_cookie_cleared_with_subdomain() { const TEST_DOMAIN = "www.mozilla.org"; add_cookie(TEST_DOMAIN); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_cookie_exists(TEST_DOMAIN, false); } -function test_cookie_not_cleared_with_uri_contains_domain() +function* test_cookie_not_cleared_with_uri_contains_domain() { const TEST_DOMAIN = "ilovemozilla.org"; add_cookie(TEST_DOMAIN); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_cookie_exists(TEST_DOMAIN, true); } // Login Manager -function test_login_manager_disabled_hosts_cleared_with_direct_match() +function* test_login_manager_disabled_hosts_cleared_with_direct_match() { const TEST_HOST = "http://mozilla.org"; add_disabled_host(TEST_HOST); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_disabled_host(TEST_HOST, false); } -function test_login_manager_disabled_hosts_cleared_with_subdomain() +function* test_login_manager_disabled_hosts_cleared_with_subdomain() { const TEST_HOST = "http://www.mozilla.org"; add_disabled_host(TEST_HOST); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_disabled_host(TEST_HOST, false); } -function test_login_manager_disabled_hosts_not_cleared_with_uri_contains_domain() +function* test_login_manager_disabled_hosts_not_cleared_with_uri_contains_domain() { const TEST_HOST = "http://ilovemozilla.org"; add_disabled_host(TEST_HOST); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_disabled_host(TEST_HOST, true); // Reset state @@ -340,27 +340,27 @@ function test_login_manager_disabled_hosts_not_cleared_with_uri_contains_domain( check_disabled_host(TEST_HOST, false); } -function test_login_manager_logins_cleared_with_direct_match() +function* test_login_manager_logins_cleared_with_direct_match() { const TEST_HOST = "http://mozilla.org"; add_login(TEST_HOST); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_login_exists(TEST_HOST, false); } -function test_login_manager_logins_cleared_with_subdomain() +function* test_login_manager_logins_cleared_with_subdomain() { const TEST_HOST = "http://www.mozilla.org"; add_login(TEST_HOST); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_login_exists(TEST_HOST, false); } -function test_login_manager_logins_not_cleared_with_uri_contains_domain() +function* test_login_manager_logins_not_cleared_with_uri_contains_domain() { const TEST_HOST = "http://ilovemozilla.org"; add_login(TEST_HOST); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_login_exists(TEST_HOST, true); let lm = Cc["@mozilla.org/login-manager;1"]. @@ -370,27 +370,27 @@ function test_login_manager_logins_not_cleared_with_uri_contains_domain() } // Permission Manager -function test_permission_manager_cleared_with_direct_match() +function* test_permission_manager_cleared_with_direct_match() { const TEST_URI = uri("http://mozilla.org"); add_permission(TEST_URI); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_permission_exists(TEST_URI, false); } -function test_permission_manager_cleared_with_subdomain() +function* test_permission_manager_cleared_with_subdomain() { const TEST_URI = uri("http://www.mozilla.org"); add_permission(TEST_URI); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_permission_exists(TEST_URI, false); } -function test_permission_manager_not_cleared_with_uri_contains_domain() +function* test_permission_manager_not_cleared_with_uri_contains_domain() { const TEST_URI = uri("http://ilovemozilla.org"); add_permission(TEST_URI); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_permission_exists(TEST_URI, true); // Reset state @@ -427,7 +427,7 @@ function* test_content_preferences_cleared_with_direct_match() do_check_false(yield preference_exists(TEST_URI)); yield add_preference(TEST_URI); do_check_true(yield preference_exists(TEST_URI)); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield waitForPurgeNotification(); do_check_false(yield preference_exists(TEST_URI)); } @@ -438,7 +438,7 @@ function* test_content_preferences_cleared_with_subdomain() do_check_false(yield preference_exists(TEST_URI)); yield add_preference(TEST_URI); do_check_true(yield preference_exists(TEST_URI)); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield waitForPurgeNotification(); do_check_false(yield preference_exists(TEST_URI)); } @@ -449,12 +449,12 @@ function* test_content_preferences_not_cleared_with_uri_contains_domain() do_check_false(yield preference_exists(TEST_URI)); yield add_preference(TEST_URI); do_check_true(yield preference_exists(TEST_URI)); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield waitForPurgeNotification(); do_check_true(yield preference_exists(TEST_URI)); // Reset state - ForgetAboutSite.removeDataFromDomain("ilovemozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("ilovemozilla.org"); yield waitForPurgeNotification(); do_check_false(yield preference_exists(TEST_URI)); } @@ -535,7 +535,7 @@ function* test_push_cleared() } // Cache -function test_cache_cleared() +function* test_cache_cleared() { // Because this test is asynchronous, it should be the last test do_check_true(tests[tests.length - 1] == arguments.callee); @@ -557,7 +557,7 @@ function test_cache_cleared() } }; os.addObserver(observer, "cacheservice:empty-cache", false); - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); do_test_pending(); } @@ -588,7 +588,7 @@ function* test_storage_cleared() do_check_eq(storage.getItem("test"), "value" + i); } - ForgetAboutSite.removeDataFromDomain("mozilla.org"); + yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield waitForPurgeNotification(); do_check_eq(s[0].getItem("test"), null); diff --git a/toolkit/jetpack/modules/system/Startup.js b/toolkit/jetpack/modules/system/Startup.js index b9e5d88b3..89eeac3bc 100644 --- a/toolkit/jetpack/modules/system/Startup.js +++ b/toolkit/jetpack/modules/system/Startup.js @@ -15,6 +15,7 @@ const appStartupSrv = Cc["@mozilla.org/toolkit/app-startup;1"] .getService(Ci.nsIAppStartup); const NAME2TOPIC = { + 'Palemoon': 'sessionstore-windows-restored', 'Firefox': 'sessionstore-windows-restored', 'Fennec': 'sessionstore-windows-restored', 'SeaMonkey': 'sessionstore-windows-restored', diff --git a/toolkit/jetpack/moz.build b/toolkit/jetpack/moz.build index 2024e6a7c..2e5dbe5e8 100644 --- a/toolkit/jetpack/moz.build +++ b/toolkit/jetpack/moz.build @@ -85,10 +85,18 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk": 'sdk/ui/toolbar.js', ] + if CONFIG['MC_PALEMOON']: + EXTRA_JS_MODULES.commonjs.sdk.ui += [ + 'sdk/ui/buttons.js', + ] + EXTRA_JS_MODULES.commonjs.sdk.ui.button += [ 'sdk/ui/button/action.js', 'sdk/ui/button/contract.js', 'sdk/ui/button/toggle.js', + ] + + EXTRA_PP_JS_MODULES.commonjs.sdk.ui.button += [ 'sdk/ui/button/view.js', ] @@ -120,9 +128,10 @@ EXTRA_JS_MODULES.commonjs += [ 'test.js', ] -EXTRA_JS_MODULES.commonjs.sdk += [ - 'sdk/webextension.js', -] +if CONFIG['MOZ_WEBEXTENSIONS']: + EXTRA_JS_MODULES.commonjs.sdk += [ + 'sdk/webextension.js', + ] EXTRA_JS_MODULES.commonjs.dev += [ 'dev/debuggee.js', @@ -211,13 +220,15 @@ EXTRA_JS_MODULES.commonjs.sdk += [ 'sdk/tabs.js', 'sdk/test.js', 'sdk/timers.js', - 'sdk/ui.js', 'sdk/url.js', 'sdk/windows.js', ] +EXTRA_PP_JS_MODULES.commonjs.sdk += [ + 'sdk/ui.js', +] + EXTRA_JS_MODULES.commonjs.sdk.addon += [ - 'sdk/addon/bootstrap.js', 'sdk/addon/events.js', 'sdk/addon/host.js', 'sdk/addon/installer.js', @@ -226,6 +237,10 @@ EXTRA_JS_MODULES.commonjs.sdk.addon += [ 'sdk/addon/window.js', ] +EXTRA_PP_JS_MODULES.commonjs.sdk.addon += [ + 'sdk/addon/bootstrap.js', +] + EXTRA_JS_MODULES.commonjs.sdk.browser += [ 'sdk/browser/events.js', ] diff --git a/toolkit/jetpack/sdk/addon/bootstrap.js b/toolkit/jetpack/sdk/addon/bootstrap.js index 0397d91e5..6c5827f1e 100644 --- a/toolkit/jetpack/sdk/addon/bootstrap.js +++ b/toolkit/jetpack/sdk/addon/bootstrap.js @@ -134,8 +134,10 @@ Bootstrap.prototype = { const main = command === "test" ? "sdk/test/runner" : null; const prefsURI = `${baseURI}defaults/preferences/prefs.js`; +#ifdef MOZ_WEBEXTENSIONS // Init the 'sdk/webextension' module from the bootstrap addon parameter. require("sdk/webextension").initFromBootstrapAddonParam(addon); +#endif const { startup } = require("sdk/addon/runner"); startup(reason, {loader, main, prefsURI}); diff --git a/toolkit/jetpack/sdk/clipboard.js b/toolkit/jetpack/sdk/clipboard.js index 048d5f2f1..c6b3c46fe 100644 --- a/toolkit/jetpack/sdk/clipboard.js +++ b/toolkit/jetpack/sdk/clipboard.js @@ -8,6 +8,7 @@ module.metadata = { "stability": "stable", "engines": { // TODO Fennec Support 789757 + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*", "Thunderbird": "*" diff --git a/toolkit/jetpack/sdk/context-menu.js b/toolkit/jetpack/sdk/context-menu.js index 004c642d4..e00f41d79 100644 --- a/toolkit/jetpack/sdk/context-menu.js +++ b/toolkit/jetpack/sdk/context-menu.js @@ -7,6 +7,7 @@ module.metadata = { "stability": "stable", "engines": { // TODO Fennec support Bug 788334 + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/panel.js b/toolkit/jetpack/sdk/panel.js index 4b625799d..34cde2edd 100644 --- a/toolkit/jetpack/sdk/panel.js +++ b/toolkit/jetpack/sdk/panel.js @@ -8,6 +8,7 @@ module.metadata = { "stability": "stable", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/places/bookmarks.js b/toolkit/jetpack/sdk/places/bookmarks.js index c4f9528f1..e8fdae4f4 100644 --- a/toolkit/jetpack/sdk/places/bookmarks.js +++ b/toolkit/jetpack/sdk/places/bookmarks.js @@ -7,6 +7,7 @@ module.metadata = { "stability": "unstable", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/places/events.js b/toolkit/jetpack/sdk/places/events.js index a3f95ee03..c5e728039 100644 --- a/toolkit/jetpack/sdk/places/events.js +++ b/toolkit/jetpack/sdk/places/events.js @@ -7,6 +7,7 @@ module.metadata = { 'stability': 'experimental', 'engines': { + 'Palemoon': '*', 'Firefox': '*', "SeaMonkey": '*' } diff --git a/toolkit/jetpack/sdk/places/favicon.js b/toolkit/jetpack/sdk/places/favicon.js index 05b057db1..7a74aa517 100644 --- a/toolkit/jetpack/sdk/places/favicon.js +++ b/toolkit/jetpack/sdk/places/favicon.js @@ -7,6 +7,7 @@ module.metadata = { "stability": "unstable", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/places/history.js b/toolkit/jetpack/sdk/places/history.js index b243b024c..f7fc3ed57 100644 --- a/toolkit/jetpack/sdk/places/history.js +++ b/toolkit/jetpack/sdk/places/history.js @@ -7,6 +7,7 @@ module.metadata = { "stability": "unstable", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/places/host/host-bookmarks.js b/toolkit/jetpack/sdk/places/host/host-bookmarks.js index 3245c4070..f6dec4069 100644 --- a/toolkit/jetpack/sdk/places/host/host-bookmarks.js +++ b/toolkit/jetpack/sdk/places/host/host-bookmarks.js @@ -7,6 +7,7 @@ module.metadata = { "stability": "experimental", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/places/host/host-query.js b/toolkit/jetpack/sdk/places/host/host-query.js index f2dbd6550..a2cd4cd35 100644 --- a/toolkit/jetpack/sdk/places/host/host-query.js +++ b/toolkit/jetpack/sdk/places/host/host-query.js @@ -6,6 +6,7 @@ module.metadata = { "stability": "experimental", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/places/host/host-tags.js b/toolkit/jetpack/sdk/places/host/host-tags.js index 929a5d5af..b94342549 100644 --- a/toolkit/jetpack/sdk/places/host/host-tags.js +++ b/toolkit/jetpack/sdk/places/host/host-tags.js @@ -7,6 +7,7 @@ module.metadata = { "stability": "experimental", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/places/utils.js b/toolkit/jetpack/sdk/places/utils.js index 44366d2aa..fe928c4ea 100644 --- a/toolkit/jetpack/sdk/places/utils.js +++ b/toolkit/jetpack/sdk/places/utils.js @@ -7,6 +7,7 @@ module.metadata = { "stability": "experimental", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/selection.js b/toolkit/jetpack/sdk/selection.js index 8682e8c6d..e393aae06 100644 --- a/toolkit/jetpack/sdk/selection.js +++ b/toolkit/jetpack/sdk/selection.js @@ -7,6 +7,7 @@ module.metadata = { "stability": "stable", "engines": { + "Palemoon": "*", "Firefox": "*", "SeaMonkey": "*" } diff --git a/toolkit/jetpack/sdk/system/xul-app.jsm b/toolkit/jetpack/sdk/system/xul-app.jsm index 90681bb1b..ed760c3a4 100644 --- a/toolkit/jetpack/sdk/system/xul-app.jsm +++ b/toolkit/jetpack/sdk/system/xul-app.jsm @@ -41,6 +41,7 @@ var platformVersion = exports.platformVersion = appInfo.platformVersion; // GUID. var ids = exports.ids = { + Palemoon: "{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}", Firefox: "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}", Mozilla: "{86c18b42-e466-45a9-ae7a-9b95ba6f5640}", SeaMonkey: "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}", diff --git a/toolkit/jetpack/sdk/ui.js b/toolkit/jetpack/sdk/ui.js index 7f9110b26..d1ff7ceb8 100644 --- a/toolkit/jetpack/sdk/ui.js +++ b/toolkit/jetpack/sdk/ui.js @@ -6,12 +6,15 @@ module.metadata = { 'stability': 'experimental', 'engines': { + 'Palemoon': '> 27', 'Firefox': '> 28' } }; exports.ActionButton = require('./ui/button/action').ActionButton; exports.ToggleButton = require('./ui/button/toggle').ToggleButton; +#ifndef MC_PALEMOON exports.Sidebar = require('./ui/sidebar').Sidebar; exports.Frame = require('./ui/frame').Frame; exports.Toolbar = require('./ui/toolbar').Toolbar; +#endif diff --git a/toolkit/jetpack/sdk/ui/button/action.js b/toolkit/jetpack/sdk/ui/button/action.js index dfb092d0c..5355705be 100644 --- a/toolkit/jetpack/sdk/ui/button/action.js +++ b/toolkit/jetpack/sdk/ui/button/action.js @@ -6,6 +6,7 @@ module.metadata = { 'stability': 'experimental', 'engines': { + 'Palemoon': '> 27', 'Firefox': '> 28' } }; diff --git a/toolkit/jetpack/sdk/ui/button/toggle.js b/toolkit/jetpack/sdk/ui/button/toggle.js index a226b3212..d8a3d1758 100644 --- a/toolkit/jetpack/sdk/ui/button/toggle.js +++ b/toolkit/jetpack/sdk/ui/button/toggle.js @@ -6,6 +6,7 @@ module.metadata = { 'stability': 'experimental', 'engines': { + 'Palemoon': '> 27', 'Firefox': '> 28' } }; diff --git a/toolkit/jetpack/sdk/ui/button/view.js b/toolkit/jetpack/sdk/ui/button/view.js index 63b7aea31..dcc3be59d 100644 --- a/toolkit/jetpack/sdk/ui/button/view.js +++ b/toolkit/jetpack/sdk/ui/button/view.js @@ -6,6 +6,7 @@ module.metadata = { 'stability': 'experimental', 'engines': { + 'Palemoon': '> 27', 'Firefox': '> 28' } }; @@ -19,14 +20,19 @@ const { isObject, isNil } = require('../../lang/type'); const { getMostRecentBrowserWindow } = require('../../window/utils'); const { ignoreWindow } = require('../../private-browsing/utils'); +#ifdef MC_PALEMOON +const { buttons } = require('../buttons'); +#else const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); const { AREA_PANEL, AREA_NAVBAR } = CustomizableUI; +#endif const { events: viewEvents } = require('./view/events'); const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; const views = new Map(); +#ifndef MC_PALEMOON const customizedWindows = new WeakMap(); const buttonListener = { @@ -64,19 +70,25 @@ CustomizableUI.addListener(buttonListener); require('../../system/unload').when( _ => CustomizableUI.removeListener(buttonListener) ); +#endif function getNode(id, window) { return !views.has(id) || ignoreWindow(window) ? null +#ifdef MC_PALEMOON + : buttons.getNode(id, window); +#else : CustomizableUI.getWidget(id).forWindow(window).node +#endif }; +#ifndef MC_PALEMOON function isInToolbar(id) { let placement = CustomizableUI.getPlacementOfWidget(id); return placement && CustomizableUI.getAreaType(placement.area) === 'toolbar'; } - +#endif function getImage(icon, isInToolbar, pixelRatio) { let targetSize = (isInToolbar ? 18 : 32) * pixelRatio; @@ -109,7 +121,11 @@ function getImage(icon, isInToolbar, pixelRatio) { } function nodeFor(id, window=getMostRecentBrowserWindow()) { +#ifdef MC_PALEMOON + return getNode(id, window); +#else return customizedWindows.has(window) ? null : getNode(id, window); +#endif }; exports.nodeFor = nodeFor; @@ -119,14 +135,23 @@ function create(options) { if (views.has(id)) throw new Error('The ID "' + id + '" seems already used.'); +#ifdef MC_PALEMOON + buttons.createButton({ +#else CustomizableUI.createWidget({ +#endif id: id, type: 'custom', +#ifdef MC_PALEMOON + + onBuild: function(document, _id) { +#else removable: true, defaultArea: AREA_NAVBAR, allowedAreas: [ AREA_PANEL, AREA_NAVBAR ], onBuild: function(document) { +#endif let window = document.defaultView; let node = document.createElementNS(XUL_NS, 'toolbarbutton'); @@ -136,16 +161,26 @@ function create(options) { if (ignoreWindow(window)) node.style.display = 'none'; +#ifdef MC_PALEMOON + node.setAttribute('id', _id); +#else node.setAttribute('id', this.id); +#endif node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional badged-button'); node.setAttribute('type', type); node.setAttribute('label', label); node.setAttribute('tooltiptext', label); node.setAttribute('image', image); +#ifdef MC_PALEMOON + node.setAttribute('pmkit-button', 'true'); +#else node.setAttribute('constrain-size', 'true'); +#endif views.set(id, { +#ifndef MC_PALEMOON area: this.currentArea, +#endif icon: icon, label: label }); @@ -171,7 +206,11 @@ function dispose(id) { if (!views.has(id)) return; views.delete(id); +#ifdef MC_PALEMOON + buttons.destroyButton(id); +#else CustomizableUI.destroyWidget(id); +#endif } exports.dispose = dispose; @@ -179,8 +218,12 @@ function setIcon(id, window, icon) { let node = getNode(id, window); if (node) { +#ifdef MC_PALEMOON + let image = getImage(icon, true, window.devicePixelRatio); +#else icon = customizedWindows.has(window) ? views.get(id).icon : icon; let image = getImage(icon, isInToolbar(id), window.devicePixelRatio); +#endif node.setAttribute('image', image); } diff --git a/toolkit/jetpack/sdk/ui/button/view/events.js b/toolkit/jetpack/sdk/ui/button/view/events.js index 98909656a..34d14be3a 100644 --- a/toolkit/jetpack/sdk/ui/button/view/events.js +++ b/toolkit/jetpack/sdk/ui/button/view/events.js @@ -7,6 +7,7 @@ module.metadata = { 'stability': 'experimental', 'engines': { + 'Palemoon': '*', 'Firefox': '*', 'SeaMonkey': '*', 'Thunderbird': '*' diff --git a/toolkit/jetpack/sdk/ui/buttons.js b/toolkit/jetpack/sdk/ui/buttons.js new file mode 100644 index 000000000..66e0fd742 --- /dev/null +++ b/toolkit/jetpack/sdk/ui/buttons.js @@ -0,0 +1,198 @@ +/* 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/. + * PMkit shim for 'sdk/ui/button', (c) JustOff, 2017 */ +"use strict"; + +module.metadata = { + "stability": "experimental", + "engines": { + "Palemoon": "> 27" + } +}; + +const { Ci, Cc } = require('chrome'); +const prefs = require('../preferences/service'); + +const buttonsList = new Map(); +const LOCATION_PREF_ROOT = "extensions.sdk-button-location."; + +let gWindowListener; + +function getLocation(id) { + let toolbarId = "nav-bar", nextItemId = ""; + let location = prefs.get(LOCATION_PREF_ROOT + id); + if (location && location.indexOf(",") !== -1) { + [toolbarId, nextItemId] = location.split(","); + } + return [toolbarId, nextItemId]; +} + +function saveLocation(id, toolbarId, nextItemId) { + let _toolbarId = toolbarId || ""; + let _nextItemId = nextItemId || ""; + prefs.set(LOCATION_PREF_ROOT + id, [_toolbarId, _nextItemId].join(",")); +} + +// Insert button into window +function insertButton(aWindow, id, onBuild) { + // Build button and save reference to it + let doc = aWindow.document; + let b = onBuild(doc, id); + aWindow[id] = b; + + // Add to the customization palette + let toolbox = doc.getElementById("navigator-toolbox"); + toolbox.palette.appendChild(b); + + // Retrieve button location from preferences + let [toolbarId, nextItemId] = getLocation(id); + let toolbar = toolbarId != "" && doc.getElementById(toolbarId); + + if (toolbar) { + let nextItem = doc.getElementById(nextItemId); + // If nextItem not in toolbar then retrieve it by reading currentset attribute + if (!(nextItem && nextItem.parentNode && nextItem.parentNode.id == toolbarId)) { + nextItem = null; + let currentSet = toolbar.getAttribute("currentset"); + let ids = (currentSet == "__empty") ? [] : currentSet.split(","); + let idx = ids.indexOf(id); + if (idx != -1) { + for (let i = idx; i < ids.length; i++) { + nextItem = doc.getElementById(ids[i]); + if (nextItem) + break; + } + } + } + // Finally insert button in the right toolbar and in the right position + toolbar.insertItem(id, nextItem, null, false); + } +} + +// Remove button from window +function removeButton(aWindow, id) { + let b = aWindow[id]; + b.parentNode.removeChild(b); + delete aWindow[id]; +} + +// Save locations of buttons after customization +function afterCustomize(e) { + for (let [id] of buttonsList) { + let toolbox = e.target; + let b = toolbox.parentNode.querySelector("#" + id); + let toolbarId = null, nextItemId = null; + if (b) { + let parent = b.parentNode; + let nextItem = b.nextSibling; + if (parent && parent.localName == "toolbar") { + toolbarId = parent.id; + nextItemId = nextItem && nextItem.id; + } + } + saveLocation(id, toolbarId, nextItemId); + } +} + +// Global window observer +function browserWindowObserver(handlers) { + this.handlers = handlers; +} + +browserWindowObserver.prototype = { + observe: function(aSubject, aTopic, aData) { + if (aTopic == "domwindowopened") { + aSubject.QueryInterface(Ci.nsIDOMWindow).addEventListener("load", this, false); + } else if (aTopic == "domwindowclosed") { + if (aSubject.document.documentElement.getAttribute("windowtype") == "navigator:browser") { + this.handlers.onShutdown(aSubject); + } + } + }, + + handleEvent: function(aEvent) { + let aWindow = aEvent.currentTarget; + aWindow.removeEventListener(aEvent.type, this, false); + + if (aWindow.document.documentElement.getAttribute("windowtype") == "navigator:browser") { + this.handlers.onStartup(aWindow); + } + } +}; + +// Run on every window startup +function browserWindowStartup(aWindow) { + for (let [id, onBuild] of buttonsList) { + insertButton(aWindow, id, onBuild); + } + aWindow.addEventListener("aftercustomization", afterCustomize, false); +}; + +// Run on every window shutdown +function browserWindowShutdown(aWindow) { + for (let [id, onBuild] of buttonsList) { + removeButton(aWindow, id); + } + aWindow.removeEventListener("aftercustomization", afterCustomize, false); +} + +// Main object +const buttons = { + createButton: function(aProperties) { + // If no buttons were inserted yet, setup global window observer + if (buttonsList.size == 0) { + let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher); + gWindowListener = new browserWindowObserver({ + onStartup: browserWindowStartup, + onShutdown: browserWindowShutdown + }); + ww.registerNotification(gWindowListener); + } + + // Add button to list + buttonsList.set(aProperties.id, aProperties.onBuild); + + // Inster button to all open windows + let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator); + let winenu = wm.getEnumerator("navigator:browser"); + while (winenu.hasMoreElements()) { + let win = winenu.getNext(); + insertButton(win, aProperties.id, aProperties.onBuild); + // When first button inserted, add afterCustomize listener + if (buttonsList.size == 1) { + win.addEventListener("aftercustomization", afterCustomize, false); + } + } + }, + + destroyButton: function(id) { + // Remove button from list + buttonsList.delete(id); + + // If no more buttons exist, remove global window observer + if (buttonsList.size == 0) { + let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher); + ww.unregisterNotification(gWindowListener); + gWindowListener = null; + } + + // Remove button from all open windows + let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator); + let winenu = wm.getEnumerator("navigator:browser"); + while (winenu.hasMoreElements()) { + let win = winenu.getNext(); + removeButton(win, id); + // If no more buttons exist, remove afterCustomize listener + if (buttonsList.size == 0) { + win.removeEventListener("aftercustomization", afterCustomize, false); + } + } + }, + + getNode: function(id, window) { + return window[id]; + } +}; + +exports.buttons = buttons; diff --git a/toolkit/jetpack/sdk/ui/state.js b/toolkit/jetpack/sdk/ui/state.js index 152ce696d..c90d4283d 100644 --- a/toolkit/jetpack/sdk/ui/state.js +++ b/toolkit/jetpack/sdk/ui/state.js @@ -8,6 +8,7 @@ module.metadata = { 'stability': 'experimental', 'engines': { + 'Palemoon': '*', 'Firefox': '*', 'SeaMonkey': '*', 'Thunderbird': '*' diff --git a/toolkit/jetpack/sdk/ui/state/events.js b/toolkit/jetpack/sdk/ui/state/events.js index 98909656a..34d14be3a 100644 --- a/toolkit/jetpack/sdk/ui/state/events.js +++ b/toolkit/jetpack/sdk/ui/state/events.js @@ -7,6 +7,7 @@ module.metadata = { 'stability': 'experimental', 'engines': { + 'Palemoon': '*', 'Firefox': '*', 'SeaMonkey': '*', 'Thunderbird': '*' diff --git a/toolkit/locales/en-US/chrome/global/aboutRights.dtd b/toolkit/locales/en-US/chrome/global/aboutRights.dtd index 319984d41..28b24e1d8 100644 --- a/toolkit/locales/en-US/chrome/global/aboutRights.dtd +++ b/toolkit/locales/en-US/chrome/global/aboutRights.dtd @@ -19,12 +19,12 @@ <!ENTITY rights.intro-point1b "Mozilla Public License"> <!ENTITY rights.intro-point1c ". This means you may use, copy and distribute &brandShortName; to others. You are also welcome to modify the source code of &brandShortName; as you want to meet your needs. The Mozilla Public License also gives you the right to distribute your modified versions."> -<!ENTITY rights.intro-point2-a "You are not granted any trademark rights or licenses to the trademarks of the Mozilla Foundation or any party, including without limitation the Firefox name or logo. Additional information on trademarks may be found "> +<!ENTITY rights.intro-point2-a "You are not granted any trademark rights or licenses to the trademarks of Moonchild Productions or any other party, including without limitation the Basilisk and Pale Moon names or logos. Additional information on trademarks may be found "> <!ENTITY rights.intro-point2-b "here"> <!ENTITY rights.intro-point2-c "."> <!-- point 2.5 text for official branded builds --> -<!ENTITY rights.intro-point2.5 "Some features in &brandShortName;, such as the Crash Reporter, give you the option to provide feedback to &vendorShortName;. By choosing to submit feedback, you give &vendorShortName; permission to use the feedback to improve its products, to publish the feedback on its websites, and to distribute the feedback."> +<!ENTITY rights.intro-point2.5 "Some features in &brandShortName; give you the option to provide feedback to the publishers of this software. By choosing to submit feedback, you give the publishers in question permission to use the feedback to improve their products, to publish the feedback on their websites, and to distribute the feedback."> <!-- point 3 text for official branded builds --> <!ENTITY rights2.intro-point3a "How we use your personal information and feedback submitted to &vendorShortName; through &brandShortName; is described in the "> @@ -47,7 +47,7 @@ <!ENTITY rights2.webservices-header "&brandFullName; Web-Based Information Services"> <!-- point 5 --> -<!ENTITY rights.intro-point5 "In order to play back certain types of video content, &brandShortName; downloads certain content decryption modules from third parties."> +<!ENTITY rights.intro-point5 "In order to play back certain types of video content, &brandShortName; may download certain content decryption modules from third parties, if playback of DRM content is enabled or available."> <!-- Note that this paragraph references a couple of entities from preferences/security.dtd, so that we can refer to text the user sees in @@ -59,6 +59,8 @@ <!ENTITY rights3.webservices-c ". Other features and Services can be disabled in the application preferences."> <!-- safe browsing points for branded builds --> +<!-- Google SafeBrowsing requires an API key; this should always remain disabled unless + an API key is obtained. Official builds do not use SafeBrowsing. --> <!ENTITY rights.safebrowsing-a "SafeBrowsing: "> <!ENTITY rights.safebrowsing-b "Disabling the Safe Browsing feature is not recommended as it may result in you going to unsafe sites. If you wish to disable the feature completely, follow these steps:"> <!ENTITY rights.safebrowsing-term1 "Open the application preferences"> @@ -67,6 +69,7 @@ <!ENTITY rights.safebrowsing-term4 "Safe Browsing is now disabled"> <!-- location aware browsing points for branded builds --> +<!-- Official builds use IP-API.com --> <!ENTITY rights.locationawarebrowsing-a "Location Aware Browsing: "> <!ENTITY rights.locationawarebrowsing-b "is always opt-in. No location information is ever sent without your permission. If you wish to disable the feature completely, follow these steps:"> <!ENTITY rights.locationawarebrowsing-term1a "In the URL bar, type "> @@ -82,10 +85,10 @@ <!ENTITY rights.webservices-term1-unbranded "Any applicable service terms for this product should be listed here."> <!-- points 1-7 text for branded builds --> -<!ENTITY rights2.webservices-term1 "&vendorShortName; and its contributors, licensors and partners work to provide the most accurate and up-to-date Services. However, we cannot guarantee that this information is comprehensive and error-free. For example, the Safe Browsing Service may not identify some risky sites and may identify some safe sites in error and the Location Aware Service all locations returned by our service providers are estimates only and neither we nor our service providers guarantee the accuracy of the locations provided."> +<!ENTITY rights2.webservices-term1 "&vendorShortName; and its contributors, licensors and partners work to provide the most accurate and up-to-date Services. However, we cannot guarantee that this information is comprehensive and error-free. For example, for the Location Aware Service all locations returned by our service provider are estimates only and neither we nor our service provider guarantee the accuracy of the locations provided."> <!ENTITY rights.webservices-term2 "&vendorShortName; may discontinue or change the Services at its discretion."> -<!ENTITY rights2.webservices-term3 "You are welcome to use these Services with the accompanying version of &brandShortName;, and &vendorShortName; grants you its rights to do so. &vendorShortName; and its licensors reserve all other rights in the Services. These terms are not intended to limit any rights granted under open source licenses applicable to &brandShortName; and to corresponding source code versions of &brandShortName;."> -<!ENTITY rights.webservices-term4 "The Services are provided "as-is." &vendorShortName;, its contributors, licensors, and distributors, disclaim all warranties, whether express or implied, including without limitation, warranties that the Services are merchantable and fit for your particular purposes. You bear the entire risk as to selecting the Services for your purposes and as to the quality and performance of the Services. Some jurisdictions do not allow the exclusion or limitation of implied warranties, so this disclaimer may not apply to you."> -<!ENTITY rights.webservices-term5 "Except as required by law, &vendorShortName;, its contributors, licensors, and distributors will not be liable for any indirect, special, incidental, consequential, punitive, or exemplary damages arising out of or in any way relating to the use of &brandShortName; and the Services. The collective liability under these terms will not exceed $500 (five hundred dollars). Some jurisdictions do not allow the exclusion or limitation of certain damages, so this exclusion and limitation may not apply to you."> +<!ENTITY rights2.webservices-term3 "You are welcome to use these Services with the accompanying version of &brandShortName;, and &vendorShortName; grants you its rights to do so. &vendorShortName; and its licensors reserve all other rights in the Services. These terms are not intended to limit any rights granted under open source licenses applicable to &brandShortName; and to corresponding source code versions of &brandShortName;, however these (optional) services are provided asa convenience to you, and in no way extend your software rights to the Services."> +<!ENTITY rights.webservices-term4 "The Services are provided "as-is" and "as-available". &vendorShortName;, its contributors, licensors and distributors disclaim all warranties, whether express or implied, including without limitation warranties that the Services are merchantable and fit for your particular purposes. You bear the entire risk as to selecting the Services for your purposes and as to the quality and performance of the Services. If your jurisdiction does not allow disclaiming of warranties, then you should not use &brandShortName; or Services."> +<!ENTITY rights.webservices-term5 "Except as required by law, &vendorShortName;, its contributors, licensors, and distributors will not be liable for any indirect, special, incidental, consequential, punitive, or exemplary damages arising out of or in any way relating to the use of &brandShortName; and the Services. The collective liability under these terms will not exceed $500 (five hundred dollars). If your jurisdiction does not allow the exclusion or limitation of damages, then you should not use &brandShortName; or Services."> <!ENTITY rights.webservices-term6 "&vendorShortName; may update these terms as necessary from time to time. These terms may not be modified or canceled without &vendorShortName;'s written agreement."> -<!ENTITY rights.webservices-term7 "These terms are governed by the laws of the state of California, U.S.A., excluding its conflict of law provisions. If any portion of these terms is held to be invalid or unenforceable, the remaining portions will remain in full force and effect. In the event of a conflict between a translated version of these terms and the English language version, the English language version shall control."> +<!ENTITY rights.webservices-term7 "These terms are governed by the laws of Sweden, excluding any conflict of law provisions. If any portion of these terms is held to be invalid or unenforceable, the remaining portions will remain in full force and effect. In the event of a conflict between a translated version of these terms and the English language version, the English language version shall take precedence."> diff --git a/toolkit/locales/en-US/chrome/global/autocomplete.properties b/toolkit/locales/en-US/chrome/global/autocomplete.properties index 5c7c84b96..44da643ac 100644 --- a/toolkit/locales/en-US/chrome/global/autocomplete.properties +++ b/toolkit/locales/en-US/chrome/global/autocomplete.properties @@ -1,6 +1,11 @@ # 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/. +switchToTab = Switch to tab + +# LOCALIZATION NOTE (visitURL): +# %S is the URL to visit. +visitURL = Visit %S # LOCALIZATION NOTE (searchWithEngine): %S will be replaced with # the search engine provider's name. This format was chosen because diff --git a/toolkit/locales/en-US/chrome/mozapps/preferences/changemp.dtd b/toolkit/locales/en-US/chrome/mozapps/preferences/changemp.dtd index 1cc7b9621..1b1d5ac55 100644 --- a/toolkit/locales/en-US/chrome/mozapps/preferences/changemp.dtd +++ b/toolkit/locales/en-US/chrome/mozapps/preferences/changemp.dtd @@ -9,5 +9,5 @@ <!ENTITY setPassword.reenterPassword.label "Re-enter password:"> <!ENTITY setPassword.meter.label "Password quality meter"> <!ENTITY setPassword.meter.loading "Loading"> -<!ENTITY masterPasswordDescription.label "A Master Password is used to protect sensitive information like site passwords. If you create a Master Password you will be asked to enter it once per session when &brandShortName; retrieves saved information protected by the password."> +<!ENTITY masterPasswordDescription.label "A Master Password is used to protect sensitive information like site passwords. If you create a Master Password you will be asked to enter it once per session when &brandShortName; retrieves saved information protected by the password. A master password must be 8 characters or longer; longer is better."> <!ENTITY masterPasswordWarning.label "Please make sure you remember the Master Password you have set. If you forget your Master Password, you will be unable to access any of the information protected by it."> diff --git a/toolkit/modules/ResetProfile.jsm b/toolkit/modules/ResetProfile.jsm index fe0d1cfe8..c1839af4f 100644 --- a/toolkit/modules/ResetProfile.jsm +++ b/toolkit/modules/ResetProfile.jsm @@ -11,7 +11,11 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/AppConstants.jsm"); -const MOZ_APP_NAME = AppConstants.MOZ_APP_NAME; +// For Basilisk and Pale Moon +// Hard-code MOZ_APP_NAME to firefox because of hard-coded type in migrator. +const MOZ_APP_NAME = (((AppConstants.MOZ_APP_NAME == "basilisk") + || (AppConstants.MOZ_APP_NAME == "palemoon")) + ? "firefox" : AppConstants.MOZ_APP_NAME); const MOZ_BUILD_APP = AppConstants.MOZ_BUILD_APP; this.ResetProfile = { diff --git a/toolkit/modules/addons/WebRequestContent.js b/toolkit/modules/addons/WebRequestContent.js index 219675e5b..f044a1cd4 100644 --- a/toolkit/modules/addons/WebRequestContent.js +++ b/toolkit/modules/addons/WebRequestContent.js @@ -80,6 +80,16 @@ var ContentPolicy = { shouldLoad(policyType, contentLocation, requestOrigin, node, mimeTypeGuess, extra, requestPrincipal) { + + // Loads of TYPE_DOCUMENT and TYPE_SUBDOCUMENT perform a ConPol check + // within docshell as well as within the ContentSecurityManager. To avoid + // duplicate evaluations we ignore ConPol checks performed within docShell. + if (extra instanceof Ci.nsISupportsString) { + if (extra.data === "conPolCheckFromDocShell") { + return Ci.nsIContentPolicy.ACCEPT; + } + } + if (requestPrincipal && Services.scriptSecurityManager.isSystemPrincipal(requestPrincipal)) { return Ci.nsIContentPolicy.ACCEPT; diff --git a/toolkit/modules/sessionstore/FormData.jsm b/toolkit/modules/sessionstore/FormData.jsm index f90ba5825..d4fb08d93 100644 --- a/toolkit/modules/sessionstore/FormData.jsm +++ b/toolkit/modules/sessionstore/FormData.jsm @@ -216,7 +216,7 @@ var FormDataInternal = { // We want to avoid saving data for about:sessionrestore as a string. // Since it's stored in the form as stringified JSON, stringifying further // causes an explosion of escape characters. cf. bug 467409 - if (isRestorationPage(ret.url)) { + if (isRestorationPage(ret.url) && ret.id && ret.id.sessionData) { ret.id.sessionData = JSON.parse(ret.id.sessionData); } diff --git a/toolkit/mozapps/extensions/internal/AddonRepository_SQLiteMigrator.jsm b/toolkit/mozapps/extensions/internal/AddonRepository_SQLiteMigrator.jsm index 11944ddf5..66147b9aa 100644 --- a/toolkit/mozapps/extensions/internal/AddonRepository_SQLiteMigrator.jsm +++ b/toolkit/mozapps/extensions/internal/AddonRepository_SQLiteMigrator.jsm @@ -60,7 +60,11 @@ this.AddonRepository_SQLiteMigrator = { this._retrieveStoredData((results) => { this._closeConnection(); - let resultArray = [addon for ([,addon] of Iterator(results))]; + // Tycho: let resultArray = [addon for ([,addon] of Iterator(results))]; + let resultArray = []; + for (let [,addon] of Iterator(results)) { + resultArray.push(addon); + } logger.debug(resultArray.length + " addons imported.") aCallback(resultArray); }); diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 2c5e3dfa7..c43811ba8 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -1931,12 +1931,10 @@ this.XPIProvider = { let chan; try { - chan = Services.io.newChannelFromURI2(aURI, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); + chan = NetUtil.newChannel({ + uri: aURI, + loadUsingSystemPrincipal: true + }); } catch (ex) { return null; @@ -4438,7 +4436,18 @@ this.XPIProvider = { if (aAddon.type == "locale") return; - if (!(aMethod in this.bootstrapScopes[aAddon.id])) { + let method = undefined; + try { + method = Components.utils.evalInSandbox(`${aMethod};`, + this.bootstrapScopes[aAddon.id], + "ECMAv5"); + } + catch (e) { + // An exception will be caught if the expected method is not defined. + // That will be logged below. + } + + if (!method) { logger.warn("Add-on " + aAddon.id + " is missing bootstrap method " + aMethod); return; } @@ -4457,9 +4466,9 @@ this.XPIProvider = { } logger.debug("Calling bootstrap method " + aMethod + " on " + aAddon.id + " version " + - aAddon.version); + aAddon.version); try { - this.bootstrapScopes[aAddon.id][aMethod](params, aReason); + method(params, aReason); } catch (e) { logger.warn("Exception running bootstrap method " + aMethod + " on " + aAddon.id, e); @@ -5456,21 +5465,17 @@ AddonInstall.prototype = { let requireBuiltIn = Preferences.get(PREF_INSTALL_REQUIREBUILTINCERTS, true); this.badCertHandler = new BadCertHandler(!requireBuiltIn); - this.channel = NetUtil.newChannel2(this.sourceURI, - null, - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); + this.channel = NetUtil.newChannel({ + uri: this.sourceURI, + loadUsingSystemPrincipal: true + }); this.channel.notificationCallbacks = this; if (this.channel instanceof Ci.nsIHttpChannel) { this.channel.setRequestHeader("Moz-XPI-Update", "1", true); if (this.channel instanceof Ci.nsIHttpChannelInternal) this.channel.forceAllowThirdPartyCookie = true; } - this.channel.asyncOpen(listener, null); + this.channel.asyncOpen2(listener); Services.obs.addObserver(this, "network:offline-about-to-go-offline", false); } diff --git a/toolkit/mozapps/extensions/test/addons/test_bootstrap_const/bootstrap.js b/toolkit/mozapps/extensions/test/addons/test_bootstrap_const/bootstrap.js new file mode 100644 index 000000000..498b76526 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_bootstrap_const/bootstrap.js @@ -0,0 +1,5 @@ +Components.utils.import("resource://gre/modules/Services.jsm");
+
+const install = function() {
+ Services.obs.notifyObservers(null, "addon-install", "");
+}
\ No newline at end of file diff --git a/toolkit/mozapps/extensions/test/addons/test_bootstrap_const/install.rdf b/toolkit/mozapps/extensions/test/addons/test_bootstrap_const/install.rdf new file mode 100644 index 000000000..af3a749ce --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_bootstrap_const/install.rdf @@ -0,0 +1,24 @@ +<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bootstrap@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+ <em:bootstrap>true</em:bootstrap>
+
+ <!-- Front End MetaData -->
+ <em:name>Test Bootstrap</em:name>
+ <em:description>Test Description</em:description>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>xpcshell@tests.mozilla.org</em:id>
+ <em:minVersion>1</em:minVersion>
+ <em:maxVersion>1</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ </Description>
+</RDF>
\ No newline at end of file diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap_const.js b/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap_const.js new file mode 100644 index 000000000..fb02b59be --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap_const.js @@ -0,0 +1,17 @@ +/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
+startupManager();
+
+add_task(function*() {
+ let sawInstall = false;
+ Services.obs.addObserver(function() {
+ sawInstall = true;
+ }, "addon-install", false);
+
+ yield promiseInstallAllFiles([do_get_addon("test_bootstrap_const")]);
+
+ ok(sawInstall);
+});
\ No newline at end of file diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini index bab072e83..2a12f147a 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini @@ -29,6 +29,7 @@ skip-if = os == "android" [test_bootstrap.js] # Bug 676992: test consistently hangs on Android skip-if = os == "android" +[test_bootstrap_const.js] [test_bootstrap_resource.js] [test_bug299716.js] # Bug 676992: test consistently hangs on Android diff --git a/toolkit/mozapps/preferences/changemp.js b/toolkit/mozapps/preferences/changemp.js index 82dd20128..71664b3e1 100644 --- a/toolkit/mozapps/preferences/changemp.js +++ b/toolkit/mozapps/preferences/changemp.js @@ -167,8 +167,8 @@ function setPasswordStrength() // length of the password var pwlength=(pw.length); - if (pwlength>5) - pwlength=5; + if (pwlength>10) + pwlength=10; // use of numbers in the password @@ -190,7 +190,7 @@ function setPasswordStrength() upper=3; - var pwstrength=((pwlength*10)-20) + (numeric*10) + (numsymbols*15) + (upper*10); + var pwstrength=((pwlength*5)-20) + (numeric*10) + (numsymbols*15) + (upper*10); // make sure we're give a value between 0 and 100 if ( pwstrength < 0 ) { @@ -227,6 +227,12 @@ function checkPasswords() } } + // Never accept short passwords < 8 chars + if (pw1.length < 8) { + ok.setAttribute("disabled", "true"); + return; + } + if (pw1 == pw2) { ok.setAttribute("disabled", "false"); } else diff --git a/toolkit/mozapps/preferences/changemp.xul b/toolkit/mozapps/preferences/changemp.xul index 14d02295e..b316fa42b 100644 --- a/toolkit/mozapps/preferences/changemp.xul +++ b/toolkit/mozapps/preferences/changemp.xul @@ -34,7 +34,7 @@ <rows> <row> <label control="oldpw">&setPassword.oldPassword.label;</label> - <textbox id="oldpw" type="password"/> + <textbox id="oldpw" type="password" size="18"/> <!-- This textbox is inserted as a workaround to the fact that making the 'type' & 'disabled' property of the 'oldpw' textbox toggle between ['password' & 'false'] and ['text' & 'true'] - as would be necessary if the menu has more @@ -46,12 +46,13 @@ </row> <row> <label control="pw1">&setPassword.newPassword.label;</label> - <textbox id="pw1" type="password" + <textbox id="pw1" type="password" size="18" oninput="setPasswordStrength(); checkPasswords();"/> </row> <row> <label control="pw2">&setPassword.reenterPassword.label;</label> - <textbox id="pw2" type="password" oninput="checkPasswords();"/> + <textbox id="pw2" type="password" size="18" + oninput="checkPasswords();"/> </row> </rows> </grid> diff --git a/toolkit/pluginproblem/content/pluginProblemBinding.css b/toolkit/pluginproblem/content/pluginProblemBinding.css index 48506de34..a545e3eba 100644 --- a/toolkit/pluginproblem/content/pluginProblemBinding.css +++ b/toolkit/pluginproblem/content/pluginProblemBinding.css @@ -19,6 +19,11 @@ object:-moz-handler-crashed, object:-moz-handler-clicktoplay, object:-moz-handler-vulnerable-updatable, object:-moz-handler-vulnerable-no-update { +%ifdef MC_PALEMOON + /* Initialize the overlay with visibility:hidden to prevent flickering if + * the plugin is too small to show the overlay */ + visibility: hidden; +%endif display: inline-block; overflow: hidden; opacity: 1 !important; diff --git a/toolkit/pluginproblem/content/pluginProblemContent.css b/toolkit/pluginproblem/content/pluginProblemContent.css index 43a9f52dc..cf8755635 100644 --- a/toolkit/pluginproblem/content/pluginProblemContent.css +++ b/toolkit/pluginproblem/content/pluginProblemContent.css @@ -51,6 +51,7 @@ a .mainBox:focus, line-height: initial; } +%ifndef MC_PALEMOON /* Initialize the overlay with visibility:hidden to prevent flickering if * the plugin is too small to show the overlay */ .mainBox > .hoverBox, @@ -62,6 +63,7 @@ a .mainBox:focus, .visible > .closeIcon { visibility: visible; } +%endif .mainBox[chromedir="rtl"] { direction: rtl; @@ -97,6 +99,10 @@ a .msgTapToPlay, :-moz-handler-blocked .msgBlocked, :-moz-handler-crashed .msgCrashed { display: block; + position: relative; + left: 0; + top: 0; + z-index: 9999; } .submitStatus[status] { diff --git a/toolkit/pluginproblem/jar.mn b/toolkit/pluginproblem/jar.mn index d0af1c82f..c027793de 100644 --- a/toolkit/pluginproblem/jar.mn +++ b/toolkit/pluginproblem/jar.mn @@ -5,6 +5,6 @@ toolkit.jar: % content pluginproblem %pluginproblem/ contentaccessible=yes pluginproblem/pluginProblem.xml (content/pluginProblem.xml) - pluginproblem/pluginProblemContent.css (content/pluginProblemContent.css) - pluginproblem/pluginProblemBinding.css (content/pluginProblemBinding.css) +* pluginproblem/pluginProblemContent.css (content/pluginProblemContent.css) +* pluginproblem/pluginProblemBinding.css (content/pluginProblemBinding.css) pluginproblem/pluginReplaceBinding.css (content/pluginReplaceBinding.css) diff --git a/toolkit/xre/MozMeegoAppService.h b/toolkit/xre/MozMeegoAppService.h deleted file mode 100644 index 063d03e02..000000000 --- a/toolkit/xre/MozMeegoAppService.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* 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/. */ - -#ifndef MOZMEEGOAPPSERVICE_H -#define MOZMEEGOAPPSERVICE_H - -#include <MApplicationService> - -/** - * App service class, which prevents registration to d-bus - * and allows multiple instances of application. This is - * required for Mozillas remote service to work, because - * it is initialized after MApplication. - */ -class MozMeegoAppService: public MApplicationService -{ - Q_OBJECT -public: - MozMeegoAppService(): MApplicationService(QString()) {} -public Q_SLOTS: - virtual QString registeredName() { return QString(); } - virtual bool isRegistered() { return false; } - virtual bool registerService() { return true; } -}; -#endif // MOZMEEGOAPPSERVICE_H diff --git a/toolkit/xre/ProfileReset.cpp b/toolkit/xre/ProfileReset.cpp index aef2d7746..c9e2ef8d4 100644 --- a/toolkit/xre/ProfileReset.cpp +++ b/toolkit/xre/ProfileReset.cpp @@ -31,13 +31,19 @@ static const char kProfileProperties[] = * Creates a new profile with a timestamp in the name to use for profile reset. */ nsresult -CreateResetProfile(nsIToolkitProfileService* aProfileSvc, nsIToolkitProfile* *aNewProfile) +CreateResetProfile(nsIToolkitProfileService* aProfileSvc, const nsACString& aOldProfileName, nsIToolkitProfile* *aNewProfile) { MOZ_ASSERT(aProfileSvc, "NULL profile service"); nsCOMPtr<nsIToolkitProfile> newProfile; - // Make the new profile "default-" + the time in seconds since epoch for uniqueness. - nsAutoCString newProfileName("default-"); + // Make the new profile the old profile (or "default-") + the time in seconds since epoch for uniqueness. + nsAutoCString newProfileName; + if (!aOldProfileName.IsEmpty()) { + newProfileName.Assign(aOldProfileName); + newProfileName.Append("-"); + } else { + newProfileName.Assign("default-"); + } newProfileName.Append(nsPrintfCString("%lld", PR_Now() / 1000)); nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us newProfileName, diff --git a/toolkit/xre/ProfileReset.h b/toolkit/xre/ProfileReset.h index 7b5efbc4e..a164fe075 100644 --- a/toolkit/xre/ProfileReset.h +++ b/toolkit/xre/ProfileReset.h @@ -11,6 +11,7 @@ static bool gProfileResetCleanupCompleted = false; static const char kResetProgressURL[] = "chrome://global/content/resetProfileProgress.xul"; nsresult CreateResetProfile(nsIToolkitProfileService* aProfileSvc, + const nsACString& aOldProfileName, nsIToolkitProfile* *aNewProfile); nsresult ProfileResetCleanup(nsIToolkitProfile* aOldProfile); diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 530e4a353..3493cd837 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -1357,7 +1357,9 @@ DumpHelp() " -v or --version Print %s version.\n" " -P <profile> Start with <profile>.\n" " --profile <path> Start with profile at <path>.\n" +#ifdef MC_BASILISK " --migration Start with migration wizard.\n" +#endif " --ProfileManager Start with ProfileManager.\n" " --no-remote Do not accept or send remote commands;\n" " implies --new-instance.\n" @@ -1886,17 +1888,20 @@ ShowProfileManager(nsIToolkitProfileService* aProfileSvc, } /** - * Set the currently running profile as the default/selected one. + * Get the currently running profile using its root directory. * + * @param aProfileSvc The profile service * @param aCurrentProfileRoot The root directory of the current profile. - * @return an error if aCurrentProfileRoot is not found or the profile could not - * be set as the default. + * @param aProfile Out-param that returns the profile object. + * @return an error if aCurrentProfileRoot is not found */ static nsresult -SetCurrentProfileAsDefault(nsIToolkitProfileService* aProfileSvc, - nsIFile* aCurrentProfileRoot) +GetCurrentProfile(nsIToolkitProfileService* aProfileSvc, + nsIFile* aCurrentProfileRoot, + nsIToolkitProfile** aProfile) { NS_ENSURE_ARG_POINTER(aProfileSvc); + NS_ENSURE_ARG_POINTER(aProfile); nsCOMPtr<nsISimpleEnumerator> profiles; nsresult rv = aProfileSvc->GetProfiles(getter_AddRefs(profiles)); @@ -1912,7 +1917,8 @@ SetCurrentProfileAsDefault(nsIToolkitProfileService* aProfileSvc, profile->GetRootDir(getter_AddRefs(profileRoot)); profileRoot->Equals(aCurrentProfileRoot, &foundMatchingProfile); if (foundMatchingProfile) { - return aProfileSvc->SetSelectedProfile(profile); + profile.forget(aProfile); + return NS_OK; } rv = profiles->GetNext(getter_AddRefs(supports)); } @@ -2000,7 +2006,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n if (gDoProfileReset) { // If we're resetting a profile, create a new one and use it to startup. nsCOMPtr<nsIToolkitProfile> newProfile; - rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile)); + rv = CreateResetProfile(aProfileSvc, gResetOldProfileName, getter_AddRefs(newProfile)); if (NS_SUCCEEDED(rv)) { rv = newProfile->GetRootDir(getter_AddRefs(lf)); NS_ENSURE_SUCCESS(rv, rv); @@ -2146,20 +2152,20 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock); } - nsCOMPtr<nsIToolkitProfile> newProfile; - rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile)); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to create a profile to reset to."); - gDoProfileReset = false; - } else { - nsresult gotName = profile->GetName(gResetOldProfileName); - if (NS_SUCCEEDED(gotName)) { - profile = newProfile; - } else { - NS_WARNING("Failed to get the name of the profile we're resetting, so aborting reset."); - gResetOldProfileName.Truncate(0); + nsresult gotName = profile->GetName(gResetOldProfileName); + if (NS_SUCCEEDED(gotName)) { + nsCOMPtr<nsIToolkitProfile> newProfile; + rv = CreateResetProfile(aProfileSvc, gResetOldProfileName, getter_AddRefs(newProfile)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to create a profile to reset to."); gDoProfileReset = false; + } else { + profile = newProfile; } + } else { + NS_WARNING("Failed to get the name of the profile we're resetting, so aborting reset."); + gResetOldProfileName.Truncate(0); + gDoProfileReset = false; } } @@ -2254,20 +2260,22 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock); } - nsCOMPtr<nsIToolkitProfile> newProfile; - rv = CreateResetProfile(aProfileSvc, getter_AddRefs(newProfile)); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to create a profile to reset to."); - gDoProfileReset = false; - } else { - nsresult gotName = profile->GetName(gResetOldProfileName); - if (NS_SUCCEEDED(gotName)) { - profile = newProfile; - } else { - NS_WARNING("Failed to get the name of the profile we're resetting, so aborting reset."); - gResetOldProfileName.Truncate(0); + nsresult gotName = profile->GetName(gResetOldProfileName); + if (NS_SUCCEEDED(gotName)) { + nsCOMPtr<nsIToolkitProfile> newProfile; + rv = CreateResetProfile(aProfileSvc, gResetOldProfileName, getter_AddRefs(newProfile)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to create a profile to reset to."); gDoProfileReset = false; } + else { + profile = newProfile; + } + } + else { + NS_WARNING("Failed to get the name of the profile we're resetting, so aborting reset."); + gResetOldProfileName.Truncate(0); + gDoProfileReset = false; } } @@ -3739,7 +3747,12 @@ XREMain::XRE_mainRun() if (gDoProfileReset) { // Automatically migrate from the current application if we just // reset the profile. - aKey = MOZ_APP_NAME; + // For Basilisk and Pale Moon: + // Hard-code MOZ_APP_NAME to firefox because of hard-coded type in migrator. + aKey = (((MOZ_APP_NAME == "basilisk") + || (MOZ_APP_NAME == "palemoon")) + ? "firefox" : MOZ_APP_NAME); + } pm->Migrate(&mDirProvider, aKey, gResetOldProfileName); } @@ -3749,15 +3762,23 @@ XREMain::XRE_mainRun() nsresult backupCreated = ProfileResetCleanup(profileBeingReset); if (NS_FAILED(backupCreated)) NS_WARNING("Could not cleanup the profile that was reset"); - // Set the new profile as the default after we're done cleaning up the old profile, - // iff that profile was already the default - if (profileWasSelected) { - // this is actually "broken" - see bug 1122124 - rv = SetCurrentProfileAsDefault(mProfileSvc, mProfD); - if (NS_FAILED(rv)) NS_WARNING("Could not set current profile as the default"); + nsCOMPtr<nsIToolkitProfile> newProfile; + rv = GetCurrentProfile(mProfileSvc, mProfD, getter_AddRefs(newProfile)); + if (NS_SUCCEEDED(rv)) { + newProfile->SetName(gResetOldProfileName); + mProfileName.Assign(gResetOldProfileName); + // Set the new profile as the default after we're done cleaning up the old profile, + // iff that profile was already the default + if (profileWasSelected) { + rv = mProfileSvc->SetDefaultProfile(newProfile); + if (NS_FAILED(rv)) NS_WARNING("Could not set current profile as the default"); + } + } else { + NS_WARNING("Could not find current profile to set as default / change name."); } - // Need to write out the fact that the profile has been removed and potentially - // that the selected/default profile changed. + + // Need to write out the fact that the profile has been removed, the new profile + // renamed, and potentially that the selected/default profile changed. mProfileSvc->Flush(); } } @@ -4285,7 +4306,6 @@ MultiprocessBlockPolicy() { if (addonsCanDisable && disabledByAddons) { gMultiprocessBlockPolicy = kE10sDisabledForAddons; - return gMultiprocessBlockPolicy; } #if defined(XP_WIN) @@ -4319,16 +4339,13 @@ MultiprocessBlockPolicy() { if (disabledForA11y) { gMultiprocessBlockPolicy = kE10sDisabledForAccessibility; - return gMultiprocessBlockPolicy; } #endif + + // We do not support E10S, block by policy. + gMultiprocessBlockPolicy = kE10sForceDisabled; - /* - * None of the blocking policies matched, so e10s is allowed to run. - * Cache the information and return 0, indicating success. - */ - gMultiprocessBlockPolicy = 0; - return 0; + return gMultiprocessBlockPolicy; } bool diff --git a/widget/GfxInfoX11.cpp b/widget/GfxInfoX11.cpp index 4297aaa93..48fc3dbb5 100644 --- a/widget/GfxInfoX11.cpp +++ b/widget/GfxInfoX11.cpp @@ -23,7 +23,7 @@ NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug) #endif // these global variables will be set when firing the glxtest process -int glxtest_pipe = 0; +int glxtest_pipe = -1; pid_t glxtest_pid = 0; nsresult @@ -50,8 +50,8 @@ GfxInfo::GetData() // to understand this function, see bug 639842. We retrieve the OpenGL driver information in a // separate process to protect against bad drivers. - // if glxtest_pipe == 0, that means that we already read the information - if (!glxtest_pipe) + // if glxtest_pipe == -1, that means that we already read the information + if (glxtest_pipe == -1) return; enum { buf_size = 1024 }; @@ -60,7 +60,7 @@ GfxInfo::GetData() &buf, buf_size-1); // -1 because we'll append a zero close(glxtest_pipe); - glxtest_pipe = 0; + glxtest_pipe = -1; // bytesread < 0 would mean that the above read() call failed. // This should never happen. If it did, the outcome would be to blacklist anyway. diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h index 643132618..442ac41e8 100644 --- a/widget/MouseEvents.h +++ b/widget/MouseEvents.h @@ -43,22 +43,31 @@ namespace dom { class WidgetPointerHelper { public: - bool convertToPointer; uint32_t pointerId; uint32_t tiltX; uint32_t tiltY; - bool retargetedByPointerCapture; + uint32_t twist; + float tangentialPressure; + bool convertToPointer; - WidgetPointerHelper() : convertToPointer(true), pointerId(0), tiltX(0), tiltY(0), - retargetedByPointerCapture(false) {} + WidgetPointerHelper() + : pointerId(0) + , tiltX(0) + , tiltY(0) + , twist(0) + , tangentialPressure(0) + , convertToPointer(true) + { + } void AssignPointerHelperData(const WidgetPointerHelper& aEvent) { - convertToPointer = aEvent.convertToPointer; pointerId = aEvent.pointerId; tiltX = aEvent.tiltX; tiltY = aEvent.tiltY; - retargetedByPointerCapture = aEvent.retargetedByPointerCapture; + twist = aEvent.twist; + tangentialPressure = aEvent.tangentialPressure; + convertToPointer = aEvent.convertToPointer; } }; diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h index 7a9d870d9..e45189bb1 100644 --- a/widget/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h @@ -219,6 +219,34 @@ struct ParamTraits<mozilla::WidgetWheelEvent> }; template<> +struct ParamTraits<mozilla::WidgetPointerHelper> +{ + typedef mozilla::WidgetPointerHelper paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.pointerId); + WriteParam(aMsg, aParam.tiltX); + WriteParam(aMsg, aParam.tiltY); + WriteParam(aMsg, aParam.twist); + WriteParam(aMsg, aParam.tangentialPressure); + // We don't serialize convertToPointer since it's temporarily variable and + // should be reset to default. + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + bool rv; + rv = ReadParam(aMsg, aIter, &aResult->pointerId) && + ReadParam(aMsg, aIter, &aResult->tiltX) && + ReadParam(aMsg, aIter, &aResult->tiltY) && + ReadParam(aMsg, aIter, &aResult->twist) && + ReadParam(aMsg, aIter, &aResult->tangentialPressure); + return rv; + } +}; + +template<> struct ParamTraits<mozilla::WidgetMouseEvent> { typedef mozilla::WidgetMouseEvent paramType; @@ -226,13 +254,13 @@ struct ParamTraits<mozilla::WidgetMouseEvent> static void Write(Message* aMsg, const paramType& aParam) { WriteParam(aMsg, static_cast<mozilla::WidgetMouseEventBase>(aParam)); + WriteParam(aMsg, static_cast<mozilla::WidgetPointerHelper>(aParam)); WriteParam(aMsg, aParam.mIgnoreRootScrollFrame); WriteParam(aMsg, static_cast<paramType::ReasonType>(aParam.mReason)); WriteParam(aMsg, static_cast<paramType::ContextMenuTriggerType>( aParam.mContextMenuTrigger)); WriteParam(aMsg, static_cast<paramType::ExitFromType>(aParam.mExitFrom)); WriteParam(aMsg, aParam.mClickCount); - WriteParam(aMsg, aParam.pointerId); } static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) @@ -243,12 +271,13 @@ struct ParamTraits<mozilla::WidgetMouseEvent> paramType::ExitFromType exitFrom = 0; rv = ReadParam(aMsg, aIter, static_cast<mozilla::WidgetMouseEventBase*>(aResult)) && + ReadParam(aMsg, aIter, + static_cast<mozilla::WidgetPointerHelper*>(aResult)) && ReadParam(aMsg, aIter, &aResult->mIgnoreRootScrollFrame) && ReadParam(aMsg, aIter, &reason) && ReadParam(aMsg, aIter, &contextMenuTrigger) && ReadParam(aMsg, aIter, &exitFrom) && - ReadParam(aMsg, aIter, &aResult->mClickCount) && - ReadParam(aMsg, aIter, &aResult->pointerId); + ReadParam(aMsg, aIter, &aResult->mClickCount); aResult->mReason = static_cast<paramType::Reason>(reason); aResult->mContextMenuTrigger = static_cast<paramType::ContextMenuTrigger>(contextMenuTrigger); @@ -290,8 +319,6 @@ struct ParamTraits<mozilla::WidgetPointerEvent> WriteParam(aMsg, static_cast<mozilla::WidgetMouseEvent>(aParam)); WriteParam(aMsg, aParam.mWidth); WriteParam(aMsg, aParam.mHeight); - WriteParam(aMsg, aParam.tiltX); - WriteParam(aMsg, aParam.tiltY); WriteParam(aMsg, aParam.mIsPrimary); } @@ -301,8 +328,6 @@ struct ParamTraits<mozilla::WidgetPointerEvent> ReadParam(aMsg, aIter, static_cast<mozilla::WidgetMouseEvent*>(aResult)) && ReadParam(aMsg, aIter, &aResult->mWidth) && ReadParam(aMsg, aIter, &aResult->mHeight) && - ReadParam(aMsg, aIter, &aResult->tiltX) && - ReadParam(aMsg, aIter, &aResult->tiltY) && ReadParam(aMsg, aIter, &aResult->mIsPrimary); return rv; } diff --git a/widget/windows/nsClipboard.cpp b/widget/windows/nsClipboard.cpp index 1afee3496..0db1dd342 100644 --- a/widget/windows/nsClipboard.cpp +++ b/widget/windows/nsClipboard.cpp @@ -65,7 +65,7 @@ nsClipboard::nsClipboard() : nsBaseClipboard() nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1"); if (observerService) - observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); + observerService->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, PR_FALSE); } //------------------------------------------------------------------------- diff --git a/widget/windows/nsDataObj.cpp b/widget/windows/nsDataObj.cpp index 02ec3b2fe..977a87c08 100644 --- a/widget/windows/nsDataObj.cpp +++ b/widget/windows/nsDataObj.cpp @@ -443,6 +443,82 @@ STDMETHODIMP_(ULONG) nsDataObj::AddRef() return m_cRef; } +namespace { +class RemoveTempFileHelper : public nsIObserver +{ +public: + explicit RemoveTempFileHelper(nsIFile* aTempFile) + : mTempFile(aTempFile) + { + MOZ_ASSERT(mTempFile); + } + + // The attach method is seperate from the constructor as we may be addref-ing + // ourself, and we want to be sure someone has a strong reference to us. + void Attach() + { + // We need to listen to both the xpcom shutdown message and our timer, and + // fire when the first of either of these two messages is received. + nsresult rv; + mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + mTimer->Init(this, 500, nsITimer::TYPE_ONE_SHOT); + + nsCOMPtr<nsIObserverService> observerService = + do_GetService("@mozilla.org/observer-service;1"); + if (NS_WARN_IF(!observerService)) { + mTimer->Cancel(); + mTimer = nullptr; + return; + } + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + +private: + ~RemoveTempFileHelper() + { + if (mTempFile) { + mTempFile->Remove(false); + } + } + + nsCOMPtr<nsIFile> mTempFile; + nsCOMPtr<nsITimer> mTimer; +}; + +NS_IMPL_ISUPPORTS(RemoveTempFileHelper, nsIObserver); + +NS_IMETHODIMP +RemoveTempFileHelper::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) +{ + // Let's be careful and make sure that we don't die immediately + RefPtr<RemoveTempFileHelper> grip = this; + + // Make sure that we aren't called again by destroying references to ourself. + nsCOMPtr<nsIObserverService> observerService = + do_GetService("@mozilla.org/observer-service;1"); + if (observerService) { + observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + } + + if (mTimer) { + mTimer->Cancel(); + mTimer = nullptr; + } + + // Remove the tempfile + if (mTempFile) { + mTempFile->Remove(false); + mTempFile = nullptr; + } + return NS_OK; +} +} // namespace //----------------------------------------------------- STDMETHODIMP_(ULONG) nsDataObj::Release() @@ -456,17 +532,12 @@ STDMETHODIMP_(ULONG) nsDataObj::Release() // We have released our last ref on this object and need to delete the // temp file. External app acting as drop target may still need to open the // temp file. Addref a timer so it can delay deleting file and destroying - // this object. Delete file anyway and destroy this obj if there's a problem. + // this object. if (mCachedTempFile) { - nsresult rv; - mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); - if (NS_SUCCEEDED(rv)) { - mTimer->InitWithFuncCallback(nsDataObj::RemoveTempFile, this, - 500, nsITimer::TYPE_ONE_SHOT); - return AddRef(); - } - mCachedTempFile->Remove(false); + RefPtr<RemoveTempFileHelper> helper = + new RemoveTempFileHelper(mCachedTempFile); mCachedTempFile = nullptr; + helper->Attach(); } delete this; @@ -2153,13 +2224,3 @@ HRESULT nsDataObj::GetFileContents_IStream(FORMATETC& aFE, STGMEDIUM& aSTG) return S_OK; } - -void nsDataObj::RemoveTempFile(nsITimer* aTimer, void* aClosure) -{ - nsDataObj *timedDataObj = static_cast<nsDataObj *>(aClosure); - if (timedDataObj->mCachedTempFile) { - timedDataObj->mCachedTempFile->Remove(false); - timedDataObj->mCachedTempFile = nullptr; - } - timedDataObj->Release(); -} diff --git a/widget/windows/nsDataObj.h b/widget/windows/nsDataObj.h index 2d7fb75ee..61f209e85 100644 --- a/widget/windows/nsDataObj.h +++ b/widget/windows/nsDataObj.h @@ -289,7 +289,6 @@ protected: bool LookupArbitraryFormat(FORMATETC *aFormat, LPDATAENTRY *aDataEntry, BOOL aAddorUpdate); bool CopyMediumData(STGMEDIUM *aMediumDst, STGMEDIUM *aMediumSrc, LPFORMATETC aFormat, BOOL aSetData); - static void RemoveTempFile(nsITimer* aTimer, void* aClosure); }; diff --git a/xpcom/glue/PLDHashTable.cpp b/xpcom/glue/PLDHashTable.cpp index 6152e9000..5e932ccb2 100644 --- a/xpcom/glue/PLDHashTable.cpp +++ b/xpcom/glue/PLDHashTable.cpp @@ -216,17 +216,17 @@ PLDHashTable::operator=(PLDHashTable&& aOther) return *this; } - // Destruct |this|. - this->~PLDHashTable(); - - // |mOps| and |mEntrySize| are const so we can't assign them. Instead, we - // require that they are equal. The justification for this is that they're + // |mOps| and |mEntrySize| are required to stay the same, they're // conceptually part of the type -- indeed, if PLDHashTable was a templated // type like nsTHashtable, they *would* be part of the type -- so it only // makes sense to assign in cases where they match. MOZ_RELEASE_ASSERT(mOps == aOther.mOps); MOZ_RELEASE_ASSERT(mEntrySize == aOther.mEntrySize); + // Reconstruct |this|. + this->~PLDHashTable(); + new (KnownNotNull, this) PLDHashTable(aOther.mOps, aOther.mEntrySize, 0); + // Move non-const pieces over. mHashShift = Move(aOther.mHashShift); mEntryCount = Move(aOther.mEntryCount); diff --git a/xpcom/reflect/xptcall/md/unix/Makefile.in b/xpcom/reflect/xptcall/md/unix/Makefile.in index e4cdc389b..716d79623 100644 --- a/xpcom/reflect/xptcall/md/unix/Makefile.in +++ b/xpcom/reflect/xptcall/md/unix/Makefile.in @@ -7,17 +7,6 @@ # HPPA ###################################################################### # -# HP-UX/PA32 -# -# for gas and gcc, check comment in xptcinvoke_asm_pa32.s -ifeq ($(OS_ARCH),HP-UX) -ifneq ($(CC),gcc) -# #18875 Building the CPP's (CXX) optimized causes a crash -CXXFLAGS := $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(CXXFLAGS)) -endif -endif - -# # Linux/HPPA/gcc # ifeq ($(OS_ARCH),Linux) diff --git a/xpcom/reflect/xptcall/md/unix/moz.build b/xpcom/reflect/xptcall/md/unix/moz.build index 1d182bbd6..148d3bf35 100644 --- a/xpcom/reflect/xptcall/md/unix/moz.build +++ b/xpcom/reflect/xptcall/md/unix/moz.build @@ -108,23 +108,6 @@ if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['OS_ARCH'] in ('Bitrig', 'OpenBSD'): 'xptcstubs_arm_openbsd.cpp', ] -if CONFIG['OS_ARCH'] == 'HP-UX': - if CONFIG['CC'] != 'gcc': - if CONFIG['OS_TEST'] == 'ia64': - SOURCES += [ - 'xptcinvoke_asm_ipf32.s', - 'xptcinvoke_ipf32.cpp', - 'xptcstubs_asm_ipf32.s', - 'xptcstubs_ipf32.cpp', - ] - else: - SOURCES += [ - 'xptcinvoke_asm_pa32.s', - 'xptcinvoke_pa32.cpp', - 'xptcstubs_asm_pa32.s', - 'xptcstubs_pa32.cpp' - ] - if CONFIG['OS_ARCH'] == 'Linux': if CONFIG['OS_TEST'] in ('hppa', 'hppa2.0', 'hppa1.1'): if CONFIG['GNU_CXX']: diff --git a/xpcom/reflect/xptcall/status.html b/xpcom/reflect/xptcall/status.html index 65de20596..7f8e54a0c 100644 --- a/xpcom/reflect/xptcall/status.html +++ b/xpcom/reflect/xptcall/status.html @@ -255,21 +255,6 @@ The word I hear is that this is working and done <TR> <TD bgcolor="green"><font color="white"><b>Done</b></font></TD> -<TD>HP-UX</TD> -<TD> -<img alt="Contributed code!" title="Contributed code!" src="http://tinderbox.mozilla.org/star.gif"> -<a href="mailto:wang@cup.hp.com">Thomas Wang <wang@cup.hp.com></a><BR> -<img alt="Contributed code!" title="Contributed code!" src="http://tinderbox.mozilla.org/star.gif"> -<a href="mailto:mgleeson1@netscape.com">Mike Gleeson <mgleeson1@netscape.com></a> -</TD> -<TD>I hear that this code is checked in and working. Though, there is some -doubt - see bug -#<a href="http://bugzilla.mozilla.org/show_bug.cgi?id=17997">17997</a> -</TD> -</TR> - -<TR> -<TD bgcolor="green"><font color="white"><b>Done</b></font></TD> <TD>AIX PPC</TD> <TD><img alt="Contributed code!" title="Contributed code!" src="http://tinderbox.mozilla.org/star.gif"> <a href="mailto:jdunn@netscape.com">Jim Dunn <jdunn@netscape.com></a></TD> |