Bug 989609 - Dynamically added toolbars with API-created widgets should not break customize mode. r=Unfocused,mdeboer, a=sledru.
authorMike Conley <mconley@mozilla.com>
Wed, 02 Apr 2014 16:39:00 -0400
changeset 192765 4732df03b90f8336a9be1038aced6b7d83f1a49a
parent 192764 78867264da1d6f97ce410c9535216a6847bb8a03
child 192766 2200d43e54857f441dbeb45c208ac0a877435612
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersUnfocused, mdeboer, sledru
bugs989609
milestone30.0a2
Bug 989609 - Dynamically added toolbars with API-created widgets should not break customize mode. r=Unfocused,mdeboer, a=sledru.
browser/components/customizableui/src/CustomizableUI.jsm
browser/components/customizableui/test/browser.ini
browser/components/customizableui/test/browser_989609_bootstrapped_custom_toolbar.js
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -1589,33 +1589,34 @@ let CustomizableUIInternal = {
     if (typeof aPosition != "number") {
       aPosition = placements.length;
     } else if (aPosition < 0) {
       aPosition = 0;
     } else if (aPosition > placements.length) {
       aPosition = placements.length;
     }
 
+    let widget = gPalette.get(aWidgetId);
+    if (widget) {
+      widget.currentPosition = aPosition;
+      widget.currentArea = oldPlacement.area;
+    }
+
     if (aPosition == oldPlacement.position) {
       return;
     }
 
     placements.splice(oldPlacement.position, 1);
     // If we just removed the item from *before* where it is now added,
     // we need to compensate the position offset for that:
     if (oldPlacement.position < aPosition) {
       aPosition--;
     }
     placements.splice(aPosition, 0, aWidgetId);
 
-    let widget = gPalette.get(aWidgetId);
-    if (widget) {
-      widget.currentPosition = aPosition;
-    }
-
     gDirty = true;
     gDirtyAreaCache.add(oldPlacement.area);
 
     this.saveState();
 
     this.notifyListeners("onWidgetMoved", aWidgetId, oldPlacement.area,
                          oldPlacement.position, aPosition);
   },
@@ -1651,29 +1652,35 @@ let CustomizableUIInternal = {
     }
 
     gSeenWidgets = new Set(gSavedState.seen || []);
     gDirtyAreaCache = new Set(gSavedState.dirtyAreaCache || []);
     gNewElementCount = gSavedState.newElementCount || 0;
   },
 
   restoreStateForArea: function(aArea, aLegacyState) {
-    if (gPlacements.has(aArea)) {
-      // Already restored.
-      return;
-    }
+    let placementsPreexisted = gPlacements.has(aArea);
 
     this.beginBatchUpdate();
     try {
       gRestoring = true;
 
       let restored = false;
-      gPlacements.set(aArea, []);
-
-      if (gSavedState && aArea in gSavedState.placements) {
+      if (placementsPreexisted) {
+        LOG("Restoring " + aArea + " from pre-existing placements");
+        for (let [position, id] in Iterator(gPlacements.get(aArea))) {
+          this.moveWidgetWithinArea(id, position);
+        }
+        gDirty = false;
+        restored = true;
+      } else {
+        gPlacements.set(aArea, []);
+      }
+
+      if (!restored && gSavedState && aArea in gSavedState.placements) {
         LOG("Restoring " + aArea + " from saved state");
         let placements = gSavedState.placements[aArea];
         for (let id of placements)
           this.addWidgetToArea(id, aArea);
         gDirty = false;
         restored = true;
       }
 
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -83,14 +83,15 @@ skip-if = os == "linux"
 [browser_980155_add_overflow_toolbar.js]
 [browser_981418-widget-onbeforecreated-handler.js]
 
 [browser_984455_bookmarks_items_reparenting.js]
 skip-if = os == "linux"
 
 [browser_985815_propagate_setToolbarVisibility.js]
 [browser_981305_separator_insertion.js]
+[browser_989609_bootstrapped_custom_toolbar.js]
 [browser_987177_destroyWidget_xul.js]
 [browser_987177_xul_wrapper_updating.js]
 [browser_989289_force_icons_mode_attribute.js]
 skip-if = os == "linux" && debug
 [browser_987492_window_api.js]
 [browser_panel_toggle.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_989609_bootstrapped_custom_toolbar.js
@@ -0,0 +1,75 @@
+/* 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";
+
+const kTestBarID = "testBar";
+const kWidgetID = "characterencoding-button";
+
+function createTestBar() {
+  let testBar = document.createElement("toolbar");
+  testBar.id = kTestBarID;
+  testBar.setAttribute("customizable", "true");
+  CustomizableUI.registerArea(kTestBarID,
+    { type: CustomizableUI.TYPE_TOOLBAR, legacy: false }
+  );
+  gNavToolbox.appendChild(testBar);
+  return testBar;
+}
+
+/**
+ * Helper function that does the following:
+ *
+ * 1) Creates a custom toolbar and registers it
+ *    with CustomizableUI.
+ * 2) Adds the widget with ID aWidgetID to that new
+ *    toolbar.
+ * 3) Enters customize mode and makes sure that the
+ *    widget is still in the right toolbar.
+ * 4) Exits customize mode, then removes and deregisters
+ *    the custom toolbar.
+ * 5) Checks that the widget has no placement.
+ * 6) Re-adds and re-registers a custom toolbar with the same
+ *    ID as the first one.
+ * 7) Enters customize mode and checks that the widget is
+ *    properly back in the toolbar.
+ * 8) Exits customize mode, removes and de-registers the
+ *    toolbar, and resets the toolbars to default.
+ */
+function checkRestoredPresence(aWidgetID) {
+  return Task.spawn(function* () {
+    let testBar = createTestBar();
+    CustomizableUI.addWidgetToArea(aWidgetID, kTestBarID);
+    let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
+    is(placement.area, kTestBarID,
+       "Expected " + aWidgetID + " to be in the test toolbar");
+
+    CustomizableUI.unregisterArea(testBar.id);
+    testBar.remove();
+
+    let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
+    is(placement, null, "Expected " + aWidgetID + " to be in the palette");
+
+    testBar = createTestBar();
+
+    yield startCustomizing();
+    let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
+    is(placement.area, kTestBarID,
+       "Expected " + aWidgetID + " to be in the test toolbar");
+    yield endCustomizing();
+
+    CustomizableUI.unregisterArea(testBar.id);
+    testBar.remove();
+
+    yield resetCustomization();
+  });
+}
+
+add_task(function* () {
+  yield checkRestoredPresence("downloads-button")
+});
+
+add_task(function* () {
+  yield checkRestoredPresence("characterencoding-button")
+});
\ No newline at end of file