summaryrefslogtreecommitdiffstats
path: root/toolkit/jetpack/sdk/ui/buttons.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/jetpack/sdk/ui/buttons.js')
-rw-r--r--toolkit/jetpack/sdk/ui/buttons.js198
1 files changed, 198 insertions, 0 deletions
diff --git a/toolkit/jetpack/sdk/ui/buttons.js b/toolkit/jetpack/sdk/ui/buttons.js
new file mode 100644
index 000000000..66e0fd742
--- /dev/null
+++ b/toolkit/jetpack/sdk/ui/buttons.js
@@ -0,0 +1,198 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ * PMkit shim for 'sdk/ui/button', (c) JustOff, 2017 */
+"use strict";
+
+module.metadata = {
+ "stability": "experimental",
+ "engines": {
+ "Palemoon": "> 27"
+ }
+};
+
+const { Ci, Cc } = require('chrome');
+const prefs = require('../preferences/service');
+
+const buttonsList = new Map();
+const LOCATION_PREF_ROOT = "extensions.sdk-button-location.";
+
+let gWindowListener;
+
+function getLocation(id) {
+ let toolbarId = "nav-bar", nextItemId = "";
+ let location = prefs.get(LOCATION_PREF_ROOT + id);
+ if (location && location.indexOf(",") !== -1) {
+ [toolbarId, nextItemId] = location.split(",");
+ }
+ return [toolbarId, nextItemId];
+}
+
+function saveLocation(id, toolbarId, nextItemId) {
+ let _toolbarId = toolbarId || "";
+ let _nextItemId = nextItemId || "";
+ prefs.set(LOCATION_PREF_ROOT + id, [_toolbarId, _nextItemId].join(","));
+}
+
+// Insert button into window
+function insertButton(aWindow, id, onBuild) {
+ // Build button and save reference to it
+ let doc = aWindow.document;
+ let b = onBuild(doc, id);
+ aWindow[id] = b;
+
+ // Add to the customization palette
+ let toolbox = doc.getElementById("navigator-toolbox");
+ toolbox.palette.appendChild(b);
+
+ // Retrieve button location from preferences
+ let [toolbarId, nextItemId] = getLocation(id);
+ let toolbar = toolbarId != "" && doc.getElementById(toolbarId);
+
+ if (toolbar) {
+ let nextItem = doc.getElementById(nextItemId);
+ // If nextItem not in toolbar then retrieve it by reading currentset attribute
+ if (!(nextItem && nextItem.parentNode && nextItem.parentNode.id == toolbarId)) {
+ nextItem = null;
+ let currentSet = toolbar.getAttribute("currentset");
+ let ids = (currentSet == "__empty") ? [] : currentSet.split(",");
+ let idx = ids.indexOf(id);
+ if (idx != -1) {
+ for (let i = idx; i < ids.length; i++) {
+ nextItem = doc.getElementById(ids[i]);
+ if (nextItem)
+ break;
+ }
+ }
+ }
+ // Finally insert button in the right toolbar and in the right position
+ toolbar.insertItem(id, nextItem, null, false);
+ }
+}
+
+// Remove button from window
+function removeButton(aWindow, id) {
+ let b = aWindow[id];
+ b.parentNode.removeChild(b);
+ delete aWindow[id];
+}
+
+// Save locations of buttons after customization
+function afterCustomize(e) {
+ for (let [id] of buttonsList) {
+ let toolbox = e.target;
+ let b = toolbox.parentNode.querySelector("#" + id);
+ let toolbarId = null, nextItemId = null;
+ if (b) {
+ let parent = b.parentNode;
+ let nextItem = b.nextSibling;
+ if (parent && parent.localName == "toolbar") {
+ toolbarId = parent.id;
+ nextItemId = nextItem && nextItem.id;
+ }
+ }
+ saveLocation(id, toolbarId, nextItemId);
+ }
+}
+
+// Global window observer
+function browserWindowObserver(handlers) {
+ this.handlers = handlers;
+}
+
+browserWindowObserver.prototype = {
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic == "domwindowopened") {
+ aSubject.QueryInterface(Ci.nsIDOMWindow).addEventListener("load", this, false);
+ } else if (aTopic == "domwindowclosed") {
+ if (aSubject.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
+ this.handlers.onShutdown(aSubject);
+ }
+ }
+ },
+
+ handleEvent: function(aEvent) {
+ let aWindow = aEvent.currentTarget;
+ aWindow.removeEventListener(aEvent.type, this, false);
+
+ if (aWindow.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
+ this.handlers.onStartup(aWindow);
+ }
+ }
+};
+
+// Run on every window startup
+function browserWindowStartup(aWindow) {
+ for (let [id, onBuild] of buttonsList) {
+ insertButton(aWindow, id, onBuild);
+ }
+ aWindow.addEventListener("aftercustomization", afterCustomize, false);
+};
+
+// Run on every window shutdown
+function browserWindowShutdown(aWindow) {
+ for (let [id, onBuild] of buttonsList) {
+ removeButton(aWindow, id);
+ }
+ aWindow.removeEventListener("aftercustomization", afterCustomize, false);
+}
+
+// Main object
+const buttons = {
+ createButton: function(aProperties) {
+ // If no buttons were inserted yet, setup global window observer
+ if (buttonsList.size == 0) {
+ let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
+ gWindowListener = new browserWindowObserver({
+ onStartup: browserWindowStartup,
+ onShutdown: browserWindowShutdown
+ });
+ ww.registerNotification(gWindowListener);
+ }
+
+ // Add button to list
+ buttonsList.set(aProperties.id, aProperties.onBuild);
+
+ // Inster button to all open windows
+ let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+ let winenu = wm.getEnumerator("navigator:browser");
+ while (winenu.hasMoreElements()) {
+ let win = winenu.getNext();
+ insertButton(win, aProperties.id, aProperties.onBuild);
+ // When first button inserted, add afterCustomize listener
+ if (buttonsList.size == 1) {
+ win.addEventListener("aftercustomization", afterCustomize, false);
+ }
+ }
+ },
+
+ destroyButton: function(id) {
+ // Remove button from list
+ buttonsList.delete(id);
+
+ // If no more buttons exist, remove global window observer
+ if (buttonsList.size == 0) {
+ let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
+ ww.unregisterNotification(gWindowListener);
+ gWindowListener = null;
+ }
+
+ // Remove button from all open windows
+ let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+ let winenu = wm.getEnumerator("navigator:browser");
+ while (winenu.hasMoreElements()) {
+ let win = winenu.getNext();
+ removeButton(win, id);
+ // If no more buttons exist, remove afterCustomize listener
+ if (buttonsList.size == 0) {
+ win.removeEventListener("aftercustomization", afterCustomize, false);
+ }
+ }
+ },
+
+ getNode: function(id, window) {
+ return window[id];
+ }
+};
+
+exports.buttons = buttons;