diff options
Diffstat (limited to 'application/palemoon')
48 files changed, 7345 insertions, 3934 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 |