forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			295 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 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 kXULWidgetId = "a-test-button"; // we'll create a button with this ID.
 | 
						|
const kAPIWidgetId = "save-page-button";
 | 
						|
const kPanel = CustomizableUI.AREA_FIXED_OVERFLOW_PANEL;
 | 
						|
const kToolbar = CustomizableUI.AREA_NAVBAR;
 | 
						|
const kVisiblePalette = "customization-palette";
 | 
						|
 | 
						|
function checkWrapper(id) {
 | 
						|
  is(
 | 
						|
    document.querySelectorAll("#wrapper-" + id).length,
 | 
						|
    1,
 | 
						|
    "There should be exactly 1 wrapper for " +
 | 
						|
      id +
 | 
						|
      " in the customizing window."
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
async function ensureVisible(node) {
 | 
						|
  let isInPalette = node.parentNode.parentNode == gNavToolbox.palette;
 | 
						|
  if (isInPalette) {
 | 
						|
    node.scrollIntoView();
 | 
						|
  }
 | 
						|
  let dwu = window.windowUtils;
 | 
						|
  await BrowserTestUtils.waitForCondition(() => {
 | 
						|
    let nodeBounds = dwu.getBoundsWithoutFlushing(node);
 | 
						|
    if (isInPalette) {
 | 
						|
      let paletteBounds = dwu.getBoundsWithoutFlushing(gNavToolbox.palette);
 | 
						|
      if (
 | 
						|
        !(
 | 
						|
          nodeBounds.top >= paletteBounds.top &&
 | 
						|
          nodeBounds.bottom <= paletteBounds.bottom
 | 
						|
        )
 | 
						|
      ) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return nodeBounds.height && nodeBounds.width;
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
var move = {
 | 
						|
  async drag(id, target) {
 | 
						|
    let targetNode = document.getElementById(target);
 | 
						|
    if (CustomizableUI.getCustomizationTarget(targetNode)) {
 | 
						|
      targetNode = CustomizableUI.getCustomizationTarget(targetNode);
 | 
						|
    }
 | 
						|
    let nodeToMove = document.getElementById(id);
 | 
						|
    await ensureVisible(nodeToMove);
 | 
						|
 | 
						|
    simulateItemDrag(nodeToMove, targetNode, "end");
 | 
						|
  },
 | 
						|
  async dragToItem(id, target) {
 | 
						|
    let targetNode = document.getElementById(target);
 | 
						|
    if (CustomizableUI.getCustomizationTarget(targetNode)) {
 | 
						|
      targetNode = CustomizableUI.getCustomizationTarget(targetNode);
 | 
						|
    }
 | 
						|
    let items = targetNode.querySelectorAll("toolbarpaletteitem");
 | 
						|
    if (target == kPanel) {
 | 
						|
      targetNode = items[items.length - 1];
 | 
						|
    } else {
 | 
						|
      targetNode = items[0];
 | 
						|
    }
 | 
						|
    let nodeToMove = document.getElementById(id);
 | 
						|
    await ensureVisible(nodeToMove);
 | 
						|
    simulateItemDrag(nodeToMove, targetNode, "start");
 | 
						|
  },
 | 
						|
  API(id, target) {
 | 
						|
    if (target == kVisiblePalette) {
 | 
						|
      return CustomizableUI.removeWidgetFromArea(id);
 | 
						|
    }
 | 
						|
    return CustomizableUI.addWidgetToArea(id, target, null);
 | 
						|
  },
 | 
						|
};
 | 
						|
 | 
						|
function isLast(containerId, defaultPlacements, id) {
 | 
						|
  assertAreaPlacements(containerId, defaultPlacements.concat([id]));
 | 
						|
  let thisTarget = CustomizableUI.getCustomizationTarget(
 | 
						|
    document.getElementById(containerId)
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    thisTarget.lastElementChild.firstElementChild.id,
 | 
						|
    id,
 | 
						|
    "Widget " + id + " should be in " + containerId + " in customizing window."
 | 
						|
  );
 | 
						|
  let otherTarget = CustomizableUI.getCustomizationTarget(
 | 
						|
    otherWin.document.getElementById(containerId)
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    otherTarget.lastElementChild.id,
 | 
						|
    id,
 | 
						|
    "Widget " + id + " should be in " + containerId + " in other window."
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
function getLastVisibleNodeInToolbar(containerId, win = window) {
 | 
						|
  let container = CustomizableUI.getCustomizationTarget(
 | 
						|
    win.document.getElementById(containerId)
 | 
						|
  );
 | 
						|
  let rv = container.lastElementChild;
 | 
						|
  while (rv?.hidden || rv?.firstElementChild?.hidden) {
 | 
						|
    rv = rv.previousElementSibling;
 | 
						|
  }
 | 
						|
  return rv;
 | 
						|
}
 | 
						|
 | 
						|
function isLastVisibleInToolbar(containerId, defaultPlacements, id) {
 | 
						|
  let newPlacements;
 | 
						|
  for (let i = defaultPlacements.length - 1; i >= 0; i--) {
 | 
						|
    let el = document.getElementById(defaultPlacements[i]);
 | 
						|
    if (el && !el.hidden) {
 | 
						|
      newPlacements = [...defaultPlacements];
 | 
						|
      newPlacements.splice(i + 1, 0, id);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (!newPlacements) {
 | 
						|
    assertAreaPlacements(containerId, defaultPlacements.concat([id]));
 | 
						|
  } else {
 | 
						|
    assertAreaPlacements(containerId, newPlacements);
 | 
						|
  }
 | 
						|
  is(
 | 
						|
    getLastVisibleNodeInToolbar(containerId).firstElementChild.id,
 | 
						|
    id,
 | 
						|
    "Widget " + id + " should be in " + containerId + " in customizing window."
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    getLastVisibleNodeInToolbar(containerId, otherWin).id,
 | 
						|
    id,
 | 
						|
    "Widget " + id + " should be in " + containerId + " in other window."
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
function isFirst(containerId, defaultPlacements, id) {
 | 
						|
  assertAreaPlacements(containerId, [id].concat(defaultPlacements));
 | 
						|
  let thisTarget = CustomizableUI.getCustomizationTarget(
 | 
						|
    document.getElementById(containerId)
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    thisTarget.firstElementChild.firstElementChild.id,
 | 
						|
    id,
 | 
						|
    "Widget " + id + " should be in " + containerId + " in customizing window."
 | 
						|
  );
 | 
						|
  let otherTarget = CustomizableUI.getCustomizationTarget(
 | 
						|
    otherWin.document.getElementById(containerId)
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    otherTarget.firstElementChild.id,
 | 
						|
    id,
 | 
						|
    "Widget " + id + " should be in " + containerId + " in other window."
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
async function checkToolbar(id, method) {
 | 
						|
  // Place at start of the toolbar:
 | 
						|
  let toolbarPlacements = getAreaWidgetIds(kToolbar);
 | 
						|
  await move[method](id, kToolbar);
 | 
						|
  if (method == "dragToItem") {
 | 
						|
    isFirst(kToolbar, toolbarPlacements, id);
 | 
						|
  } else if (method == "drag") {
 | 
						|
    isLastVisibleInToolbar(kToolbar, toolbarPlacements, id);
 | 
						|
  } else {
 | 
						|
    isLast(kToolbar, toolbarPlacements, id);
 | 
						|
  }
 | 
						|
  checkWrapper(id);
 | 
						|
}
 | 
						|
 | 
						|
async function checkPanel(id, method) {
 | 
						|
  let panelPlacements = getAreaWidgetIds(kPanel);
 | 
						|
  await move[method](id, kPanel);
 | 
						|
  let children = document
 | 
						|
    .getElementById(kPanel)
 | 
						|
    .querySelectorAll("toolbarpaletteitem");
 | 
						|
  let otherChildren = otherWin.document.getElementById(kPanel).children;
 | 
						|
  let newPlacements = panelPlacements.concat([id]);
 | 
						|
  // Relative position of the new item from the end:
 | 
						|
  let position = -1;
 | 
						|
  // For the drag to item case, we drag to the last item, making the dragged item the
 | 
						|
  // penultimate item. We can't well use the first item because the panel has complicated
 | 
						|
  // rules about rearranging wide items (which, by default, the first two items are).
 | 
						|
  if (method == "dragToItem") {
 | 
						|
    newPlacements.pop();
 | 
						|
    newPlacements.splice(panelPlacements.length - 1, 0, id);
 | 
						|
    position = -2;
 | 
						|
  }
 | 
						|
  assertAreaPlacements(kPanel, newPlacements);
 | 
						|
  is(
 | 
						|
    children[children.length + position].firstElementChild.id,
 | 
						|
    id,
 | 
						|
    "Widget " + id + " should be in " + kPanel + " in customizing window."
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    otherChildren[otherChildren.length + position].id,
 | 
						|
    id,
 | 
						|
    "Widget " + id + " should be in " + kPanel + " in other window."
 | 
						|
  );
 | 
						|
  checkWrapper(id);
 | 
						|
}
 | 
						|
 | 
						|
async function checkPalette(id, method) {
 | 
						|
  // Move back to palette:
 | 
						|
  await move[method](id, kVisiblePalette);
 | 
						|
  ok(CustomizableUI.inDefaultState, "Should end in default state");
 | 
						|
  let visibleChildren = gCustomizeMode.visiblePalette.children;
 | 
						|
  let expectedChild =
 | 
						|
    method == "dragToItem"
 | 
						|
      ? visibleChildren[0]
 | 
						|
      : visibleChildren[visibleChildren.length - 1];
 | 
						|
  // Items dragged to the end of the palette should be the final item. That they're the penultimate
 | 
						|
  // item when dragged is tracked in bug 1395950. Once that's fixed, this hack can be removed.
 | 
						|
  if (method == "drag") {
 | 
						|
    expectedChild = expectedChild.previousElementSibling;
 | 
						|
  }
 | 
						|
  is(
 | 
						|
    expectedChild.firstElementChild.id,
 | 
						|
    id,
 | 
						|
    "Widget " +
 | 
						|
      id +
 | 
						|
      " was moved using " +
 | 
						|
      method +
 | 
						|
      " and should now be wrapped in palette in customizing window."
 | 
						|
  );
 | 
						|
  if (id == kXULWidgetId) {
 | 
						|
    ok(
 | 
						|
      otherWin.gNavToolbox.palette.querySelector("#" + id),
 | 
						|
      "Widget " + id + " should be in invisible palette in other window."
 | 
						|
    );
 | 
						|
  }
 | 
						|
  checkWrapper(id);
 | 
						|
}
 | 
						|
 | 
						|
// This test needs a XUL button that's in the palette by default. No such
 | 
						|
// button currently exists, so we create a simple one.
 | 
						|
function createXULButtonForWindow(win) {
 | 
						|
  createDummyXULButton(kXULWidgetId, "test-button", win);
 | 
						|
}
 | 
						|
 | 
						|
function removeXULButtonForWindow(win) {
 | 
						|
  win.gNavToolbox.palette.querySelector(`#${kXULWidgetId}`).remove();
 | 
						|
}
 | 
						|
 | 
						|
var otherWin;
 | 
						|
 | 
						|
// Moving widgets in two windows, one with customize mode and one without, should work.
 | 
						|
add_task(async function MoveWidgetsInTwoWindows() {
 | 
						|
  CustomizableUI.createWidget({
 | 
						|
    id: "cui-mode-wrapping-some-panel-item",
 | 
						|
    label: "Test panel wrapping",
 | 
						|
  });
 | 
						|
  await startCustomizing();
 | 
						|
  otherWin = await openAndLoadWindow(null, true);
 | 
						|
  await otherWin.PanelUI.ensureReady();
 | 
						|
  // Create the XUL button to use in the test in both windows.
 | 
						|
  createXULButtonForWindow(window);
 | 
						|
  createXULButtonForWindow(otherWin);
 | 
						|
  ok(CustomizableUI.inDefaultState, "Should start in default state");
 | 
						|
 | 
						|
  for (let widgetId of [kXULWidgetId, kAPIWidgetId]) {
 | 
						|
    for (let method of ["API", "drag", "dragToItem"]) {
 | 
						|
      info("Moving widget " + widgetId + " using " + method);
 | 
						|
      await checkToolbar(widgetId, method);
 | 
						|
      // We add an item to the panel because otherwise we can't test dragging
 | 
						|
      // to items that are already there. We remove it because
 | 
						|
      // 'checkPalette' checks that we leave the browser in the default state.
 | 
						|
      CustomizableUI.addWidgetToArea(
 | 
						|
        "cui-mode-wrapping-some-panel-item",
 | 
						|
        CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
 | 
						|
      );
 | 
						|
      await checkPanel(widgetId, method);
 | 
						|
      CustomizableUI.removeWidgetFromArea("cui-mode-wrapping-some-panel-item");
 | 
						|
      await checkPalette(widgetId, method);
 | 
						|
      CustomizableUI.addWidgetToArea(
 | 
						|
        "cui-mode-wrapping-some-panel-item",
 | 
						|
        CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
 | 
						|
      );
 | 
						|
      await checkPanel(widgetId, method);
 | 
						|
      await checkToolbar(widgetId, method);
 | 
						|
      CustomizableUI.removeWidgetFromArea("cui-mode-wrapping-some-panel-item");
 | 
						|
      await checkPalette(widgetId, method);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  await promiseWindowClosed(otherWin);
 | 
						|
  otherWin = null;
 | 
						|
  await endCustomizing();
 | 
						|
  removeXULButtonForWindow(window);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function asyncCleanup() {
 | 
						|
  CustomizableUI.destroyWidget("cui-mode-wrapping-some-panel-item");
 | 
						|
  await resetCustomization();
 | 
						|
});
 |