summaryrefslogtreecommitdiffstats
path: root/toolkit/jetpack/sdk/ui/button/view.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/jetpack/sdk/ui/button/view.js')
-rw-r--r--toolkit/jetpack/sdk/ui/button/view.js243
1 files changed, 243 insertions, 0 deletions
diff --git a/toolkit/jetpack/sdk/ui/button/view.js b/toolkit/jetpack/sdk/ui/button/view.js
new file mode 100644
index 000000000..63b7aea31
--- /dev/null
+++ b/toolkit/jetpack/sdk/ui/button/view.js
@@ -0,0 +1,243 @@
+/* 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';
+
+module.metadata = {
+ 'stability': 'experimental',
+ 'engines': {
+ 'Firefox': '> 28'
+ }
+};
+
+const { Cu } = require('chrome');
+const { on, off, emit } = require('../../event/core');
+
+const { data } = require('sdk/self');
+
+const { isObject, isNil } = require('../../lang/type');
+
+const { getMostRecentBrowserWindow } = require('../../window/utils');
+const { ignoreWindow } = require('../../private-browsing/utils');
+const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
+const { AREA_PANEL, AREA_NAVBAR } = CustomizableUI;
+
+const { events: viewEvents } = require('./view/events');
+
+const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
+
+const views = new Map();
+const customizedWindows = new WeakMap();
+
+const buttonListener = {
+ onCustomizeStart: window => {
+ for (let [id, view] of views) {
+ setIcon(id, window, view.icon);
+ setLabel(id, window, view.label);
+ }
+
+ customizedWindows.set(window, true);
+ },
+ onCustomizeEnd: window => {
+ customizedWindows.delete(window);
+
+ for (let [id, ] of views) {
+ let placement = CustomizableUI.getPlacementOfWidget(id);
+
+ if (placement)
+ emit(viewEvents, 'data', { type: 'update', target: id, window: window });
+ }
+ },
+ onWidgetAfterDOMChange: (node, nextNode, container) => {
+ let { id } = node;
+ let view = views.get(id);
+ let window = node.ownerDocument.defaultView;
+
+ if (view) {
+ emit(viewEvents, 'data', { type: 'update', target: id, window: window });
+ }
+ }
+};
+
+CustomizableUI.addListener(buttonListener);
+
+require('../../system/unload').when( _ =>
+ CustomizableUI.removeListener(buttonListener)
+);
+
+function getNode(id, window) {
+ return !views.has(id) || ignoreWindow(window)
+ ? null
+ : CustomizableUI.getWidget(id).forWindow(window).node
+};
+
+function isInToolbar(id) {
+ let placement = CustomizableUI.getPlacementOfWidget(id);
+
+ return placement && CustomizableUI.getAreaType(placement.area) === 'toolbar';
+}
+
+
+function getImage(icon, isInToolbar, pixelRatio) {
+ let targetSize = (isInToolbar ? 18 : 32) * pixelRatio;
+ let bestSize = 0;
+ let image = icon;
+
+ if (isObject(icon)) {
+ for (let size of Object.keys(icon)) {
+ size = +size;
+ let offset = targetSize - size;
+
+ if (offset === 0) {
+ bestSize = size;
+ break;
+ }
+
+ let delta = Math.abs(offset) - Math.abs(targetSize - bestSize);
+
+ if (delta < 0)
+ bestSize = size;
+ }
+
+ image = icon[bestSize];
+ }
+
+ if (image.indexOf('./') === 0)
+ return data.url(image.substr(2));
+
+ return image;
+}
+
+function nodeFor(id, window=getMostRecentBrowserWindow()) {
+ return customizedWindows.has(window) ? null : getNode(id, window);
+};
+exports.nodeFor = nodeFor;
+
+function create(options) {
+ let { id, label, icon, type, badge } = options;
+
+ if (views.has(id))
+ throw new Error('The ID "' + id + '" seems already used.');
+
+ CustomizableUI.createWidget({
+ id: id,
+ type: 'custom',
+ removable: true,
+ defaultArea: AREA_NAVBAR,
+ allowedAreas: [ AREA_PANEL, AREA_NAVBAR ],
+
+ onBuild: function(document) {
+ let window = document.defaultView;
+
+ let node = document.createElementNS(XUL_NS, 'toolbarbutton');
+
+ let image = getImage(icon, true, window.devicePixelRatio);
+
+ if (ignoreWindow(window))
+ node.style.display = 'none';
+
+ node.setAttribute('id', this.id);
+ node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional badged-button');
+ node.setAttribute('type', type);
+ node.setAttribute('label', label);
+ node.setAttribute('tooltiptext', label);
+ node.setAttribute('image', image);
+ node.setAttribute('constrain-size', 'true');
+
+ views.set(id, {
+ area: this.currentArea,
+ icon: icon,
+ label: label
+ });
+
+ node.addEventListener('command', function(event) {
+ if (views.has(id)) {
+ emit(viewEvents, 'data', {
+ type: 'click',
+ target: id,
+ window: event.view,
+ checked: node.checked
+ });
+ }
+ });
+
+ return node;
+ }
+ });
+};
+exports.create = create;
+
+function dispose(id) {
+ if (!views.has(id)) return;
+
+ views.delete(id);
+ CustomizableUI.destroyWidget(id);
+}
+exports.dispose = dispose;
+
+function setIcon(id, window, icon) {
+ let node = getNode(id, window);
+
+ if (node) {
+ icon = customizedWindows.has(window) ? views.get(id).icon : icon;
+ let image = getImage(icon, isInToolbar(id), window.devicePixelRatio);
+
+ node.setAttribute('image', image);
+ }
+}
+exports.setIcon = setIcon;
+
+function setLabel(id, window, label) {
+ let node = nodeFor(id, window);
+
+ if (node) {
+ node.setAttribute('label', label);
+ node.setAttribute('tooltiptext', label);
+ }
+}
+exports.setLabel = setLabel;
+
+function setDisabled(id, window, disabled) {
+ let node = nodeFor(id, window);
+
+ if (node)
+ node.disabled = disabled;
+}
+exports.setDisabled = setDisabled;
+
+function setChecked(id, window, checked) {
+ let node = nodeFor(id, window);
+
+ if (node)
+ node.checked = checked;
+}
+exports.setChecked = setChecked;
+
+function setBadge(id, window, badge, color) {
+ let node = nodeFor(id, window);
+
+ if (node) {
+ // `Array.from` is needed to handle unicode symbol properly:
+ // '𝐀𝐁'.length is 4 where Array.from('𝐀𝐁').length is 2
+ let text = isNil(badge)
+ ? ''
+ : Array.from(String(badge)).slice(0, 4).join('');
+
+ node.setAttribute('badge', text);
+
+ let badgeNode = node.ownerDocument.getAnonymousElementByAttribute(node,
+ 'class', 'toolbarbutton-badge');
+
+ if (badgeNode)
+ badgeNode.style.backgroundColor = isNil(color) ? '' : color;
+ }
+}
+exports.setBadge = setBadge;
+
+function click(id) {
+ let node = nodeFor(id);
+
+ if (node)
+ node.click();
+}
+exports.click = click;