Attachment #800975: Patch v2.2 for bug #902100

View | Details | Raw Unified | Return to bug 902100
Collapse All | Expand All

(-)a/browser/components/customizableui/src/CustomizableUI.jsm (-37 / +33 lines)
Line     Link Here 
 Lines 103-131   let gInBatchStack = 0; Link Here 
103
let gResetting = false;
103
let gResetting = false;
104
104
105
/**
105
/**
106
 * gBuildAreas maps area IDs to actual area nodes within browser windows.
106
 * gBuildAreas maps area IDs to actual area nodes within browser windows.
107
 */
107
 */
108
let gBuildAreas = new Map();
108
let gBuildAreas = new Map();
109
109
110
/**
110
/**
111
 * gBuildWindows is a map of windows that have registered build areas, mapped
111
 * gBuildWindows is a set of windows that have registered build areas.
112
 * to a Set of known toolboxes in that window.
113
 */
112
 */
114
let gBuildWindows = new Map();
113
let gBuildWindows = new Set();
115
114
116
let gNewElementCount = 0;
115
let gNewElementCount = 0;
117
let gGroupWrapperCache = new Map();
116
let gGroupWrapperCache = new Map();
118
let gSingleWrapperCache = new WeakMap();
117
let gSingleWrapperCache = new WeakMap();
119
let gListeners = new Set();
118
let gListeners = new Set();
120
119
121
let gModuleName = "[CustomizableUI]";
120
let gModuleName = "[CustomizableUI]";
122
#include logging.js
121
#include logging.js
123
122
123
let CustomizeHelper = {
124
  getToolboxForWindow: function(aWindow) {
125
    return aWindow.gNavToolbox;
126
  },
127
};
128
124
let CustomizableUIInternal = {
129
let CustomizableUIInternal = {
125
  initialize: function() {
130
  initialize: function() {
126
    LOG("Initializing");
131
    LOG("Initializing");
127
132
128
    this.addListener(this);
133
    this.addListener(this);
129
    this._defineBuiltInWidgets();
134
    this._defineBuiltInWidgets();
130
    this.loadSavedState();
135
    this.loadSavedState();
131
136
 Lines 383-399   let CustomizableUIInternal = { Link Here 
383
388
384
      this.insertWidgetBefore(node, currentNode, container, aArea);
389
      this.insertWidgetBefore(node, currentNode, container, aArea);
385
      this._addParentFlex(node);
390
      this._addParentFlex(node);
386
      if (gResetting)
391
      if (gResetting)
387
        this.notifyListeners("onWidgetReset", id);
392
        this.notifyListeners("onWidgetReset", id);
388
    }
393
    }
389
394
390
    if (currentNode) {
395
    if (currentNode) {
391
      let palette = aAreaNode.toolbox ? aAreaNode.toolbox.palette : null;
396
      let palette = CustomizeHelper.getToolboxForWindow(window).palette;
392
      let limit = currentNode.previousSibling;
397
      let limit = currentNode.previousSibling;
393
      let node = container.lastChild;
398
      let node = container.lastChild;
394
      while (node && node != limit) {
399
      while (node && node != limit) {
395
        let previousSibling = node.previousSibling;
400
        let previousSibling = node.previousSibling;
396
        // Nodes opt-in to removability. If they're removable, and we haven't
401
        // Nodes opt-in to removability. If they're removable, and we haven't
397
        // seen them in the placements array, then we toss them into the palette
402
        // seen them in the placements array, then we toss them into the palette
398
        // if one exists. If no palette exists, we just remove the node. If the
403
        // if one exists. If no palette exists, we just remove the node. If the
399
        // node is not removable, we leave it where it is. However, we can only
404
        // node is not removable, we leave it where it is. However, we can only
 Lines 520-536   let CustomizableUIInternal = { Link Here 
520
    for (let btn of aPanel.querySelectorAll("toolbarbutton")) {
525
    for (let btn of aPanel.querySelectorAll("toolbarbutton")) {
521
      btn.setAttribute("tabindex", "0");
526
      btn.setAttribute("tabindex", "0");
522
      this.ensureButtonContextMenu(btn, true);
527
      this.ensureButtonContextMenu(btn, true);
523
      if (!btn.hasAttribute("type")) {
528
      if (!btn.hasAttribute("type")) {
524
        btn.setAttribute("type", "wrap");
529
        btn.setAttribute("type", "wrap");
525
      }
530
      }
526
    }
531
    }
527
532
528
    aPanel.toolbox = document.getElementById("navigator-toolbox");
529
    aPanel.customizationTarget = aPanel;
533
    aPanel.customizationTarget = aPanel;
530
534
531
    this.addPanelCloseListeners(aPanel);
535
    this.addPanelCloseListeners(aPanel);
532
536
533
    let placements = gPlacements.get(CustomizableUI.AREA_PANEL);
537
    let placements = gPlacements.get(CustomizableUI.AREA_PANEL);
534
    this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanel);
538
    this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanel);
535
    this.registerBuildArea(CustomizableUI.AREA_PANEL, aPanel);
539
    this.registerBuildArea(CustomizableUI.AREA_PANEL, aPanel);
536
  },
540
  },
 Lines 613-629   let CustomizableUIInternal = { Link Here 
613
      if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
617
      if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
614
        container.removeChild(widgetNode);
618
        container.removeChild(widgetNode);
615
      } else {
619
      } else {
616
        this.removeLocationAttributes(widgetNode);
620
        this.removeLocationAttributes(widgetNode);
617
        widgetNode.removeAttribute("tabindex");
621
        widgetNode.removeAttribute("tabindex");
618
        if (widgetNode.getAttribute("type") == "wrap") {
622
        if (widgetNode.getAttribute("type") == "wrap") {
619
          widgetNode.removeAttribute("type");
623
          widgetNode.removeAttribute("type");
620
        }
624
        }
621
        areaNode.toolbox.palette.appendChild(widgetNode);
625
        let palette = CustomizeHelper.getToolboxForWindow(window).palette;
626
        palette.appendChild(widgetNode);
622
      }
627
      }
623
      if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) {
628
      if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) {
624
        areaNode.setAttribute("currentset", areaNode.currentSet);
629
        areaNode.setAttribute("currentset", areaNode.currentSet);
625
      }
630
      }
626
631
627
      let windowCache = gSingleWrapperCache.get(window);
632
      let windowCache = gSingleWrapperCache.get(window);
628
      if (windowCache) {
633
      if (windowCache) {
629
        windowCache.delete(aWidgetId);
634
        windowCache.delete(aWidgetId);
 Lines 675-706   let CustomizableUIInternal = { Link Here 
675
  },
680
  },
676
681
677
  registerBuildArea: function(aArea, aNode) {
682
  registerBuildArea: function(aArea, aNode) {
678
    // We ensure that the window is registered to have its customization data
683
    // We ensure that the window is registered to have its customization data
679
    // cleaned up when unloading.
684
    // cleaned up when unloading.
680
    let window = aNode.ownerDocument.defaultView;
685
    let window = aNode.ownerDocument.defaultView;
681
    this.registerBuildWindow(window);
686
    this.registerBuildWindow(window);
682
687
683
    // Also register this build area's toolbox.
684
    if (aNode.toolbox) {
685
      gBuildWindows.get(window).add(aNode.toolbox);
686
    }
687
688
    if (!gBuildAreas.has(aArea)) {
688
    if (!gBuildAreas.has(aArea)) {
689
      gBuildAreas.set(aArea, new Set());
689
      gBuildAreas.set(aArea, new Set());
690
    }
690
    }
691
691
692
    gBuildAreas.get(aArea).add(aNode);
692
    gBuildAreas.get(aArea).add(aNode);
693
  },
693
  },
694
694
695
  registerBuildWindow: function(aWindow) {
695
  registerBuildWindow: function(aWindow) {
696
    if (!gBuildWindows.has(aWindow)) {
696
    gBuildWindows.add(aWindow);
697
      gBuildWindows.set(aWindow, new Set());
698
    }
699
697
700
    aWindow.addEventListener("unload", this);
698
    aWindow.addEventListener("unload", this);
701
    aWindow.addEventListener("command", this, true);
699
    aWindow.addEventListener("command", this, true);
702
  },
700
  },
703
701
704
  unregisterBuildWindow: function(aWindow) {
702
  unregisterBuildWindow: function(aWindow) {
705
    aWindow.removeEventListener("unload", this);
703
    aWindow.removeEventListener("unload", this);
706
    aWindow.removeEventListener("command", this, true);
704
    aWindow.removeEventListener("command", this, true);
 Lines 830-877   let CustomizableUIInternal = { Link Here 
830
    let node = document.getElementById(aId);
828
    let node = document.getElementById(aId);
831
    if (node) {
829
    if (node) {
832
      let parent = node.parentNode;
830
      let parent = node.parentNode;
833
      while (parent && !(parent.customizationTarget ||
831
      while (parent && !(parent.customizationTarget ||
834
                         parent.localName == "toolbarpaletteitem")) {
832
                         parent.localName == "toolbarpaletteitem")) {
835
        parent = parent.parentNode;
833
        parent = parent.parentNode;
836
      }
834
      }
837
835
838
      if ((parent && parent.customizationTarget == node.parentNode &&
836
      if ((parent && parent.customizationTarget == node.parentNode) ||
839
           gBuildWindows.get(aWindow).has(parent.toolbox)) ||
840
          (parent && parent.localName == "toolbarpaletteitem")) {
837
          (parent && parent.localName == "toolbarpaletteitem")) {
841
        // Normalize the removable attribute. For backwards compat, if
838
        // Normalize the removable attribute. For backwards compat, if
842
        // the widget is not defined in a toolbox palette then absence
839
        // the widget is not defined in a toolbox palette then absence
843
        // of the "removable" attribute means it is not removable.
840
        // of the "removable" attribute means it is not removable.
844
        if (!node.hasAttribute("removable")) {
841
        if (!node.hasAttribute("removable")) {
845
          // If we first see this in customization mode, it may be in the
842
          // If we first see this in customization mode, it may be in the
846
          // customization palette instead of the toolbox palette.
843
          // customization palette instead of the toolbox palette.
847
          node.setAttribute("removable", !parent.customizationTarget);
844
          node.setAttribute("removable", !parent.customizationTarget);
848
        }
845
        }
849
846
850
        return node;
847
        return node;
851
      }
848
      }
852
    }
849
    }
853
850
854
    let toolboxes = gBuildWindows.get(aWindow);
851
    let palette = CustomizeHelper.getToolboxForWindow(aWindow).palette;
855
    for (let toolbox of toolboxes) {
852
    // Attempt to locate a node with a matching ID within
856
      if (toolbox.palette) {
853
    // the palette.
857
        // Attempt to locate a node with a matching ID within
854
    let node = palette.querySelector(idToSelector(aId));
858
        // the palette.
855
    if (node) {
859
        let node = toolbox.palette.querySelector(idToSelector(aId));
856
      // Normalize the removable attribute. For backwards compat, this
860
        if (node) {
857
      // is optional if the widget is defined in the toolbox palette,
861
          // Normalize the removable attribute. For backwards compat, this
858
      // and defaults to *true*, unlike if it was defined elsewhere.
862
          // is optional if the widget is defined in the toolbox palette,
859
      if (!node.hasAttribute("removable")) {
863
          // and defaults to *true*, unlike if it was defined elsewhere.
860
        node.setAttribute("removable", true);
864
          if (!node.hasAttribute("removable")) {
865
            node.setAttribute("removable", true);
866
          }
867
          return node;
868
        }
869
      }
861
      }
862
      return node;
870
    }
863
    }
871
    return null;
864
    return null;
872
  },
865
  },
873
866
874
  buildWidget: function(aDocument, aWidget) {
867
  buildWidget: function(aDocument, aWidget) {
875
    if (typeof aWidget == "string") {
868
    if (typeof aWidget == "string") {
876
      aWidget = gPalette.get(aWidget);
869
      aWidget = gPalette.get(aWidget);
877
    }
870
    }
 Lines 1801-1817   let CustomizableUIInternal = { Link Here 
1801
      if (gBuildWindows.size == 0) {
1794
      if (gBuildWindows.size == 0) {
1802
        // We don't have any build windows to look at, so just assume for now
1795
        // We don't have any build windows to look at, so just assume for now
1803
        // that its removable.
1796
        // that its removable.
1804
        return true;
1797
        return true;
1805
      }
1798
      }
1806
1799
1807
      if (!widgetNode) {
1800
      if (!widgetNode) {
1808
        // Pick any of the build windows to look at.
1801
        // Pick any of the build windows to look at.
1809
        let [window,] = [...gBuildWindows][0];
1802
        let window = [...gBuildWindows][0];
1810
        [, widgetNode] = this.getWidgetNode(widgetId, window);
1803
        [, widgetNode] = this.getWidgetNode(widgetId, window);
1811
      }
1804
      }
1812
      // If we don't have a node, we assume it's removable. This can happen because
1805
      // If we don't have a node, we assume it's removable. This can happen because
1813
      // getWidgetProvider returns PROVIDER_XUL by default, but this will also happen
1806
      // getWidgetProvider returns PROVIDER_XUL by default, but this will also happen
1814
      // for API-provided widgets which have been destroyed.
1807
      // for API-provided widgets which have been destroyed.
1815
      if (!widgetNode) {
1808
      if (!widgetNode) {
1816
        return true;
1809
        return true;
1817
      }
1810
      }
 Lines 2145-2161   function XULWidgetGroupWrapper(aWidgetId Link Here 
2145
    if (wrapperMap.has(aWidgetId)) {
2138
    if (wrapperMap.has(aWidgetId)) {
2146
      return wrapperMap.get(aWidgetId);
2139
      return wrapperMap.get(aWidgetId);
2147
    }
2140
    }
2148
2141
2149
    let instance = aWindow.document.getElementById(aWidgetId);
2142
    let instance = aWindow.document.getElementById(aWidgetId);
2150
    if (!instance) {
2143
    if (!instance) {
2151
      // Toolbar palettes aren't part of the document, so elements in there
2144
      // Toolbar palettes aren't part of the document, so elements in there
2152
      // won't be found via document.getElementById().
2145
      // won't be found via document.getElementById().
2153
      instance = aWindow.gNavToolbox.palette.querySelector(idToSelector(aWidgetId));
2146
      let palette = CustomizeHelper.getToolboxForWindow(aWindow).palette;
2147
      instance = palette.querySelector(idToSelector(aWidgetId));
2154
    }
2148
    }
2155
2149
2156
    let wrapper = new XULWidgetSingleWrapper(aWidgetId, instance);
2150
    let wrapper = new XULWidgetSingleWrapper(aWidgetId, instance);
2157
    wrapperMap.set(aWidgetId, wrapper);
2151
    wrapperMap.set(aWidgetId, wrapper);
2158
    return wrapper;
2152
    return wrapper;
2159
  };
2153
  };
2160
2154
2161
  this.__defineGetter__("areaType", function() {
2155
  this.__defineGetter__("areaType", function() {
 Lines 2222-2239   OverflowableToolbar.prototype = { Link Here 
2222
2216
2223
  init: function() {
2217
  init: function() {
2224
    this._target = this._toolbar.customizationTarget;
2218
    this._target = this._toolbar.customizationTarget;
2225
    let doc = this._toolbar.ownerDocument;
2219
    let doc = this._toolbar.ownerDocument;
2226
    this._list = doc.getElementById(this._toolbar.getAttribute("overflowtarget"));
2220
    this._list = doc.getElementById(this._toolbar.getAttribute("overflowtarget"));
2227
2221
2228
    let window = doc.defaultView;
2222
    let window = doc.defaultView;
2229
    window.addEventListener("resize", this);
2223
    window.addEventListener("resize", this);
2230
    window.gNavToolbox.addEventListener("customizationstarting", this);
2224
    let toolbox = CustomizeHelper.getToolboxForWindow(window);
2231
    window.gNavToolbox.addEventListener("aftercustomization", this);
2225
    toolbox.addEventListener("customizationstarting", this);
2226
    toolbox.addEventListener("aftercustomization", this);
2232
2227
2233
    let chevronId = this._toolbar.getAttribute("overflowbutton");
2228
    let chevronId = this._toolbar.getAttribute("overflowbutton");
2234
    this._chevron = doc.getElementById(chevronId);
2229
    this._chevron = doc.getElementById(chevronId);
2235
    this._chevron.addEventListener("command", this);
2230
    this._chevron.addEventListener("command", this);
2236
2231
2237
    this._panel = doc.getElementById("widget-overflow");
2232
    this._panel = doc.getElementById("widget-overflow");
2238
    this._panel.addEventListener("popuphiding", this);
2233
    this._panel.addEventListener("popuphiding", this);
2239
    CustomizableUIInternal.addPanelCloseListeners(this._panel);
2234
    CustomizableUIInternal.addPanelCloseListeners(this._panel);
 Lines 2254-2271   OverflowableToolbar.prototype = { Link Here 
2254
      Services.obs.removeObserver(this, "browser-delayed-startup-finished");
2249
      Services.obs.removeObserver(this, "browser-delayed-startup-finished");
2255
      return;
2250
      return;
2256
    }
2251
    }
2257
2252
2258
    this._disable();
2253
    this._disable();
2259
2254
2260
    let window = this._toolbar.ownerDocument.defaultView;
2255
    let window = this._toolbar.ownerDocument.defaultView;
2261
    window.removeEventListener("resize", this);
2256
    window.removeEventListener("resize", this);
2262
    window.gNavToolbox.removeEventListener("customizationstarting", this);
2257
    let toolbox = CustomizeHelper.getToolboxForWindow(window);
2263
    window.gNavToolbox.removeEventListener("aftercustomization", this);
2258
    toolbox.removeEventListener("customizationstarting", this);
2259
    toolbox.removeEventListener("aftercustomization", this);
2264
    this._chevron.removeEventListener("command", this);
2260
    this._chevron.removeEventListener("command", this);
2265
    this._panel.removeEventListener("popuphiding", this);
2261
    this._panel.removeEventListener("popuphiding", this);
2266
    CustomizableUIInternal.removePanelCloseListeners(this._panel);
2262
    CustomizableUIInternal.removePanelCloseListeners(this._panel);
2267
  },
2263
  },
2268
2264
2269
  handleEvent: function(aEvent) {
2265
  handleEvent: function(aEvent) {
2270
    switch(aEvent.type) {
2266
    switch(aEvent.type) {
2271
      case "overflow":
2267
      case "overflow":

Return to bug 902100