[FIX] web: improve useSortable when no placeholder is not a clone

Sortable uses the "enter" and "leave" events to handle the move of the
placeholder in the container. When the initial drag element is cloned,
the algorithm is more simple as the placeholder takes the same size as
the original one. When we use a custom placeholder (in our case, a small
line) and the placeholder change position, it triggers an "enter" and
"leave" events in loop due to the smaller size of the placeholder.

This commit ensures the placeholder to move only one time per pointer
event move ("enter" and "leave") and avoid flickering when we move one
element on the first/last element.

Note: a better solution to avoid this complexity is to use pointer
"move" event instead of "enter" and "leave".

closes odoo/odoo#138350

Signed-off-by: Adrien Dieudonné (adr) <adr@odoo.com>
This commit is contained in:
Romeo Fragomeli
2023-10-12 13:16:48 +00:00
parent 0463551083
commit b49a5d1b01
+28 -5
View File
@@ -141,6 +141,9 @@ const hookParams = {
};
const onElementComplexPointerEnter = (ev) => {
if (ctx.haveAlreadyChanged) {
return;
}
const element = ev.currentTarget;
const siblingArray = [...element.parentElement.children].filter(
@@ -160,14 +163,18 @@ const hookParams = {
if (isDirectSibling) {
if (pos === Node.DOCUMENT_POSITION_PRECEDING) {
element.before(current.placeHolder);
ctx.haveAlreadyChanged = true;
} else if (pos === Node.DOCUMENT_POSITION_FOLLOWING) {
element.after(current.placeHolder);
ctx.haveAlreadyChanged = true;
}
} else {
if (pos === Node.DOCUMENT_POSITION_FOLLOWING) {
element.before(current.placeHolder);
ctx.haveAlreadyChanged = true;
} else if (pos === Node.DOCUMENT_POSITION_PRECEDING) {
element.after(current.placeHolder);
ctx.haveAlreadyChanged = true;
}
}
}
@@ -179,21 +186,34 @@ const hookParams = {
* @param {PointerEvent} ev
*/
const onElementComplexPointerLeave = (ev) => {
if (ctx.haveAlreadyChanged) {
return;
}
const element = ev.currentTarget;
const elementRect = element.getBoundingClientRect();
const relatedElement = ev.relatedTarget;
const relatedElementRect = element.getBoundingClientRect();
const siblingArray = [...element.parentElement.children].filter(
(el) =>
el === current.placeHolder ||
(el.matches(elementSelector) && !el.classList.contains(DRAGGED_CLASS))
);
const pointerOnSiblings = siblingArray.indexOf(relatedElement) > -1;
const elementIndex = siblingArray.indexOf(element);
const isAtEdge = elementIndex === 0 || elementIndex === siblingArray.length - 1;
if (isAtEdge && (!groupSelector || current.group === element.closest(groupSelector))) {
const pos = current.placeHolder.compareDocumentPosition(element);
if (pos === Node.DOCUMENT_POSITION_PRECEDING) {
const isFirst = elementIndex === 0;
const isAbove = relatedElementRect.top <= elementRect.top;
const isLast = elementIndex === siblingArray.length - 1;
const isBelow = relatedElementRect.bottom >= elementRect.bottom;
const pos = current.placeHolder.compareDocumentPosition(element);
if (!pointerOnSiblings) {
if (isFirst && isAbove && pos === Node.DOCUMENT_POSITION_PRECEDING) {
element.before(current.placeHolder);
} else if (pos === Node.DOCUMENT_POSITION_FOLLOWING) {
ctx.haveAlreadyChanged = true;
} else if (isLast && isBelow && pos === Node.DOCUMENT_POSITION_FOLLOWING) {
element.after(current.placeHolder);
ctx.haveAlreadyChanged = true;
}
}
callHandler("onElementLeave", { element });
@@ -258,6 +278,9 @@ const hookParams = {
return pick(current, "element", "group");
},
onDrag({ ctx }) {
ctx.haveAlreadyChanged = false;
},
onDragEnd({ ctx }) {
return pick(ctx.current, "element", "group");
},