addon-sdk/source/lib/sdk/ui/button/view.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/addon-sdk/source/lib/sdk/ui/button/view.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,222 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +'use strict';
     1.8 +
     1.9 +module.metadata = {
    1.10 +  'stability': 'experimental',
    1.11 +  'engines': {
    1.12 +    'Firefox': '> 28'
    1.13 +  }
    1.14 +};
    1.15 +
    1.16 +const { Cu } = require('chrome');
    1.17 +const { on, off, emit } = require('../../event/core');
    1.18 +
    1.19 +const { data } = require('sdk/self');
    1.20 +
    1.21 +const { isObject } = require('../../lang/type');
    1.22 +
    1.23 +const { getMostRecentBrowserWindow } = require('../../window/utils');
    1.24 +const { ignoreWindow } = require('../../private-browsing/utils');
    1.25 +const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
    1.26 +const { AREA_PANEL, AREA_NAVBAR } = CustomizableUI;
    1.27 +
    1.28 +const { events: viewEvents } = require('./view/events');
    1.29 +
    1.30 +const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
    1.31 +
    1.32 +const views = new Map();
    1.33 +const customizedWindows = new WeakMap();
    1.34 +
    1.35 +const buttonListener = {
    1.36 +  onCustomizeStart: window => {
    1.37 +    for (let [id, view] of views) {
    1.38 +      setIcon(id, window, view.icon);
    1.39 +      setLabel(id, window, view.label);
    1.40 +    }
    1.41 +
    1.42 +    customizedWindows.set(window, true);
    1.43 +  },
    1.44 +  onCustomizeEnd: window => {
    1.45 +    customizedWindows.delete(window);
    1.46 +
    1.47 +    for (let [id, ] of views) {
    1.48 +      let placement = CustomizableUI.getPlacementOfWidget(id);
    1.49 +
    1.50 +      if (placement)
    1.51 +        emit(viewEvents, 'data', { type: 'update', target: id, window: window });
    1.52 +    }
    1.53 +  },
    1.54 +  onWidgetAfterDOMChange: (node, nextNode, container) => {
    1.55 +    let { id } = node;
    1.56 +    let view = views.get(id);
    1.57 +    let window = node.ownerDocument.defaultView;
    1.58 +
    1.59 +    if (view) {
    1.60 +      emit(viewEvents, 'data', { type: 'update', target: id, window: window });
    1.61 +    }
    1.62 +  }
    1.63 +};
    1.64 +
    1.65 +CustomizableUI.addListener(buttonListener);
    1.66 +
    1.67 +require('../../system/unload').when( _ =>
    1.68 +  CustomizableUI.removeListener(buttonListener)
    1.69 +);
    1.70 +
    1.71 +function getNode(id, window) {
    1.72 +  return !views.has(id) || ignoreWindow(window)
    1.73 +    ? null
    1.74 +    : CustomizableUI.getWidget(id).forWindow(window).node
    1.75 +};
    1.76 +
    1.77 +function isInToolbar(id) {
    1.78 +  let placement = CustomizableUI.getPlacementOfWidget(id);
    1.79 +
    1.80 +  return placement && CustomizableUI.getAreaType(placement.area) === 'toolbar';
    1.81 +}
    1.82 +
    1.83 +
    1.84 +function getImage(icon, isInToolbar, pixelRatio) {
    1.85 +  let targetSize = (isInToolbar ? 18 : 32) * pixelRatio;
    1.86 +  let bestSize = 0;
    1.87 +  let image = icon;
    1.88 +
    1.89 +  if (isObject(icon)) {
    1.90 +    for (let size of Object.keys(icon)) {
    1.91 +      size = +size;
    1.92 +      let offset = targetSize - size;
    1.93 +
    1.94 +      if (offset === 0) {
    1.95 +        bestSize = size;
    1.96 +        break;
    1.97 +      }
    1.98 +
    1.99 +      let delta = Math.abs(offset) - Math.abs(targetSize - bestSize);
   1.100 +
   1.101 +      if (delta < 0)
   1.102 +        bestSize = size;
   1.103 +    }
   1.104 +
   1.105 +    image = icon[bestSize];
   1.106 +  }
   1.107 +
   1.108 +  if (image.indexOf('./') === 0)
   1.109 +    return data.url(image.substr(2));
   1.110 +
   1.111 +  return image;
   1.112 +}
   1.113 +
   1.114 +function nodeFor(id, window=getMostRecentBrowserWindow()) {
   1.115 +  return customizedWindows.has(window) ? null : getNode(id, window);
   1.116 +};
   1.117 +exports.nodeFor = nodeFor;
   1.118 +
   1.119 +function create(options) {
   1.120 +  let { id, label, icon, type } = options;
   1.121 +
   1.122 +  if (views.has(id))
   1.123 +    throw new Error('The ID "' + id + '" seems already used.');
   1.124 +
   1.125 +  CustomizableUI.createWidget({
   1.126 +    id: id,
   1.127 +    type: 'custom',
   1.128 +    removable: true,
   1.129 +    defaultArea: AREA_NAVBAR,
   1.130 +    allowedAreas: [ AREA_PANEL, AREA_NAVBAR ],
   1.131 +
   1.132 +    onBuild: function(document) {
   1.133 +      let window = document.defaultView;
   1.134 +
   1.135 +      let node = document.createElementNS(XUL_NS, 'toolbarbutton');
   1.136 +
   1.137 +      let image = getImage(icon, true, window.devicePixelRatio);
   1.138 +
   1.139 +      if (ignoreWindow(window))
   1.140 +        node.style.display = 'none';
   1.141 +
   1.142 +      node.setAttribute('id', this.id);
   1.143 +      node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional');
   1.144 +      node.setAttribute('type', type);
   1.145 +      node.setAttribute('label', label);
   1.146 +      node.setAttribute('tooltiptext', label);
   1.147 +      node.setAttribute('image', image);
   1.148 +      node.setAttribute('sdk-button', 'true');
   1.149 +
   1.150 +      views.set(id, {
   1.151 +        area: this.currentArea,
   1.152 +        icon: icon,
   1.153 +        label: label
   1.154 +      });
   1.155 +
   1.156 +      node.addEventListener('command', function(event) {
   1.157 +        if (views.has(id)) {
   1.158 +          emit(viewEvents, 'data', {
   1.159 +            type: 'click',
   1.160 +            target: id,
   1.161 +            window: event.view,
   1.162 +            checked: node.checked
   1.163 +          });
   1.164 +        }
   1.165 +      });
   1.166 +
   1.167 +      return node;
   1.168 +    }
   1.169 +  });
   1.170 +};
   1.171 +exports.create = create;
   1.172 +
   1.173 +function dispose(id) {
   1.174 +  if (!views.has(id)) return;
   1.175 +
   1.176 +  views.delete(id);
   1.177 +  CustomizableUI.destroyWidget(id);
   1.178 +}
   1.179 +exports.dispose = dispose;
   1.180 +
   1.181 +function setIcon(id, window, icon) {
   1.182 +  let node = getNode(id, window);
   1.183 +
   1.184 +  if (node) {
   1.185 +    icon = customizedWindows.has(window) ? views.get(id).icon : icon;
   1.186 +    let image = getImage(icon, isInToolbar(id), window.devicePixelRatio);
   1.187 +
   1.188 +    node.setAttribute('image', image);
   1.189 +  }
   1.190 +}
   1.191 +exports.setIcon = setIcon;
   1.192 +
   1.193 +function setLabel(id, window, label) {
   1.194 +  let node = nodeFor(id, window);
   1.195 +
   1.196 +  if (node) {
   1.197 +    node.setAttribute('label', label);
   1.198 +    node.setAttribute('tooltiptext', label);
   1.199 +  }
   1.200 +}
   1.201 +exports.setLabel = setLabel;
   1.202 +
   1.203 +function setDisabled(id, window, disabled) {
   1.204 +  let node = nodeFor(id, window);
   1.205 +
   1.206 +  if (node)
   1.207 +    node.disabled = disabled;
   1.208 +}
   1.209 +exports.setDisabled = setDisabled;
   1.210 +
   1.211 +function setChecked(id, window, checked) {
   1.212 +  let node = nodeFor(id, window);
   1.213 +
   1.214 +  if (node)
   1.215 +    node.checked = checked;
   1.216 +}
   1.217 +exports.setChecked = setChecked;
   1.218 +
   1.219 +function click(id) {
   1.220 +  let node = nodeFor(id);
   1.221 +
   1.222 +  if (node)
   1.223 +    node.click();
   1.224 +}
   1.225 +exports.click = click;

mercurial