mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset 77c3e8e02df4 (bug 919965) to fix commit msg
This commit is contained in:
parent
992d4ec18f
commit
9da15c701f
@ -1954,9 +1954,6 @@ this.CustomizableUI = {
|
||||
get TYPE_MENU_PANEL() "menu-panel",
|
||||
get TYPE_TOOLBAR() "toolbar",
|
||||
|
||||
get WIDE_PANEL_CLASS() "panel-wide-item",
|
||||
get PANEL_COLUMN_COUNT() 3,
|
||||
|
||||
addListener: function(aListener) {
|
||||
CustomizableUIInternal.addListener(aListener);
|
||||
},
|
||||
|
@ -14,6 +14,10 @@ const kPaletteId = "customization-palette";
|
||||
const kAboutURI = "about:customizing";
|
||||
const kDragDataTypePrefix = "text/toolbarwrapper-id/";
|
||||
const kPlaceholderClass = "panel-customization-placeholder";
|
||||
const kWidePanelItemClass = "panel-wide-item";
|
||||
// TODO(bug 885574): Merge this constant with the one in CustomizableWidgets.jsm,
|
||||
// maybe just use a pref for this.
|
||||
const kColumnsInMenuPanel = 3;
|
||||
const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
@ -21,8 +25,6 @@ Cu.import("resource:///modules/CustomizableUI.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DragPositionManager",
|
||||
"resource:///modules/DragPositionManager.jsm");
|
||||
|
||||
let gModuleName = "[CustomizeMode]";
|
||||
#include logging.js
|
||||
@ -216,7 +218,6 @@ CustomizeMode.prototype = {
|
||||
|
||||
window.gNavToolbox.removeEventListener("toolbarvisibilitychange", this);
|
||||
|
||||
DragPositionManager.stop();
|
||||
window.PanelUI.mainView.removeEventListener("contextmenu", this, true);
|
||||
this.visiblePalette.removeEventListener("dragstart", this, true);
|
||||
this.visiblePalette.removeEventListener("dragover", this, true);
|
||||
@ -796,28 +797,22 @@ CustomizeMode.prototype = {
|
||||
|
||||
// Hack needed so that the dragimage will still show the
|
||||
// item as it appeared before it was hidden.
|
||||
this._initializeDragAfterMove = function() {
|
||||
let win = aEvent.target.ownerDocument.defaultView;
|
||||
win.setTimeout(function() {
|
||||
// For automated tests, we sometimes start exiting customization mode
|
||||
// before this fires, which leaves us with placeholders inserted after
|
||||
// we've exited. So we need to check that we are indeed customizing.
|
||||
if (this._customizing && !this._transitioning) {
|
||||
item.hidden = true;
|
||||
this._showPanelCustomizationPlaceholders();
|
||||
DragPositionManager.start(this.window);
|
||||
}
|
||||
this._initializeDragAfterMove = null;
|
||||
this.window.clearTimeout(this._dragInitializeTimeout);
|
||||
}.bind(this);
|
||||
this._dragInitializeTimeout = this.window.setTimeout(this._initializeDragAfterMove, 0);
|
||||
}.bind(this), 0);
|
||||
},
|
||||
|
||||
_onDragOver: function(aEvent) {
|
||||
if (this._isUnwantedDragDrop(aEvent)) {
|
||||
return;
|
||||
}
|
||||
if (this._initializeDragAfterMove) {
|
||||
this._initializeDragAfterMove();
|
||||
}
|
||||
|
||||
__dumpDragData(aEvent);
|
||||
|
||||
@ -850,8 +845,7 @@ CustomizeMode.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let targetIsToolbar = CustomizableUI.getAreaType(targetArea.id) == "toolbar";
|
||||
let targetNode = this._getDragOverNode(aEvent, targetArea, targetIsToolbar, draggedItemId);
|
||||
let targetNode = this._getDragOverNode(aEvent, targetArea);
|
||||
|
||||
// We need to determine the place that the widget is being dropped in
|
||||
// the target.
|
||||
@ -869,15 +863,20 @@ CustomizeMode.prototype = {
|
||||
dragValue = "after";
|
||||
} else {
|
||||
dragOverItem = targetParent.children[position];
|
||||
if (!targetIsToolbar) {
|
||||
dragValue = "before";
|
||||
dragOverItem = position == -1 ? targetParent.firstChild : targetParent.children[position];
|
||||
} else {
|
||||
// Check if the aDraggedItem is hovered past the first half of dragOverItem
|
||||
let window = dragOverItem.ownerDocument.defaultView;
|
||||
let direction = window.getComputedStyle(dragOverItem, null).direction;
|
||||
let itemRect = dragOverItem.getBoundingClientRect();
|
||||
let dropTargetCenter = itemRect.left + (itemRect.width / 2);
|
||||
if (targetParent == window.PanelUI.contents) {
|
||||
dragValue = "true";
|
||||
if (direction == "ltr" && aEvent.clientX > dropTargetCenter) {
|
||||
position++;
|
||||
} else if (direction == "rtl" && aEvent.clientX < dropTargetCenter) {
|
||||
position--;
|
||||
}
|
||||
dragOverItem = position == -1 ? targetParent.firstChild : targetParent.children[position];
|
||||
} else {
|
||||
let existingDir = dragOverItem.getAttribute("dragover");
|
||||
if ((existingDir == "before") == (direction == "ltr")) {
|
||||
dropTargetCenter += (parseInt(dragOverItem.style.borderLeftWidth) || 0) / 2;
|
||||
@ -891,12 +890,12 @@ CustomizeMode.prototype = {
|
||||
}
|
||||
|
||||
if (this._dragOverItem && dragOverItem != this._dragOverItem) {
|
||||
this._cancelDragActive(this._dragOverItem, dragOverItem);
|
||||
this._setDragActive(this._dragOverItem, false);
|
||||
}
|
||||
|
||||
if (dragOverItem != this._dragOverItem || dragValue != dragOverItem.getAttribute("dragover")) {
|
||||
if (dragOverItem != targetArea.customizationTarget) {
|
||||
this._setDragActive(dragOverItem, dragValue, draggedItemId, targetIsToolbar);
|
||||
this._setDragActive(dragOverItem, dragValue, draggedItemId);
|
||||
}
|
||||
this._dragOverItem = dragOverItem;
|
||||
}
|
||||
@ -911,8 +910,6 @@ CustomizeMode.prototype = {
|
||||
}
|
||||
|
||||
__dumpDragData(aEvent);
|
||||
this._initializeDragAfterMove = null;
|
||||
this.window.clearTimeout(this._dragInitializeTimeout);
|
||||
|
||||
let targetArea = this._getCustomizableParent(aEvent.currentTarget);
|
||||
let document = aEvent.target.ownerDocument;
|
||||
@ -921,8 +918,8 @@ CustomizeMode.prototype = {
|
||||
aEvent.dataTransfer.mozGetDataAt(kDragDataTypePrefix + documentId, 0);
|
||||
let draggedWrapper = document.getElementById("wrapper-" + draggedItemId);
|
||||
let originArea = this._getCustomizableParent(draggedWrapper);
|
||||
if (this._dragSizeMap) {
|
||||
this._dragSizeMap.clear();
|
||||
if (this._dragWidthMap) {
|
||||
this._dragWidthMap.clear();
|
||||
}
|
||||
// Do nothing if the target area or origin area are not customizable.
|
||||
if (!targetArea || !originArea) {
|
||||
@ -946,7 +943,7 @@ CustomizeMode.prototype = {
|
||||
targetNode = targetNode.firstChild;
|
||||
}
|
||||
|
||||
this._cancelDragActive(this._dragOverItem, null, true);
|
||||
this._setDragActive(this._dragOverItem, false);
|
||||
this._removePanelCustomizationPlaceholders();
|
||||
|
||||
try {
|
||||
@ -1070,14 +1067,8 @@ CustomizeMode.prototype = {
|
||||
|
||||
__dumpDragData(aEvent);
|
||||
|
||||
// When leaving customization areas, cancel the drag on the last dragover item
|
||||
// We've attached the listener to areas, so aEvent.currentTarget will be the area.
|
||||
// We don't care about dragexit events fired on descendants of the area,
|
||||
// so we check that the event's target is the same as the area to which the listener
|
||||
// was attached.
|
||||
if (this._dragOverItem && aEvent.target == aEvent.currentTarget) {
|
||||
this._cancelDragActive(this._dragOverItem);
|
||||
this._dragOverItem = null;
|
||||
if (this._dragOverItem) {
|
||||
this._setDragActive(this._dragOverItem, false);
|
||||
}
|
||||
},
|
||||
|
||||
@ -1085,8 +1076,6 @@ CustomizeMode.prototype = {
|
||||
if (this._isUnwantedDragDrop(aEvent)) {
|
||||
return;
|
||||
}
|
||||
this._initializeDragAfterMove = null;
|
||||
this.window.clearTimeout(this._dragInitializeTimeout);
|
||||
|
||||
__dumpDragData(aEvent);
|
||||
let document = aEvent.target.ownerDocument;
|
||||
@ -1125,21 +1114,24 @@ CustomizeMode.prototype = {
|
||||
mozSourceNode.ownerDocument.defaultView != this.window;
|
||||
},
|
||||
|
||||
_setDragActive: function(aItem, aValue, aDraggedItemId, aInToolbar) {
|
||||
_setDragActive: function(aItem, aValue, aDraggedItemId) {
|
||||
if (!aItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aValue) {
|
||||
if (aItem.hasAttribute("dragover") != aValue) {
|
||||
aItem.setAttribute("dragover", aValue);
|
||||
|
||||
// Calculate width of the item when it'd be dropped in this position
|
||||
let window = aItem.ownerDocument.defaultView;
|
||||
let draggedItem = window.document.getElementById(aDraggedItemId);
|
||||
if (!aInToolbar) {
|
||||
this._setPanelDragActive(aItem, draggedItem, aValue);
|
||||
let width = this._getDragItemWidth(aItem, draggedItem);
|
||||
if (width) {
|
||||
let panelContents = window.PanelUI.contents;
|
||||
if (aItem.parentNode == panelContents) {
|
||||
this._setPanelDragActive(aItem, draggedItem, width);
|
||||
} else {
|
||||
// Calculate width of the item when it'd be dropped in this position
|
||||
let width = this._getDragItemSize(aItem, draggedItem).width;
|
||||
let direction = window.getComputedStyle(aItem).direction;
|
||||
let prop, otherProp;
|
||||
// If we're inserting before in ltr, or after in rtl:
|
||||
@ -1151,88 +1143,131 @@ CustomizeMode.prototype = {
|
||||
prop = "borderRightWidth";
|
||||
otherProp = "border-left-width";
|
||||
}
|
||||
aItem.style[prop] = width + 'px';
|
||||
aItem.style[prop] = width;
|
||||
aItem.style.removeProperty(otherProp);
|
||||
}
|
||||
}
|
||||
},
|
||||
_cancelDragActive: function(aItem, aNextItem, aNoTransition) {
|
||||
let currentArea = this._getCustomizableParent(aItem);
|
||||
if (!currentArea) {
|
||||
return;
|
||||
}
|
||||
let isToolbar = CustomizableUI.getAreaType(currentArea.id) == "toolbar";
|
||||
if (isToolbar) {
|
||||
} else {
|
||||
aItem.removeAttribute("dragover");
|
||||
// Remove both property values in the case that the end padding
|
||||
// had been set.
|
||||
aItem.style.removeProperty("border-left-width");
|
||||
aItem.style.removeProperty("border-right-width");
|
||||
} else {
|
||||
if (aNextItem) {
|
||||
let nextArea = this._getCustomizableParent(aNextItem);
|
||||
if (nextArea == currentArea) {
|
||||
// No need to do anything if we're still dragging in this area:
|
||||
}
|
||||
},
|
||||
|
||||
_setPanelDragActive: function(aDragOverNode, aDraggedItem, aWidth) {
|
||||
let document = aDragOverNode.ownerDocument;
|
||||
let window = document.defaultView;
|
||||
let panelContents = window.PanelUI.contents;
|
||||
while (!aDragOverNode.id && aDragOverNode.parentNode != panelContents)
|
||||
aDragOverNode = aDragOverNode.parentNode;
|
||||
if (!aDragOverNode.id)
|
||||
return;
|
||||
|
||||
if (!aDragOverNode.previousSibling ||
|
||||
!aDragOverNode.previousSibling.classList.contains(kPlaceholderClass)) {
|
||||
let isPlaceholderAtEnd = function(aPlaceholder) {
|
||||
do {
|
||||
aPlaceholder = aPlaceholder.nextSibling;
|
||||
if (!aPlaceholder)
|
||||
return true;
|
||||
if (!aPlaceholder.classList.contains(kPlaceholderClass))
|
||||
return false;
|
||||
} while (aPlaceholder.nextSibling)
|
||||
return true;
|
||||
}
|
||||
|
||||
let resetAnimAttributes = function(aPlaceholder) {
|
||||
if (!aPlaceholder)
|
||||
return;
|
||||
aPlaceholder.removeAttribute("expand");
|
||||
aPlaceholder.removeAttribute("contract");
|
||||
aPlaceholder.removeAttribute("hidden");
|
||||
aPlaceholder.style.removeProperty("width");
|
||||
}
|
||||
|
||||
let placeholders = Array.slice(panelContents.getElementsByClassName(kPlaceholderClass));
|
||||
|
||||
let toExpand = placeholders.shift();
|
||||
let toContract = placeholders.shift();
|
||||
if (toContract && isPlaceholderAtEnd(toContract))
|
||||
toContract = null;
|
||||
// Seek to find hidden placeholders first to use for the expand transition.
|
||||
while (toExpand.getAttribute("hidden") != "true" && placeholders.length)
|
||||
toExpand = placeholders.shift();
|
||||
|
||||
if (toExpand.transitioning || (toContract && toContract.transitioning))
|
||||
return;
|
||||
|
||||
let wasHidden = (toContract && toContract.getAttribute("hidden") == "true") ||
|
||||
toExpand.getAttribute("hidden") == "true";
|
||||
resetAnimAttributes(toContract);
|
||||
resetAnimAttributes(toExpand);
|
||||
|
||||
aDragOverNode.parentNode.insertBefore(toExpand, aDragOverNode);
|
||||
toExpand.style.width = "0px";
|
||||
toExpand.setAttribute("expand", "true");
|
||||
toExpand.transitioning = true;
|
||||
if (toContract) {
|
||||
toContract.style.width = aWidth;
|
||||
toContract.setAttribute("contract", "true");
|
||||
toContract.transitioning = true;
|
||||
}
|
||||
|
||||
window.mozRequestAnimationFrame(() => {
|
||||
if (toContract)
|
||||
toContract.style.width = "0px";
|
||||
toExpand.style.width = aWidth;
|
||||
});
|
||||
toExpand.addEventListener("transitionend", function expandTransitionEnd() {
|
||||
toExpand.removeEventListener("transitionend", expandTransitionEnd, false);
|
||||
toExpand.transitioning = false;
|
||||
});
|
||||
if (toContract) {
|
||||
toContract.addEventListener("transitionend", function contractTransitionEnd() {
|
||||
toContract.removeEventListener("transitionend", contractTransitionEnd, false);
|
||||
panelContents.appendChild(toContract);
|
||||
if (wasHidden)
|
||||
toContract.setAttribute("hidden", "true");
|
||||
toContract.transitioning = false;
|
||||
});
|
||||
}
|
||||
// Otherwise, clear everything out:
|
||||
let positionManager = DragPositionManager.getManagerForArea(currentArea);
|
||||
positionManager.clearPlaceholders(currentArea, aNoTransition);
|
||||
}
|
||||
},
|
||||
|
||||
_setPanelDragActive: function(aDragOverNode, aDraggedItem, aValue) {
|
||||
let targetArea = this._getCustomizableParent(aDragOverNode);
|
||||
let positionManager = DragPositionManager.getManagerForArea(targetArea);
|
||||
let draggedSize = this._getDragItemSize(aDragOverNode, aDraggedItem);
|
||||
let isWide = aDraggedItem.classList.contains(CustomizableUI.WIDE_PANEL_CLASS);
|
||||
positionManager.insertPlaceholder(targetArea, aDragOverNode, isWide, draggedSize);
|
||||
},
|
||||
|
||||
_getDragItemSize: function(aDragOverNode, aDraggedItem) {
|
||||
_getDragItemWidth: function(aDragOverNode, aDraggedItem) {
|
||||
// Cache it good, cache it real good.
|
||||
if (!this._dragSizeMap)
|
||||
this._dragSizeMap = new WeakMap();
|
||||
if (!this._dragSizeMap.has(aDraggedItem))
|
||||
this._dragSizeMap.set(aDraggedItem, new WeakMap());
|
||||
let itemMap = this._dragSizeMap.get(aDraggedItem);
|
||||
if (!this._dragWidthMap)
|
||||
this._dragWidthMap = new WeakMap();
|
||||
if (!this._dragWidthMap.has(aDraggedItem))
|
||||
this._dragWidthMap.set(aDraggedItem, new WeakMap());
|
||||
let itemMap = this._dragWidthMap.get(aDraggedItem);
|
||||
let targetArea = this._getCustomizableParent(aDragOverNode);
|
||||
let currentArea = this._getCustomizableParent(aDraggedItem);
|
||||
// Return the size for this target from cache, if it exists.
|
||||
let size = itemMap.get(targetArea);
|
||||
if (size)
|
||||
return size;
|
||||
if (!targetArea)
|
||||
return;
|
||||
// Return the width for this target from cache, if it exists.
|
||||
let width = itemMap.get(targetArea);
|
||||
if (width)
|
||||
return width;
|
||||
|
||||
// Calculate size of the item when it'd be dropped in this position.
|
||||
// Calculate width of the item when it'd be dropped in this position.
|
||||
let currentParent = aDraggedItem.parentNode;
|
||||
let currentSibling = aDraggedItem.nextSibling;
|
||||
const kAreaType = "cui-areatype";
|
||||
let areaType, currentType;
|
||||
|
||||
if (targetArea != currentArea) {
|
||||
// Move the widget temporarily next to the placeholder.
|
||||
aDragOverNode.parentNode.insertBefore(aDraggedItem, aDragOverNode);
|
||||
// Update the node's areaType.
|
||||
areaType = CustomizableUI.getAreaType(targetArea.id);
|
||||
currentType = aDraggedItem.hasAttribute(kAreaType) &&
|
||||
let areaType = CustomizableUI.getAreaType(targetArea.id);
|
||||
const kAreaType = "cui-areatype";
|
||||
let currentType = aDraggedItem.hasAttribute(kAreaType) &&
|
||||
aDraggedItem.getAttribute(kAreaType);
|
||||
if (areaType)
|
||||
aDraggedItem.setAttribute(kAreaType, areaType);
|
||||
this.wrapToolbarItem(aDraggedItem, areaType || "palette");
|
||||
CustomizableUI.onWidgetDrag(aDraggedItem.id, targetArea.id);
|
||||
} else {
|
||||
aDraggedItem.parentNode.hidden = false;
|
||||
}
|
||||
|
||||
// Fetch the new size.
|
||||
let rect = aDraggedItem.parentNode.getBoundingClientRect();
|
||||
size = {width: rect.width, height: rect.height};
|
||||
// Cache the found value of size for this target.
|
||||
itemMap.set(targetArea, size);
|
||||
|
||||
if (targetArea != currentArea) {
|
||||
this.unwrapToolbarItem(aDraggedItem.parentNode);
|
||||
// Fetch the new width.
|
||||
width = Math.floor(aDraggedItem.getBoundingClientRect().width) + "px";
|
||||
// Put the item back into its previous position.
|
||||
if (currentSibling)
|
||||
currentParent.insertBefore(aDraggedItem, currentSibling);
|
||||
@ -1246,10 +1281,9 @@ CustomizeMode.prototype = {
|
||||
aDraggedItem.setAttribute(kAreaType, currentType);
|
||||
}
|
||||
CustomizableUI.onWidgetDrag(aDraggedItem.id);
|
||||
} else {
|
||||
aDraggedItem.parentNode.hidden = true;
|
||||
}
|
||||
return size;
|
||||
// Cache the found value of width for this target.
|
||||
itemMap.set(targetArea, width);
|
||||
return width;
|
||||
},
|
||||
|
||||
_getCustomizableParent: function(aElement) {
|
||||
@ -1264,7 +1298,7 @@ CustomizeMode.prototype = {
|
||||
return null;
|
||||
},
|
||||
|
||||
_getDragOverNode: function(aEvent, aAreaElement, aInToolbar, aDraggedItemId) {
|
||||
_getDragOverNode: function(aEvent, aAreaElement) {
|
||||
let expectedParent = aAreaElement.customizationTarget || aAreaElement;
|
||||
// Our tests are stupid. Cope:
|
||||
if (!aEvent.clientX && !aEvent.clientY) {
|
||||
@ -1280,17 +1314,10 @@ CustomizeMode.prototype = {
|
||||
dragX = Math.min(bounds.right, Math.max(dragX, bounds.left));
|
||||
dragY = Math.min(bounds.bottom, Math.max(dragY, bounds.top));
|
||||
|
||||
let targetNode;
|
||||
if (aInToolbar) {
|
||||
targetNode = aAreaElement.ownerDocument.elementFromPoint(dragX, dragY);
|
||||
let targetNode = aAreaElement.ownerDocument.elementFromPoint(dragX, dragY);
|
||||
while (targetNode && targetNode.parentNode != expectedParent) {
|
||||
targetNode = targetNode.parentNode;
|
||||
}
|
||||
} else {
|
||||
let positionManager = DragPositionManager.getManagerForArea(aAreaElement);
|
||||
// Find the closest node:
|
||||
targetNode = positionManager.find(aAreaElement, dragX, dragY, aDraggedItemId);
|
||||
}
|
||||
return targetNode || aEvent.target;
|
||||
},
|
||||
|
||||
@ -1299,7 +1326,7 @@ CustomizeMode.prototype = {
|
||||
let doc = aEvent.target.ownerDocument;
|
||||
doc.documentElement.setAttribute("customizing-movingItem", true);
|
||||
let item = this._getWrapper(aEvent.target);
|
||||
if (item && !item.classList.contains(kPlaceholderClass)) {
|
||||
if (item) {
|
||||
item.setAttribute("mousedown", "true");
|
||||
}
|
||||
},
|
||||
@ -1324,24 +1351,27 @@ CustomizeMode.prototype = {
|
||||
},
|
||||
|
||||
_showPanelCustomizationPlaceholders: function() {
|
||||
this._removePanelCustomizationPlaceholders();
|
||||
let doc = this.document;
|
||||
let contents = this.panelUIContents;
|
||||
let visibleWideItems = contents.querySelectorAll("toolbarpaletteitem:not([hidden]) > ." + kWidePanelItemClass);
|
||||
let visibleChildren = contents.querySelectorAll("toolbarpaletteitem:not([hidden])");
|
||||
// TODO(bug 885578): Still doesn't handle a hole when there is a wide
|
||||
// widget located at the bottom of the panel.
|
||||
let narrowItemsAfterWideItem = 0;
|
||||
let node = contents.lastChild;
|
||||
while (node && !node.classList.contains(CustomizableUI.WIDE_PANEL_CLASS) &&
|
||||
(!node.firstChild || !node.firstChild.classList.contains(CustomizableUI.WIDE_PANEL_CLASS))) {
|
||||
if (!node.hidden && !node.classList.contains(kPlaceholderClass)) {
|
||||
while (node && !node.classList.contains(kWidePanelItemClass) &&
|
||||
(!node.firstChild || !node.firstChild.classList.contains(kWidePanelItemClass))) {
|
||||
if (!node.hidden) {
|
||||
narrowItemsAfterWideItem++;
|
||||
}
|
||||
node = node.previousSibling;
|
||||
}
|
||||
|
||||
let orphanedItems = narrowItemsAfterWideItem % CustomizableUI.PANEL_COLUMN_COUNT;
|
||||
let placeholders = CustomizableUI.PANEL_COLUMN_COUNT - orphanedItems;
|
||||
let orphanedItems = narrowItemsAfterWideItem % kColumnsInMenuPanel;
|
||||
let placeholders = kColumnsInMenuPanel - orphanedItems;
|
||||
|
||||
let currentPlaceholderCount = contents.querySelectorAll("." + kPlaceholderClass).length;
|
||||
if (placeholders > currentPlaceholderCount) {
|
||||
while (placeholders-- > currentPlaceholderCount) {
|
||||
while (placeholders--) {
|
||||
let placeholder = doc.createElement("toolbarpaletteitem");
|
||||
placeholder.classList.add(kPlaceholderClass);
|
||||
//XXXjaws The toolbarbutton child here is only necessary to get
|
||||
@ -1351,11 +1381,6 @@ CustomizeMode.prototype = {
|
||||
placeholder.appendChild(placeholderChild);
|
||||
contents.appendChild(placeholder);
|
||||
}
|
||||
} else if (placeholders < currentPlaceholderCount) {
|
||||
while (placeholders++ < currentPlaceholderCount) {
|
||||
contents.querySelectorAll("." + kPlaceholderClass)[0].remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_removePanelCustomizationPlaceholders: function() {
|
||||
@ -1384,9 +1409,6 @@ function getPlaceForItem(aElement) {
|
||||
}
|
||||
|
||||
function __dumpDragData(aEvent, caller) {
|
||||
if (!gDebug) {
|
||||
return;
|
||||
}
|
||||
let str = "Dumping drag data (CustomizeMode.jsm) {\n";
|
||||
str += " type: " + aEvent["type"] + "\n";
|
||||
for (let el of ["target", "currentTarget", "relatedTarget"]) {
|
||||
|
@ -1,364 +0,0 @@
|
||||
/* 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";
|
||||
|
||||
Components.utils.import("resource:///modules/CustomizableUI.jsm");
|
||||
|
||||
let gManagers = new WeakMap();
|
||||
|
||||
const kPaletteId = "customization-palette";
|
||||
const kPlaceholderClass = "panel-customization-placeholder";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DragPositionManager"];
|
||||
|
||||
function AreaPositionManager(aContainer) {
|
||||
// Caching the direction and bounds of the container for quick access later:
|
||||
let window = aContainer.ownerDocument.defaultView;
|
||||
this._dir = window.getComputedStyle(aContainer).direction;
|
||||
let containerRect = aContainer.getBoundingClientRect();
|
||||
this._containerInfo = {
|
||||
left: containerRect.left,
|
||||
right: containerRect.right,
|
||||
width: containerRect.width
|
||||
};
|
||||
this._inPanel = aContainer.id == CustomizableUI.AREA_PANEL;
|
||||
this._horizontalDistance = null;
|
||||
this.update(aContainer);
|
||||
}
|
||||
|
||||
AreaPositionManager.prototype = {
|
||||
_nodePositionStore: null,
|
||||
_wideCache: null,
|
||||
|
||||
update: function(aContainer) {
|
||||
let window = aContainer.ownerDocument.defaultView;
|
||||
this._nodePositionStore = new WeakMap();
|
||||
this._wideCache = new Set();
|
||||
let last = null;
|
||||
let singleItemHeight;
|
||||
for (let child of aContainer.children) {
|
||||
let isNodeWide = this._checkIfWide(child);
|
||||
if (isNodeWide) {
|
||||
this._wideCache.add(child.id);
|
||||
}
|
||||
let coordinates = this._lazyStoreGet(child);
|
||||
// We keep a baseline horizontal distance between non-wide nodes around
|
||||
// for use when we can't compare with previous/next nodes
|
||||
if (!this._horizontalDistance && last && !isNodeWide) {
|
||||
this._horizontalDistance = coordinates.left - last.left;
|
||||
}
|
||||
// We also keep the basic height of non-wide items for use below:
|
||||
if (!isNodeWide && !singleItemHeight) {
|
||||
singleItemHeight = coordinates.height;
|
||||
}
|
||||
last = !isNodeWide ? coordinates : null;
|
||||
}
|
||||
if (this._inPanel) {
|
||||
this._heightToWidthFactor = CustomizableUI.PANEL_COLUMN_COUNT;
|
||||
} else {
|
||||
this._heightToWidthFactor = this._containerInfo.width / singleItemHeight;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the closest node in the container given the coordinates.
|
||||
* "Closest" is defined in a somewhat strange manner: we prefer nodes
|
||||
* which are in the same row over nodes that are in a different row.
|
||||
* In order to implement this, we use a weighted cartesian distance
|
||||
* where dy is more heavily weighted by a factor corresponding to the
|
||||
* ratio between the container's width and the height of its elements.
|
||||
*/
|
||||
find: function(aContainer, aX, aY, aDraggedItemId) {
|
||||
let closest = null;
|
||||
let minCartesian = Number.MAX_VALUE;
|
||||
for (let node of aContainer.children) {
|
||||
let coordinates = this._lazyStoreGet(node);
|
||||
let hDiff = coordinates.x - aX;
|
||||
let vDiff = coordinates.y - aY;
|
||||
// For wide widgets, we're always going to be further from the center
|
||||
// horizontally. Compensate:
|
||||
if (this.isWide(node)) {
|
||||
hDiff /= CustomizableUI.PANEL_COLUMN_COUNT;
|
||||
}
|
||||
// Then compensate for the height/width ratio so that we prefer items
|
||||
// which are in the same row:
|
||||
hDiff /= this._heightToWidthFactor;
|
||||
|
||||
let cartesianDiff = hDiff * hDiff + vDiff * vDiff;
|
||||
if (cartesianDiff < minCartesian) {
|
||||
minCartesian = cartesianDiff;
|
||||
closest = node;
|
||||
}
|
||||
}
|
||||
|
||||
// Now correct this node based on what we're dragging
|
||||
if (closest) {
|
||||
let doc = aContainer.ownerDocument;
|
||||
let draggedItem = doc.getElementById(aDraggedItemId);
|
||||
// If dragging a wide item, always pick the first item in a row:
|
||||
if (draggedItem &&
|
||||
draggedItem.classList.contains(CustomizableUI.WIDE_PANEL_CLASS)) {
|
||||
return this._firstInRow(closest);
|
||||
}
|
||||
let targetBounds = this._lazyStoreGet(closest);
|
||||
let farSide = this._dir == "ltr" ? "right" : "left";
|
||||
let outsideX = targetBounds[farSide];
|
||||
// Check if we're closer to the next target than to this one:
|
||||
// Only move if we're not targeting a node in a different row:
|
||||
if (aY > targetBounds.top && aY < targetBounds.bottom) {
|
||||
if ((this._dir == "ltr" && aX > outsideX) ||
|
||||
(this._dir == "rtl" && aX < outsideX)) {
|
||||
return closest.nextSibling || aContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
},
|
||||
|
||||
/**
|
||||
* "Insert" a "placeholder" by shifting the subsequent children out of the
|
||||
* way. We go through all the children, and shift them based on the position
|
||||
* they would have if we had inserted something before aBefore. We use CSS
|
||||
* transforms for this, which are CSS transitioned.
|
||||
*/
|
||||
insertPlaceholder: function(aContainer, aBefore, aWide, aSize) {
|
||||
let isShifted = false;
|
||||
let shiftDown = aWide;
|
||||
for (let child of aContainer.children) {
|
||||
// Don't need to shift hidden nodes:
|
||||
if (child.getAttribute("hidden") == "true") {
|
||||
continue;
|
||||
}
|
||||
// If this is the node before which we're inserting, start shifting
|
||||
// everything that comes after. One exception is inserting at the end
|
||||
// of the menupanel, in which case we do not shift the placeholders:
|
||||
if (child == aBefore && !child.classList.contains(kPlaceholderClass)) {
|
||||
isShifted = true;
|
||||
// If the node before which we're inserting is wide, we should
|
||||
// shift everything one row down:
|
||||
if (!shiftDown && this.isWide(child)) {
|
||||
shiftDown = true;
|
||||
}
|
||||
}
|
||||
// If we're moving items before a wide node that were already there,
|
||||
// it's possible it's not necessary to shift nodes
|
||||
// including & after the wide node.
|
||||
if (this.__undoShift) {
|
||||
isShifted = false;
|
||||
}
|
||||
if (isShifted) {
|
||||
// Conversely, if we're adding something before a wide node, for
|
||||
// simplicity's sake we move everything including the wide node down:
|
||||
if (this.__moveDown) {
|
||||
shiftDown = true;
|
||||
}
|
||||
// Determine the CSS transform based on the next node:
|
||||
child.style.transform = this._getNextPos(child, shiftDown, aSize);
|
||||
} else {
|
||||
// If we're not shifting this node, reset the transform
|
||||
child.style.transform = "";
|
||||
}
|
||||
}
|
||||
delete this.__moveDown;
|
||||
delete this.__undoShift;
|
||||
},
|
||||
|
||||
isWide: function(aNode) {
|
||||
return this._wideCache.has(aNode.id);
|
||||
},
|
||||
|
||||
_checkIfWide: function(aNode) {
|
||||
return this._inPanel && aNode && aNode.firstChild &&
|
||||
aNode.firstChild.classList.contains(CustomizableUI.WIDE_PANEL_CLASS);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset all the transforms in this container, optionally without
|
||||
* transitioning them.
|
||||
* @param aContainer the container in which to reset transforms
|
||||
* @param aNoTransition if truthy, adds a notransition attribute to the node
|
||||
* while resetting the transform.
|
||||
*/
|
||||
clearPlaceholders: function(aContainer, aNoTransition) {
|
||||
for (let child of aContainer.children) {
|
||||
if (aNoTransition) {
|
||||
child.setAttribute("notransition", true);
|
||||
}
|
||||
child.style.transform = "";
|
||||
if (aNoTransition) {
|
||||
// Need to force a reflow otherwise this won't work.
|
||||
child.getBoundingClientRect();
|
||||
child.removeAttribute("notransition");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_getNextPos: function(aNode, aShiftDown, aSize) {
|
||||
// Shifting down is easy:
|
||||
if (this._inPanel && aShiftDown) {
|
||||
return "translate(0, " + aSize.height + "px)";
|
||||
}
|
||||
return this._diffWithNext(aNode, aSize);
|
||||
},
|
||||
|
||||
_diffWithNext: function(aNode, aSize) {
|
||||
let xDiff;
|
||||
let yDiff = null;
|
||||
let nodeBounds = this._lazyStoreGet(aNode);
|
||||
let side = this._dir == "ltr" ? "left" : "right";
|
||||
let next = this._getVisibleSiblingForDirection(aNode, "next");
|
||||
// First we determine the transform along the x axis.
|
||||
// Usually, there will be a next node to base this on:
|
||||
if (next) {
|
||||
let otherBounds = this._lazyStoreGet(next);
|
||||
xDiff = otherBounds[side] - nodeBounds[side];
|
||||
// If the next node is a wide item in the panel, check if we could maybe
|
||||
// just move further out in the same row, without snapping to the next
|
||||
// one. This happens, for example, if moving an item that's before a wide
|
||||
// node within its own row of items. There will be space to drop this
|
||||
// item within the row, and the rest of the items do not need to shift.
|
||||
if (this.isWide(next)) {
|
||||
let otherXDiff = this._moveNextBasedOnPrevious(aNode, nodeBounds,
|
||||
this._firstInRow(aNode));
|
||||
// If this has the same sign as our original shift, we're still
|
||||
// snapping to the start of the row. In this case, we should move
|
||||
// everything after us a row down, so as not to display two nodes on
|
||||
// top of each other:
|
||||
// (we would be able to get away with checking for equality instead of
|
||||
// equal signs here, but one of these is based on the x coordinate of
|
||||
// the first item in row N and one on that for row N - 1, so this is
|
||||
// safer, as their margins might differ)
|
||||
if ((otherXDiff < 0) == (xDiff < 0)) {
|
||||
this.__moveDown = true;
|
||||
} else {
|
||||
// Otherwise, we succeeded and can move further out. This also means
|
||||
// we can stop shifting the rest of the content:
|
||||
xDiff = otherXDiff;
|
||||
this.__undoShift = true;
|
||||
}
|
||||
} else {
|
||||
// We set this explicitly because otherwise some strange difference
|
||||
// between the height and the actual difference between line creeps in
|
||||
// and messes with alignments
|
||||
yDiff = otherBounds.top - nodeBounds.top;
|
||||
}
|
||||
} else {
|
||||
// We don't have a sibling whose position we can use. First, let's see
|
||||
// if we're also the first item (which complicates things):
|
||||
let firstNode = this._firstInRow(aNode);
|
||||
if (aNode == firstNode) {
|
||||
// Maybe we stored the horizontal distance between non-wide nodes,
|
||||
// if not, we'll use the width of the incoming node as a proxy:
|
||||
xDiff = this._horizontalDistance || aSize.width;
|
||||
} else {
|
||||
// If not, we should be able to get the distance to the previous node
|
||||
// and use the inverse, unless there's no room for another node (ie we
|
||||
// are the last node and there's no room for another one)
|
||||
xDiff = this._moveNextBasedOnPrevious(aNode, nodeBounds, firstNode);
|
||||
}
|
||||
}
|
||||
|
||||
// If we've not determined the vertical difference yet, check it here
|
||||
if (yDiff === null) {
|
||||
// If the next node is behind rather than in front, we must have moved
|
||||
// vertically:
|
||||
if ((xDiff > 0 && this._dir == "rtl") || (xDiff < 0 && this._dir == "ltr")) {
|
||||
yDiff = aSize.height;
|
||||
} else {
|
||||
// Otherwise, we haven't
|
||||
yDiff = 0;
|
||||
}
|
||||
}
|
||||
return "translate(" + xDiff + "px, " + yDiff + "px)";
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function to find the transform a node if there isn't a next node
|
||||
* to base that on.
|
||||
* @param aNode the node to transform
|
||||
* @param aNodeBounds the bounding rect info of this node
|
||||
* @param aFirstNodeInRow the first node in aNode's row
|
||||
*/
|
||||
_moveNextBasedOnPrevious: function(aNode, aNodeBounds, aFirstNodeInRow) {
|
||||
let next = this._getVisibleSiblingForDirection(aNode, "previous");
|
||||
let otherBounds = this._lazyStoreGet(next);
|
||||
let side = this._dir == "ltr" ? "left" : "right";
|
||||
let xDiff = aNodeBounds[side] - otherBounds[side];
|
||||
// If, however, this means we move outside the container's box
|
||||
// (i.e. the row in which this item is placed is full)
|
||||
// we should move it to align with the first item in the next row instead
|
||||
let bound = this._containerInfo[this._dir == "ltr" ? "right" : "left"];
|
||||
if ((this._dir == "ltr" && xDiff + aNodeBounds.right > bound) ||
|
||||
(this._dir == "rtl" && xDiff + aNodeBounds.left < bound)) {
|
||||
xDiff = this._lazyStoreGet(aFirstNodeInRow)[side] - aNodeBounds[side];
|
||||
}
|
||||
return xDiff;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get position details from our cache. If the node is not yet cached, get its position
|
||||
* information and cache it now.
|
||||
* @param aNode the node whose position info we want
|
||||
* @return the position info
|
||||
*/
|
||||
_lazyStoreGet: function(aNode) {
|
||||
let rect = this._nodePositionStore.get(aNode);
|
||||
if (!rect) {
|
||||
rect = aNode.getBoundingClientRect();
|
||||
rect.x = rect.left + rect.width / 2;
|
||||
rect.y = rect.top + rect.height / 2;
|
||||
this._nodePositionStore.set(aNode, rect);
|
||||
}
|
||||
return rect;
|
||||
},
|
||||
|
||||
_firstInRow: function(aNode) {
|
||||
let bound = this._lazyStoreGet(aNode).top;
|
||||
let rv = aNode;
|
||||
let prev;
|
||||
while (rv && (prev = this._getVisibleSiblingForDirection(rv, "previous"))) {
|
||||
if (this._lazyStoreGet(prev).bottom <= bound) {
|
||||
return rv;
|
||||
}
|
||||
rv = prev;
|
||||
}
|
||||
return rv;
|
||||
},
|
||||
|
||||
_getVisibleSiblingForDirection: function(aNode, aDirection) {
|
||||
let rv = aNode;
|
||||
do {
|
||||
rv = rv[aDirection + "Sibling"];
|
||||
} while (rv && rv.getAttribute("hidden") == "true")
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
let DragPositionManager = {
|
||||
start: function(aWindow) {
|
||||
let areas = CustomizableUI.areas.filter((area) => CustomizableUI.getAreaType(area) != "toolbar");
|
||||
areas = areas.map((area) => CustomizableUI.getCustomizeTargetForArea(area, aWindow));
|
||||
areas.push(aWindow.document.getElementById(kPaletteId));
|
||||
for (let areaNode of areas) {
|
||||
let positionManager = gManagers.get(areaNode);
|
||||
if (positionManager) {
|
||||
positionManager.update(areaNode);
|
||||
} else {
|
||||
gManagers.set(areaNode, new AreaPositionManager(areaNode));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
gManagers.clear();
|
||||
},
|
||||
|
||||
getManagerForArea: function(aArea) {
|
||||
return gManagers.get(aArea);
|
||||
}
|
||||
};
|
||||
|
||||
Object.freeze(DragPositionManager);
|
||||
|
@ -23,6 +23,13 @@ let gWideWidgets = new Set();
|
||||
// All the widgets we know of:
|
||||
let gSeenWidgets = new Set();
|
||||
|
||||
// The class by which we recognize wide widgets:
|
||||
const kWidePanelItemClass = "panel-wide-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) {
|
||||
@ -54,7 +61,7 @@ let PanelWideWidgetTracker = {
|
||||
// Furthermore, onWidgetCreated only fires for API-based widgets, not for XUL ones.
|
||||
onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer) {
|
||||
if (!gSeenWidgets.has(aNode.id)) {
|
||||
if (aNode.classList.contains(CustomizableUI.WIDE_PANEL_CLASS)) {
|
||||
if (aNode.classList.contains(kWidePanelItemClass)) {
|
||||
gWideWidgets.add(aNode.id);
|
||||
}
|
||||
gSeenWidgets.add(aNode.id);
|
||||
@ -130,12 +137,12 @@ let PanelWideWidgetTracker = {
|
||||
}
|
||||
}
|
||||
|
||||
if (fixedPos !== null || prevSiblingCount % CustomizableUI.PANEL_COLUMN_COUNT) {
|
||||
if (fixedPos !== null || prevSiblingCount % kColumnsInMenuPanel) {
|
||||
let desiredPos = (fixedPos !== null) ? fixedPos : gPanelPlacements.indexOf(aWidgetId);
|
||||
let desiredChange = -(prevSiblingCount % CustomizableUI.PANEL_COLUMN_COUNT);
|
||||
let desiredChange = -(prevSiblingCount % kColumnsInMenuPanel);
|
||||
if (aMoveForwards && fixedPos == null) {
|
||||
// +1 because otherwise we'd count ourselves:
|
||||
desiredChange = CustomizableUI.PANEL_COLUMN_COUNT + desiredChange + 1;
|
||||
desiredChange = kColumnsInMenuPanel + desiredChange + 1;
|
||||
}
|
||||
desiredPos += desiredChange;
|
||||
CustomizableUI.moveWidgetWithinArea(aWidgetId, desiredPos);
|
||||
|
@ -5,7 +5,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'DragPositionManager.jsm',
|
||||
'ScrollbarSampler.jsm',
|
||||
]
|
||||
|
||||
|
@ -115,21 +115,6 @@ toolbarpaletteitem[mousedown] {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.panel-customization-placeholder,
|
||||
toolbarpaletteitem[place="palette"],
|
||||
toolbarpaletteitem[place="panel"] {
|
||||
transition: background-color, border-color, box-shadow, transform;
|
||||
transition-duration: 10ms, 10ms, 10ms, 250ms;
|
||||
transition-timing-function: linear, linear, linear, ease-in-out;
|
||||
}
|
||||
|
||||
toolbarpaletteitem[notransition][place="palette"],
|
||||
toolbarpaletteitem[notransition][place="panel"] {
|
||||
transition: background-color, border-color, box-shadow;
|
||||
transition-duration: 10ms, 10ms, 10ms;
|
||||
transition-timing-function: linear, linear, linear;
|
||||
}
|
||||
|
||||
toolbarpaletteitem > toolbarbutton > .toolbarbutton-icon {
|
||||
transition: transform 50ms ease-in-out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user