Bug 923859 - Wide widget rearranging: derecurse, simplify, improve, r=jaws

This commit is contained in:
Gijs Kruitbosch
2013-10-10 13:40:44 +02:00
parent cc1230a0e9
commit 7be4f1f0e3
2 changed files with 72 additions and 48 deletions

View File

@@ -26,26 +26,36 @@ let gSeenWidgets = new Set();
// The class by which we recognize wide widgets:
const kWidePanelItemClass = "panel-combined-item";
// TODO(bug 885574): Merge this constant with the one in CustomizeMode.jsm,
// maybe just use a pref for this.
const kColumnsInMenuPanel = 3;
let PanelWideWidgetTracker = {
// Listeners used to validate panel contents whenever they change:
onWidgetAdded: function(aWidgetId, aArea, aPosition) {
if (aArea == gPanel) {
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
let moveForward = this.shouldMoveForward(aWidgetId, aPosition);
this.adjustWidgets(aWidgetId, aPosition, moveForward);
this.adjustWidgets(aWidgetId, moveForward);
}
},
onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) {
if (aArea == gPanel) {
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
let moveForward = this.shouldMoveForward(aWidgetId, aNewPosition);
this.adjustWidgets(aWidgetId, Math.min(aOldPosition, aNewPosition), moveForward);
this.adjustWidgets(aWidgetId, moveForward);
}
},
onWidgetRemoved: function(aWidgetId, aPrevArea) {
if (aPrevArea == gPanel) {
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
let pos = gPanelPlacements.indexOf(aWidgetId);
this.adjustWidgets(aWidgetId, pos);
this.adjustWidgets(aWidgetId, false);
}
},
onWidgetReset: function(aWidgetId) {
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
},
// Listener to keep abreast of any new nodes. We use the DOM one because
// we need access to the actual node's classlist, so we can't use the ones above.
// Furthermore, onWidgetCreated only fires for API-based widgets, not for XUL ones.
@@ -63,46 +73,31 @@ let PanelWideWidgetTracker = {
gWideWidgets.delete(aWidgetId);
},
shouldMoveForward: function(aWidgetId, aPosition) {
let currentWidgetAtPosition = gPanelPlacements[aPosition];
let currentWidgetAtPosition = gPanelPlacements[aPosition + 1];
return gWideWidgets.has(currentWidgetAtPosition) && !gWideWidgets.has(aWidgetId);
},
adjustWidgets: function(aWidgetId, aPosition, aMoveForwards) {
if (this.adjustmentStack == 0) {
this.movingForward = aMoveForwards;
}
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
// First, make a list of all the widgets that are *after* the insertion/moving point.
let widgetsAffected = [];
for (let widget of gWideWidgets) {
let wideWidgetPos = gPanelPlacements.indexOf(widget);
// This would just be wideWidgetPos >= aPosition, except that if we start re-arranging
// widgets, we would re-enter here because obviously the wide widget ends up in its
// own position, and we'd never stop trying to rearrange things.
// So instead, we check the wide widget is after the insertion point *or*
// this is the first move, and the widget is exactly on the insertion point
if (wideWidgetPos > aPosition || (!this.adjustmentStack && wideWidgetPos == aPosition)) {
widgetsAffected.push(widget);
}
}
if (!widgetsAffected.length) {
adjustWidgets: function(aWidgetId, aMoveForwards) {
if (this.adjusting) {
return;
}
widgetsAffected.sort(function(a, b) gPanelPlacements.indexOf(a) < gPanelPlacements.indexOf(b));
this.adjustmentStack++;
this.adjustPosition(widgetsAffected[0]);
this.adjustmentStack--;
if (this.adjustmentStack == 0) {
delete this.movingForward;
this.adjusting = true;
let widgetsAffected = [w for (w of gPanelPlacements) if (gWideWidgets.has(w))];
// If we're moving the wide widgets forwards (down/to the right in the panel)
// we want to start with the last widgets. Otherwise we move widgets over other wide
// widgets, which might mess up their order. Likewise, if moving backwards we should start with
// the first widget and work our way down/right from there.
let compareFn = aMoveForwards ? (function(a, b) a < b) : (function(a, b) a > b)
widgetsAffected.sort(function(a, b) compareFn(gPanelPlacements.indexOf(a),
gPanelPlacements.indexOf(b)));
for (let widget of widgetsAffected) {
this.adjustPosition(widget, aMoveForwards);
}
this.adjusting = false;
},
// This function is called whenever an item gets moved in the menu panel. It
// adjusts the position of widgets within the panel to reduce single-column
// buttons from being placed in a row by themselves.
adjustPosition: function(aWidgetId) {
// TODO(bug 885574): Merge this constant with the one in CustomizeMode.jsm,
// maybe just use a pref for this.
const kColumnsInMenuPanel = 3;
// adjusts the position of widgets within the panel to prevent "gaps" between
// wide widgets that could be filled up with single column widgets
adjustPosition: function(aWidgetId, aMoveForwards) {
// Make sure that there are n % columns = 0 narrow buttons before the widget.
let placementIndex = gPanelPlacements.indexOf(aWidgetId);
let prevSiblingCount = 0;
@@ -140,20 +135,15 @@ let PanelWideWidgetTracker = {
if (fixedPos !== null || prevSiblingCount % kColumnsInMenuPanel) {
let desiredPos = (fixedPos !== null) ? fixedPos : gPanelPlacements.indexOf(aWidgetId);
if (this.movingForward) {
// Add 1 because we're moving forward, and we would otherwise count the widget itself.
desiredPos += (kColumnsInMenuPanel - (prevSiblingCount % kColumnsInMenuPanel)) + 1;
} else {
desiredPos -= prevSiblingCount % kColumnsInMenuPanel;
let desiredChange = -(prevSiblingCount % kColumnsInMenuPanel);
if (aMoveForwards && fixedPos == null) {
// +1 because otherwise we'd count ourselves:
desiredChange = kColumnsInMenuPanel + desiredChange + 1;
}
// We don't need to move all of the items in this pass, because
// this move will trigger adjustPosition to get called again. The
// function will stop recursing when it finds that there is no
// more work that is needed.
desiredPos += desiredChange;
CustomizableUI.moveWidgetWithinArea(aWidgetId, desiredPos);
}
},
adjustmentStack: 0,
init: function() {
// Initialize our local placements copy and register the listener
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);

View File

@@ -149,8 +149,6 @@ let gTests = [
"preferences-button",
"add-ons-button"];
simulateItemDrag(developerButton, zoomControls);
// Currently, the developer-button is placed after the zoom-controls, but it should be
// placed like expectedPlacementsAfterInsert describes.
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
let palette = document.getElementById("customization-palette");
@@ -169,6 +167,42 @@ let gTests = [
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
},
},
{
desc: "Dragging an item from the palette to before the edit-controls " +
"should move it and two other buttons before the edit and zoom controls.",
setup: startCustomizing,
run: function() {
let developerButton = document.getElementById("developer-button");
let editControls = document.getElementById("edit-controls");
let placementsAfterInsert = ["developer-button",
"new-window-button",
"privatebrowsing-button",
"edit-controls",
"zoom-controls",
"save-page-button",
"print-button",
"history-panelmenu",
"fullscreen-button",
"find-button",
"preferences-button",
"add-ons-button"];
simulateItemDrag(developerButton, editControls);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
let palette = document.getElementById("customization-palette");
// Check that the palette items are re-wrapped correctly.
let feedWrapper = document.getElementById("wrapper-feed-button");
let feedButton = document.getElementById("feed-button");
is(feedButton.parentNode, feedWrapper,
"feed-button should be a child of wrapper-feed-button");
is(feedWrapper.getAttribute("place"), "palette",
"The feed-button wrapper should have it's place set to 'palette'");
simulateItemDrag(developerButton, palette);
is(developerButton.parentNode.tagName, "toolbarpaletteitem",
"The developer-button should be wrapped by a toolbarpaletteitem");
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
},
},
{
desc: "Dragging the edit-controls to be before the zoom-controls button " +
"should not move any widgets.",