diff --git a/browser/components/customizableui/src/CustomizeMode.jsm b/browser/components/customizableui/src/CustomizeMode.jsm index c705eba6b4c..5f32571c4a7 100644 --- a/browser/components/customizableui/src/CustomizeMode.jsm +++ b/browser/components/customizableui/src/CustomizeMode.jsm @@ -777,6 +777,9 @@ CustomizeMode.prototype = { }, _setDragActive: function(aItem, aValue, aWidth, aAtEnd) { + if (!aItem) { + return; + } let node = aItem; let window = aItem.ownerDocument.defaultView; let direction = window.getComputedStyle(aItem, null).direction; diff --git a/browser/components/customizableui/test/Makefile.in b/browser/components/customizableui/test/Makefile.in index 7a6a814e03b..fe74e7d83c2 100644 --- a/browser/components/customizableui/test/Makefile.in +++ b/browser/components/customizableui/test/Makefile.in @@ -13,6 +13,7 @@ include $(DEPTH)/config/autoconf.mk MOCHITEST_BROWSER_FILES = \ browser_873501_handle_specials.js \ browser_877178_unregisterArea.js \ + browser_878452_drag_to_panel.js \ head.js \ $(NULL) diff --git a/browser/components/customizableui/test/browser_878452_drag_to_panel.js b/browser/components/customizableui/test/browser_878452_drag_to_panel.js new file mode 100644 index 00000000000..7150a2dc43c --- /dev/null +++ b/browser/components/customizableui/test/browser_878452_drag_to_panel.js @@ -0,0 +1,81 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Dragging an item from the palette to another button in the panel should work.", + setup: startCustomizing, + run: function() { + let btn = document.getElementById("developer-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + + let lastButtonIndex = placements.length - 1; + let lastButton = placements[lastButtonIndex]; + let placementsAfterInsert = placements.slice(0, lastButtonIndex).concat(["developer-button", lastButton]); + let lastButtonNode = document.getElementById(lastButton); + simulateItemDrag(btn, lastButtonNode); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + teardown: endCustomizing + }, + { + desc: "Dragging an item from the palette to the panel itself should also work.", + setup: startCustomizing, + run: function() { + let btn = document.getElementById("developer-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + + let placementsAfterAppend = placements.concat(["developer-button"]); + simulateItemDrag(btn, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + teardown: endCustomizing + }, + { + desc: "Dragging an item from the palette to an empty panel should also work.", + setup: function() { + let widgetIds = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + while (widgetIds.length) { + CustomizableUI.removeWidgetFromArea(widgetIds.shift()); + } + return startCustomizing() + }, + run: function() { + let btn = document.getElementById("developer-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + + assertAreaPlacements(panel.id, []); + + let placementsAfterAppend = ["developer-button"]; + simulateItemDrag(btn, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + assertAreaPlacements(panel.id, []); + }, + teardown: endCustomizing + } +]; + +function cleanup() { + resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + registerCleanupFunction(cleanup); + runTests(gTests); +} + diff --git a/browser/components/customizableui/test/head.js b/browser/components/customizableui/test/head.js index e55e558e237..4047c2f2b1e 100644 --- a/browser/components/customizableui/test/head.js +++ b/browser/components/customizableui/test/head.js @@ -5,9 +5,16 @@ // Avoid leaks by using tmp for imports... let tmp = {}; +Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", tmp); Cu.import("resource://gre/modules/Task.jsm", tmp); Cu.import("resource:///modules/CustomizableUI.jsm", tmp); -let {Task, CustomizableUI} = tmp; +let {Promise, Task, CustomizableUI} = tmp; + +let ChromeUtils = {}; +let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader); +scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", ChromeUtils); + +let {synthesizeDragStart, synthesizeDrop} = ChromeUtils; const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; @@ -41,12 +48,15 @@ function removeCustomToolbars() { function resetCustomization() { CustomizableUI.reset(); + if (document.documentElement.hasAttribute("customizing")) { + window.gCustomizeMode.exit(); + } } function assertAreaPlacements(areaId, expectedPlacements) { let actualPlacements = getAreaWidgetIds(areaId); is(actualPlacements.length, expectedPlacements.length, - "Area " + areaId + " should have the right number of items."); + "Area " + areaId + " should have " + expectedPlacements.length + " items."); let minItems = Math.min(expectedPlacements.length, actualPlacements.length); for (let i = 0; i < minItems; i++) { if (typeof expectedPlacements[i] == "string") { @@ -68,6 +78,35 @@ function getAreaWidgetIds(areaId) { return widgetAry.map(x => x.id); } +function simulateItemDrag(toDrag, target) { + let docId = toDrag.ownerDocument.documentElement.id; + let dragData = [[{type: 'text/toolbarwrapper-id/' + docId, + data: {id: toDrag.id, width: toDrag.getBoundingClientRect().width + 'px'}}]]; + synthesizeDragStart(toDrag.parentNode, dragData); + synthesizeDrop(target, target, dragData); +} + +function endCustomizing() { + let deferred = Promise.defer(); + function onCustomizationEnds(ev) { + window.gNavToolbox.removeEventListener("aftercustomization", onCustomizationEnds); + deferred.resolve(ev); + } + window.gNavToolbox.addEventListener("aftercustomization", onCustomizationEnds); + window.gCustomizeMode.exit(); + return deferred.promise; +} +function startCustomizing() { + let deferred = Promise.defer(); + function onCustomizing() { + window.gNavToolbox.removeEventListener("customizationready", onCustomizing); + deferred.resolve(); + } + window.gNavToolbox.addEventListener("customizationready", onCustomizing); + window.gCustomizeMode.enter(); + return deferred.promise; +} + function testRunner(testAry) { for (let test of testAry) { info(test.desc);