 Issue 5741004535627776:
  Fix toolbar icon customization in Australis  (Closed)
    
  
    Issue 5741004535627776:
  Fix toolbar icon customization in Australis  (Closed) 
  | Left: | ||
| Right: | 
| OLD | NEW | 
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * This file is part of Adblock Plus <http://adblockplus.org/>, | |
| 3 * Copyright (C) 2006-2013 Eyeo GmbH | |
| 4 * | |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | |
| 6 * it under the terms of the GNU General Public License version 3 as | |
| 7 * published by the Free Software Foundation. | |
| 8 * | |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 * GNU General Public License for more details. | |
| 13 * | |
| 14 * You should have received a copy of the GNU General Public License | |
| 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | |
| 16 */ | |
| 17 | |
| 18 /** | |
| 19 * @fileOverview This emulates a subset of the CustomizableUI API from Firefox 2 8. | |
| 20 */ | |
| 21 | |
| 22 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", null); | |
| 23 | |
| 24 let {Utils} = require("utils"); | |
| 25 | |
| 26 // UI module has to be referenced lazily to avoid circular references | |
| 27 XPCOMUtils.defineLazyGetter(this, "UI", function() require("ui").UI); | |
| 28 | |
| 29 let widgets = Map(); | |
| 30 | |
| 31 function getToolbox(/**Window*/ window, /**Widget*/ widget) /**Element*/ | |
| 32 { | |
| 33 if (!("defaultArea" in widget) || !widget.defaultArea) | |
| 34 return null; | |
| 35 | |
| 36 let toolbar = UI.findElement(window, widget.defaultArea); | |
| 37 if (!toolbar) | |
| 38 return null; | |
| 39 | |
| 40 let toolbox = toolbar.toolbox; | |
| 41 if (toolbox && ("palette" in toolbox) && toolbox.palette) | |
| 42 return toolbox; | |
| 43 else | |
| 44 return null; | |
| 45 } | |
| 46 | |
| 47 function getToolbar(/**Element*/ element) /**Element*/ | |
| 48 { | |
| 49 for (let parent = element.parentNode; parent; parent = parent.parentNode) | |
| 50 if (parent.localName == "toolbar") | |
| 51 return parent; | |
| 52 return null; | |
| 53 } | |
| 54 | |
| 55 function getPaletteItem(/**Element*/ toolbox, /**String*/ id) /**Element*/ | |
| 56 { | |
| 57 for (let child of toolbox.palette.children) | |
| 58 if (child.id == id) | |
| 59 return child; | |
| 60 | |
| 61 return null; | |
| 62 } | |
| 63 | |
| 64 function restoreWidget(/**Element*/ toolbox, /**Widget*/ widget) | |
| 65 { | |
| 66 // Create node | |
| 67 let node = widget.onBuild(toolbox.ownerDocument); | |
| 68 if (typeof widget.onClick == "function") | |
| 69 node.addEventListener("click", widget.onClick, false); | |
| 70 if (typeof widget.onCommand == "function") | |
| 71 node.addEventListener("command", widget.onCommand, false); | |
| 72 | |
| 73 // Insert into the palette first | |
| 74 toolbox.palette.insertBefore(node, toolbox.palette.firstChild); | |
| 75 | |
| 76 // Now find out where we should put it | |
| 77 let position = toolbox.getAttribute(widget.positionAttribute); | |
| 78 if (!/^\S*,\S*,\S*$/.test(position)) | |
| 79 position = null; | |
| 80 | |
| 81 if (position == null) | |
| 82 { | |
| 83 // No explicitly saved position but maybe we can find it in a currentset | |
| 84 // attribute somewhere. | |
| 85 let toolbars = toolbox.externalToolbars.slice(); | |
| 86 for (let child of toolbox.children) | |
| 87 if (child.localName == "toolbar") | |
| 88 toolbars.push(child); | |
| 89 for (let toolbar of toolbars) | |
| 90 { | |
| 91 let currentSet = toolbar.getAttribute("currentset"); | |
| 92 if (currentSet) | |
| 93 { | |
| 94 let items = currentSet.split(","); | |
| 95 let index = items.indexOf(widget.id); | |
| 96 if (index >= 0) | |
| 97 { | |
| 98 let before = (index + 1 < items.length ? items[index + 1] : ""); | |
| 99 position = "visible," + toolbar.id + "," + before; | |
| 100 toolbox.setAttribute(widget.positionAttribute, position); | |
| 101 toolbox.ownerDocument.persist(toolbox.id, widget.positionAttribute); | |
| 102 break; | |
| 103 } | |
| 104 } | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 showWidget(toolbox, widget, position); | |
| 109 } | |
| 110 | |
| 111 function showWidget(/**Element*/ toolbox, /**Widget*/ widget, /**String*/ positi on) | |
| 112 { | |
| 113 let visible = "visible", parent = null, before = null; | |
| 114 if (position) | |
| 115 { | |
| 116 [visible, parent, before] = position.split(",", 3); | |
| 117 parent = toolbox.ownerDocument.getElementById(parent); | |
| 118 if (before == "") | |
| 119 before = null; | |
| 120 else | |
| 121 before = toolbox.ownerDocument.getElementById(before); | |
| 122 if (before && before.parentNode != parent) | |
| 123 before = null; | |
| 124 } | |
| 125 | |
| 126 if (visible == "visible" && !parent) | |
| 127 { | |
| 128 let insertionPoint = { | |
| 129 parent: widget.defaultArea | |
| 130 }; | |
| 131 if (typeof widget.defaultBefore != "undefined") | |
| 132 insertionPoint.before = widget.defaultBefore; | |
| 133 if (typeof widget.defaultAfter != "undefined") | |
| 134 insertionPoint.after = widget.defaultAfter; | |
| 135 | |
| 136 [parent, before] = UI.resolveInsertionPoint(toolbox.ownerDocument.defaultVie w, insertionPoint); | |
| 137 } | |
| 138 | |
| 139 if (parent && parent.localName != "toolbar") | |
| 140 parent = null; | |
| 141 | |
| 142 if (visible != "visible") | |
| 143 { | |
| 144 // Move to palette if the item is currently visible | |
| 145 let node = toolbox.ownerDocument.getElementById(widget.id); | |
| 146 if (node) | |
| 147 toolbox.palette.appendChild(node); | |
| 148 } | |
| 149 else if (parent) | |
| 150 { | |
| 151 // Add the item to the toolbar | |
| 152 let items = parent.currentSet.split(","); | |
| 153 let index = (before ? items.indexOf(before.id) : -1); | |
| 154 if (index < 0) | |
| 155 before = null; | |
| 156 parent.insertItem(widget.id, before, null, false); | |
| 157 } | |
| 158 | |
| 159 saveState(toolbox, widget); | |
| 160 } | |
| 161 | |
| 162 function removeWidget(/**Window*/ window, /**Widget*/ widget) | |
| 163 { | |
| 164 let element = window.document.getElementById(widget.id); | |
| 165 if (element) | |
| 166 element.parentNode.removeChild(element); | |
| 167 | |
| 168 let toolbox = getToolbox(window, widget); | |
| 169 if (toolbox) | |
| 170 { | |
| 171 let paletteItem = getPaletteItem(toolbox, widget.id); | |
| 172 if (paletteItem) | |
| 173 paletteItem.parentNode.removeChild(paletteItem); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 function onToolbarCustomization(/**Event*/ event) | |
| 178 { | |
| 179 let toolbox = event.currentTarget; | |
| 180 for (let [id, widget] of widgets) | |
| 181 saveState(toolbox, widget); | |
| 182 } | |
| 183 | |
| 184 function saveState(/**Element*/ toolbox, /**Widget*/ widget) | |
| 185 { | |
| 186 let node = toolbox.ownerDocument.getElementById(widget.id); | |
| 187 | |
| 188 let position = toolbox.getAttribute(widget.positionAttribute) || "hidden,,"; | |
| 189 if (node) | |
| 190 { | |
| 191 if (typeof widget.onAdded == "function") | |
| 192 widget.onAdded(node) | |
| 193 | |
| 194 let toolbar = getToolbar(node); | |
| 195 position = "visible," + toolbar.id + "," + (node.nextSibling ? node.nextSibl ing.id : ""); | |
| 196 } | |
| 197 else | |
| 198 position = position.replace(/^visible,/, "hidden,") | |
| 199 | |
| 200 toolbox.setAttribute(widget.positionAttribute, position); | |
| 201 toolbox.ownerDocument.persist(toolbox.id, widget.positionAttribute); | |
| 202 } | |
| 203 | |
| 204 let CustomizableUI = exports.CustomizableUI = | |
| 205 { | |
| 206 createWidget: function(widget) | |
| 207 { | |
| 208 if (typeof widget.id == "undefined" || | |
| 209 typeof widget.defaultArea == "undefined" || | |
| 210 typeof widget.positionAttribute == "undefined") | |
| 211 { | |
| 212 throw new Error("Unexpected: required property missing from the widget dat a"); | |
| 213 } | |
| 214 widgets.set(widget.id, widget); | |
| 215 | |
| 216 // Show widget in any existing windows | |
| 217 for (let window of UI.applicationWindows) | |
| 218 { | |
| 219 let toolbox = getToolbox(window, widget); | |
| 220 if (toolbox) | |
| 221 { | |
| 222 toolbox.addEventListener("aftercustomization", onToolbarCustomization, f alse); | |
| 223 restoreWidget(toolbox, widget); | |
| 224 } | |
| 225 } | |
| 226 }, | |
| 227 | |
| 228 destroyWidget: function(id) | |
| 229 { | |
| 230 // Don't do anything here. This function is called on shutdown, | |
| 231 // removeFromWindow will take care of cleaning up already. | |
| 232 }, | |
| 233 | |
| 234 getPlacementOfWidget: function(id) | |
| 235 { | |
| 236 let window = UI.currentWindow; | |
| 237 if (!window) | |
| 238 return null; | |
| 239 | |
| 240 let widget = window.document.getElementById(id); | |
| 241 if (!widget) | |
| 242 return null; | |
| 243 | |
| 244 let toolbar = getToolbar(widget); | |
| 245 if (!toolbar) | |
| 246 return null; | |
| 247 | |
| 248 let items = toolbar.currentSet.split(","); | |
| 249 let index = items.indexOf(id); | |
| 250 if (index < 0) | |
| 251 return null; | |
| 252 else | |
| 253 return {area: toolbar.id, placement: index}; | |
| 
Wladimir Palant
2013/11/27 16:04:01
Given that we don't use the placement parameter in
 | |
| 254 }, | |
| 255 | |
| 256 addWidgetToArea: function(id, area, position) | |
| 257 { | |
| 258 let widget = widgets.get(id); | |
| 259 for (let window of UI.applicationWindows) | |
| 260 { | |
| 261 let toolbox = getToolbox(window, widget); | |
| 262 if (!toolbox) | |
| 263 continue; | |
| 264 | |
| 265 let position = toolbox.getAttribute(widget.positionAttribute); | |
| 
Wladimir Palant
2013/11/27 16:04:01
This masks a parameter. We should probably simply
 | |
| 266 if (position) | |
| 267 position = position.replace(/^hidden,/, "visible,"); | |
| 268 showWidget(toolbox, widget, position); | |
| 269 } | |
| 270 }, | |
| 271 | |
| 272 removeWidgetFromArea: function(id) | |
| 273 { | |
| 274 let widget = widgets.get(id); | |
| 275 for (let window of UI.applicationWindows) | |
| 276 { | |
| 277 let toolbox = getToolbox(window, widget); | |
| 278 if (!toolbox) | |
| 279 continue; | |
| 280 | |
| 281 let position = toolbox.getAttribute(widget.positionAttribute); | |
| 282 if (position) | |
| 283 position = position.replace(/^visible,/, "hidden,"); | |
| 284 else | |
| 285 position = "hidden,,"; | |
| 286 showWidget(toolbox, widget, position); | |
| 287 } | |
| 288 } | |
| 289 }; | |
| 290 | |
| 291 let {WindowObserver} = require("windowObserver"); | |
| 292 new WindowObserver({ | |
| 293 applyToWindow: function(window) | |
| 294 { | |
| 295 let {isKnownWindow} = require("appSupport"); | |
| 296 if (!isKnownWindow(window)) | |
| 297 return; | |
| 298 | |
| 299 for (let [id, widget] of widgets) | |
| 300 { | |
| 301 let toolbox = getToolbox(window, widget); | |
| 302 if (toolbox) | |
| 303 { | |
| 304 toolbox.addEventListener("aftercustomization", onToolbarCustomization, f alse); | |
| 305 | |
| 306 // Restore widget asynchronously to allow the stylesheet to load | |
| 307 Utils.runAsync(restoreWidget.bind(null, toolbox, widget)); | |
| 308 } | |
| 309 } | |
| 310 }, | |
| 311 | |
| 312 removeFromWindow: function(window) | |
| 313 { | |
| 314 let {isKnownWindow} = require("appSupport"); | |
| 315 if (!isKnownWindow(window)) | |
| 316 return; | |
| 317 | |
| 318 for (let [id, widget] of widgets) | |
| 319 { | |
| 320 let toolbox = getToolbox(window, widget); | |
| 321 if (toolbox) | |
| 322 toolbox.removeEventListener("aftercustomization", onToolbarCustomization , false); | |
| 323 | |
| 324 removeWidget(window, widget); | |
| 325 } | |
| 326 } | |
| 327 }); | |
| OLD | NEW |