summaryrefslogtreecommitdiff
path: root/browser/components/statusbar
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/statusbar')
-rw-r--r--browser/components/statusbar/Downloads.jsm674
-rw-r--r--browser/components/statusbar/Progress.jsm183
-rw-r--r--browser/components/statusbar/Status.jsm492
-rw-r--r--browser/components/statusbar/Status4Evar.jsm312
-rw-r--r--browser/components/statusbar/Toolbars.jsm221
-rw-r--r--browser/components/statusbar/content-thunk.js23
-rw-r--r--browser/components/statusbar/content/overlay.css14
-rw-r--r--browser/components/statusbar/content/overlay.js16
-rw-r--r--browser/components/statusbar/content/overlay.xul82
-rw-r--r--browser/components/statusbar/content/prefs.css10
-rw-r--r--browser/components/statusbar/content/prefs.js274
-rw-r--r--browser/components/statusbar/content/prefs.xml704
-rw-r--r--browser/components/statusbar/content/prefs.xul297
-rw-r--r--browser/components/statusbar/content/tabbrowser.xml218
-rw-r--r--browser/components/statusbar/jar.mn15
-rw-r--r--browser/components/statusbar/moz.build24
-rw-r--r--browser/components/statusbar/status4evar.idl57
-rw-r--r--browser/components/statusbar/status4evar.js695
-rw-r--r--browser/components/statusbar/status4evar.manifest3
19 files changed, 4314 insertions, 0 deletions
diff --git a/browser/components/statusbar/Downloads.jsm b/browser/components/statusbar/Downloads.jsm
new file mode 100644
index 000000000..091fdad2e
--- /dev/null
+++ b/browser/components/statusbar/Downloads.jsm
@@ -0,0 +1,674 @@
+/* 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 EXPORTED_SYMBOLS = ["S4EDownloadService"];
+
+const CC = Components.classes;
+const CI = Components.interfaces;
+const CU = Components.utils;
+
+CU.import("resource://gre/modules/Services.jsm");
+CU.import("resource://gre/modules/PluralForm.jsm");
+CU.import("resource://gre/modules/DownloadUtils.jsm");
+CU.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
+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._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;
+ }
+ }
+};
+
+function JSTransferHandler(window, downloadService)
+{
+ this._window = window;
+
+ 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);
+}
+
+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();
+ }
+};
+
+function JSTransferListener(downloadService, listPromise, isPrivate)
+{
+ this._downloadService = downloadService;
+ this._isPrivate = isPrivate;
+ this._downloads = new Map();
+
+ 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);
+ }
+};
+
diff --git a/browser/components/statusbar/Progress.jsm b/browser/components/statusbar/Progress.jsm
new file mode 100644
index 000000000..69d55db49
--- /dev/null
+++ b/browser/components/statusbar/Progress.jsm
@@ -0,0 +1,183 @@
+/* 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 EXPORTED_SYMBOLS = ["S4EProgressService"];
+
+const CI = Components.interfaces;
+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.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 ])
+};
+
diff --git a/browser/components/statusbar/Status.jsm b/browser/components/statusbar/Status.jsm
new file mode 100644
index 000000000..dbdd1fc49
--- /dev/null
+++ b/browser/components/statusbar/Status.jsm
@@ -0,0 +1,492 @@
+/* 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 EXPORTED_SYMBOLS = ["S4EStatusService"];
+
+const CU = Components.utils;
+
+CU.import("resource://gre/modules/Services.jsm");
+CU.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function S4EStatusService(window, service, getters)
+{
+ this._window = window;
+ this._service = service;
+ this._getters = getters;
+
+ 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,
+ _isVideo: 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() {
+
+ // Object.prototype.watch() shim, based on Eli Grey's polyfill
+ // object.watch
+ if (!this._window.XULBrowserWindow.watch) {
+ Object.defineProperty(this._window.XULBrowserWindow, "watch", {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function (prop, handler) {
+ var oldval = this[prop],
+ newval = oldval,
+ getter = function () {
+ return newval;
+ },
+ setter = function (val) {
+ oldval = newval;
+ return newval = handler.call(this, prop, oldval, val);
+ }
+ ;
+
+ try {
+ if (delete this[prop]) { // can't watch constants
+ Object.defineProperty(this, prop, {
+ get: getter,
+ set: setter,
+ enumerable: true,
+ configurable: true
+ });
+ }
+ } catch(e) {
+ // This fails fatally on non-configurable props, so just
+ // ignore errors if it does.
+ }
+ }
+ });
+ }
+
+ // object.unwatch
+ if (!this._window.XULBrowserWindow.unwatch) {
+ Object.defineProperty(this._window.XULBrowserWindow, "unwatch", {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function (prop) {
+ var val = this[prop];
+ delete this[prop]; // remove accessors
+ this[prop] = val;
+ }
+ });
+ }
+
+ 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);
+ },
+
+ 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);
+ }
+ }
+ },
+
+ setFullScreenState: function(isFullScreen, isVideo)
+ {
+ this._isFullScreen = isFullScreen;
+ this._isVideo = isFullScreen && isVideo;
+
+ 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)
+ {
+ 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._isVideo)
+ {
+ 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;
+}
+
+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);
+ }
+};
+
diff --git a/browser/components/statusbar/Status4Evar.jsm b/browser/components/statusbar/Status4Evar.jsm
new file mode 100644
index 000000000..6400f2e2a
--- /dev/null
+++ b/browser/components/statusbar/Status4Evar.jsm
@@ -0,0 +1,312 @@
+/* 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 EXPORTED_SYMBOLS = ["Status4Evar"];
+
+const CC = Components.classes;
+const CI = Components.interfaces;
+const CU = Components.utils;
+
+const s4e_service = CC["@caligonstudios.com/status4evar;1"].getService(CI.nsIStatus4Evar);
+
+CU.import("resource://gre/modules/Services.jsm");
+CU.import("resource://gre/modules/XPCOMUtils.jsm");
+CU.import("resource://gre/modules/AddonManager.jsm");
+
+CU.import("resource:///modules/statusbar/Status.jsm");
+CU.import("resource:///modules/statusbar/Progress.jsm");
+CU.import("resource:///modules/statusbar/Downloads.jsm");
+CU.import("resource:///modules/statusbar/Toolbars.jsm");
+
+function Status4Evar(window, gBrowser, 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, gBrowser, this);
+
+ 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);
+ }
+
+};
+
+function S4EWindowGetters(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);
+ }
+};
+
+function SizeModeService(window, gBrowser, s4e)
+{
+ this._window = window;
+ this._gBrowser = gBrowser;
+ this._s4e = s4e;
+ this._mm = this._window.messageManager;
+
+ this.lastFullScreen = this._window.fullScreen;
+ this.lastwindowState = this._window.windowState;
+
+ if(s4e_service.advancedStatusDetectFullScreen)
+ {
+ this._mm.addMessageListener("status4evar@caligonstudios.com:video-detect-answer", this)
+ this._mm.loadFrameScript("resource:///modules/statusbar/content-thunk.js", true);
+ }
+
+ this._window.addEventListener("sizemodechange", this, false);
+}
+
+SizeModeService.prototype =
+{
+ _window: null,
+ _gBrowser: null,
+ _s4e: null,
+ _mm: null,
+
+ lastFullScreen: null,
+ lastwindowState: null,
+
+ destroy: function()
+ {
+ this._window.removeEventListener("sizemodechange", this, false);
+
+ if(s4e_service.advancedStatusDetectFullScreen)
+ {
+ this._mm.removeDelayedFrameScript("resource:///modules/statusbar/content-thunk.js");
+ this._mm.removeMessageListener("status4evar@caligonstudios.com:video-detect-answer", this);
+ }
+
+ ["_window", "_gBrowser", "_s4e", "_mm"].forEach(function(prop)
+ {
+ delete this[prop];
+ }, this);
+ },
+
+ handleEvent: function(e)
+ {
+ if(this._window.fullScreen != this.lastFullScreen && s4e_service.advancedStatusDetectFullScreen)
+ {
+ this.lastFullScreen = this._window.fullScreen;
+
+ if(this.lastFullScreen && s4e_service.advancedStatusDetectVideo)
+ {
+ this._gBrowser.selectedBrowser.messageManager.sendAsyncMessage("status4evar@caligonstudios.com:video-detect");
+ }
+ else
+ {
+ this._s4e.statusService.setFullScreenState(this.lastFullScreen, false);
+ }
+ }
+
+ if(this._window.windowState != this.lastwindowState)
+ {
+ this.lastwindowState = this._window.windowState;
+ this._s4e.toolbars.updateWindowGripper(true);
+ }
+ },
+
+ receiveMessage: function(message)
+ {
+ if(message.name == "status4evar@caligonstudios.com:video-detect-answer")
+ {
+ this._s4e.statusService.setFullScreenState(this.lastFullScreen, message.data.isVideo);
+ }
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([ CI.nsIDOMEventListener, CI.nsIMessageListener ])
+};
diff --git a/browser/components/statusbar/Toolbars.jsm b/browser/components/statusbar/Toolbars.jsm
new file mode 100644
index 000000000..321efd092
--- /dev/null
+++ b/browser/components/statusbar/Toolbars.jsm
@@ -0,0 +1,221 @@
+/* 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 EXPORTED_SYMBOLS = ["S4EToolbars"];
+
+const CI = Components.interfaces;
+const CU = Components.utils;
+
+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);
+}
+
+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);
+ }
+};
+
+function ClassicS4EToolbars(window, 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;
+ }
+};
diff --git a/browser/components/statusbar/content-thunk.js b/browser/components/statusbar/content-thunk.js
new file mode 100644
index 000000000..fe1fbabad
--- /dev/null
+++ b/browser/components/statusbar/content-thunk.js
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function handleVideoDetect(message)
+{
+ let isVideo = false;
+
+ let fsEl = content.document.mozFullScreenElement;
+ if(fsEl)
+ {
+ isVideo = (
+ fsEl.nodeName == "VIDEO"
+ || (fsEl.nodeName == "IFRAME" && fsEl.contentDocument && fsEl.contentDocument.getElementsByTagName("VIDEO").length > 0)
+ || fsEl.getElementsByTagName("VIDEO").length > 0
+ );
+ }
+
+ sendAsyncMessage("status4evar@caligonstudios.com:video-detect-answer", {isVideo: isVideo});
+}
+
+addMessageListener("status4evar@caligonstudios.com:video-detect", handleVideoDetect);
+
diff --git a/browser/components/statusbar/content/overlay.css b/browser/components/statusbar/content/overlay.css
new file mode 100644
index 000000000..fd3452119
--- /dev/null
+++ b/browser/components/statusbar/content/overlay.css
@@ -0,0 +1,14 @@
+/* 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");
+
+/*
+ * Status Popup
+ */
+
+statuspanel {
+ -moz-binding: url("chrome://browser/content/statusbar/tabbrowser.xml#statuspanel");
+}
+
diff --git a/browser/components/statusbar/content/overlay.js b/browser/components/statusbar/content/overlay.js
new file mode 100644
index 000000000..b868aaf0e
--- /dev/null
+++ b/browser/components/statusbar/content/overlay.js
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+if(!caligon) var caligon = {};
+
+window.addEventListener("load", function buildS4E()
+{
+ window.removeEventListener("load", buildS4E, false);
+
+ Components.utils.import("resource:///modules/statusbar/Status4Evar.jsm");
+
+ caligon.status4evar = new Status4Evar(window, gBrowser, gNavToolbox);
+ caligon.status4evar.setup();
+}, false);
+
diff --git a/browser/components/statusbar/content/overlay.xul b/browser/components/statusbar/content/overlay.xul
new file mode 100644
index 000000000..b9934ee65
--- /dev/null
+++ b/browser/components/statusbar/content/overlay.xul
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE overlay SYSTEM "chrome://browser/locale/statusbar/statusbar-overlay.dtd">
+
+<?xml-stylesheet href="chrome://browser/content/statusbar/overlay.css" type="text/css" ?>
+<?xml-stylesheet href="chrome://browser/skin/statusbar/overlay.css" type="text/css" ?>
+<?xml-stylesheet href="chrome://browser/skin/statusbar/dynamic.css" type="text/css" ?>
+
+<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>
+
+ <script type="application/javascript" src="chrome://browser/content/statusbar/overlay.js" />
+
+ <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>
+
+ <menupopup id="menu_ToolsPopup">
+ <menuitem id="statusbar-options-fx" command="S4E:Options"
+ label="&status4evar.menu.options.label;"/>
+ </menupopup>
+
+ <menupopup id="appmenu_customizeMenu">
+ <menuitem id="statusbar-options-app" command="S4E:Options"
+ 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>
+
+ <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>
+
+ <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/browser/components/statusbar/content/prefs.css b/browser/components/statusbar/content/prefs.css
new file mode 100644
index 000000000..bafaa6129
--- /dev/null
+++ b/browser/components/statusbar/content/prefs.css
@@ -0,0 +1,10 @@
+/* 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");
+
+.css-bg-editor {
+ -moz-binding: url("chrome://browser/content/statusbar/prefs.xml#css-bg-editor");
+}
+
diff --git a/browser/components/statusbar/content/prefs.js b/browser/components/statusbar/content/prefs.js
new file mode 100644
index 000000000..47fd4b63d
--- /dev/null
+++ b/browser/components/statusbar/content/prefs.js
@@ -0,0 +1,274 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+Components.utils.import("resource://gre/modules/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;
+ },
+
+//
+// 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;
+ }
+ }
+ },
+
+//
+// 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;
+ },
+
+//
+// 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;
+ }
+ }
+ },
+
+//
+// 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;
+ },
+
+//
+// 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);
+ },
+
+//
+// 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()
+ {
+ }
+}
+
+var XULBrowserWindow = {
+}
+
diff --git a/browser/components/statusbar/content/prefs.xml b/browser/components/statusbar/content/prefs.xml
new file mode 100644
index 000000000..44baab18d
--- /dev/null
+++ b/browser/components/statusbar/content/prefs.xml
@@ -0,0 +1,704 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE bindings SYSTEM "chrome://browser/locale/statusbar/statusbar-prefs.dtd">
+
+<bindings id="status4evar-prefs-bindings"
+ xmlns="http://www.mozilla.org/xbl"
+ 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" />
+<!--
+ <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: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>
+</bindings>
+
diff --git a/browser/components/statusbar/content/prefs.xul b/browser/components/statusbar/content/prefs.xul
new file mode 100644
index 000000000..dd4158246
--- /dev/null
+++ b/browser/components/statusbar/content/prefs.xul
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE prefwindow [
+ <!ENTITY % prefsDTD SYSTEM "chrome://browser/locale/statusbar/statusbar-prefs.dtd">
+ %prefsDTD;
+]>
+
+<?xml-stylesheet href="chrome://global/skin/config.css" type="text/css" ?>
+<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css" ?>
+
+<?xml-stylesheet href="chrome://browser/content/statusbar/overlay.css" type="text/css" ?>
+<?xml-stylesheet href="chrome://browser/skin/statusbar/overlay.css" type="text/css" ?>
+<?xml-stylesheet href="chrome://browser/skin/statusbar/dynamic.css" type="text/css" ?>
+
+<?xml-stylesheet href="chrome://browser/content/statusbar/prefs.css" type="text/css" ?>
+<?xml-stylesheet href="chrome://browser/skin/statusbar/prefs.css" type="text/css" ?>
+
+<prefwindow id="status4evar-prefs" title="&status4evar.window.title;"
+ 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" />
+
+ <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/browser/components/statusbar/content/tabbrowser.xml b/browser/components/statusbar/content/tabbrowser.xml
new file mode 100644
index 000000000..2f475771d
--- /dev/null
+++ b/browser/components/statusbar/content/tabbrowser.xml
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<bindings id="status4evar-bindings"
+ xmlns="http://www.mozilla.org/xbl"
+ 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>
+</bindings>
+
diff --git a/browser/components/statusbar/jar.mn b/browser/components/statusbar/jar.mn
new file mode 100644
index 000000000..b5a8d09b2
--- /dev/null
+++ b/browser/components/statusbar/jar.mn
@@ -0,0 +1,15 @@
+# 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/.
+
+browser.jar:
+% overlay chrome://browser/content/browser.xul chrome://browser/content/statusbar/overlay.xul
+% style chrome://global/content/customizeToolbar.xul chrome://browser/skin/statusbar/overlay.css
+ content/browser/statusbar/overlay.js (content/overlay.js)
+ content/browser/statusbar/prefs.js (content/prefs.js)
+ content/browser/statusbar/prefs.xml (content/prefs.xml)
+ content/browser/statusbar/tabbrowser.xml (content/tabbrowser.xml)
+ content/browser/statusbar/overlay.xul (content/overlay.xul)
+ content/browser/statusbar/prefs.xul (content/prefs.xul)
+ content/browser/statusbar/overlay.css (content/overlay.css)
+ content/browser/statusbar/prefs.css (content/prefs.css) \ No newline at end of file
diff --git a/browser/components/statusbar/moz.build b/browser/components/statusbar/moz.build
new file mode 100644
index 000000000..9d237181b
--- /dev/null
+++ b/browser/components/statusbar/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+JAR_MANIFESTS += [ 'jar.mn' ]
+
+XPIDL_SOURCES += [ 'status4evar.idl' ]
+
+XPIDL_MODULE = 'status4evar'
+
+EXTRA_COMPONENTS += [
+ 'status4evar.js',
+ 'status4evar.manifest',
+]
+
+EXTRA_JS_MODULES.statusbar = [
+ 'content-thunk.js',
+ 'Downloads.jsm',
+ 'Progress.jsm',
+ 'Status.jsm',
+ 'Status4Evar.jsm',
+ 'Toolbars.jsm',
+] \ No newline at end of file
diff --git a/browser/components/statusbar/status4evar.idl b/browser/components/statusbar/status4evar.idl
new file mode 100644
index 000000000..534dea31c
--- /dev/null
+++ b/browser/components/statusbar/status4evar.idl
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+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);
+};
+
diff --git a/browser/components/statusbar/status4evar.js b/browser/components/statusbar/status4evar.js
new file mode 100644
index 000000000..4aa2e3e78
--- /dev/null
+++ b/browser/components/statusbar/status4evar.js
@@ -0,0 +1,695 @@
+/* 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";
+
+// Component constants
+const CC = Components.classes;
+const CI = Components.interfaces;
+const CU = Components.utils;
+
+CU.import("resource://gre/modules/XPCOMUtils.jsm");
+CU.import("resource://gre/modules/Services.jsm");
+
+const CURRENT_MIGRATION = 8;
+
+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);
+ }
+};
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([Status_4_Evar]);
+
diff --git a/browser/components/statusbar/status4evar.manifest b/browser/components/statusbar/status4evar.manifest
new file mode 100644
index 000000000..4bcf697d6
--- /dev/null
+++ b/browser/components/statusbar/status4evar.manifest
@@ -0,0 +1,3 @@
+component {33d0433d-07be-4dc4-87fd-954057310efd} status4evar.js
+contract @caligonstudios.com/status4evar;1 {33d0433d-07be-4dc4-87fd-954057310efd}
+category profile-after-change Status-4-Evar @caligonstudios.com/status4evar;1