The bug show case - http://codepen.io/tedbeer/pen/MwXEZg
It happens when a drop zone inside another drop zone is bigger than the parent.
DnD manager looks for a drop target and selectы the smallest. It does not take into account that a child node can be bigger than a parent node.
I propose changing the algorithm a bit:
- find all targets intersecting with the drag source
- from related targets (parent-child-descendant) leave the deepest (descendants) only
- among remaining targets choose the target with the biggest intersection
The pen using patched amplesdk - http://codepen.io/tedbeer/pen/KpeBBz
Here the patch implementing the algorithm and solving the problem:
--- /amplesdk3/ample/runtime/managers/DragAndDropManager.js+++ /ample-patched/ample/runtime/managers/DragAndDropManager.js@@ -242,10 +242,19 @@
// fill in array with drag targets
var aElements = fElement_getElementsByTagName(oBrowser_modalNode || this.documentElement, '*');
- for (var nIndex = 0, nLength = aElements.length; nIndex < nLength; nIndex++)- if (aElements[nIndex].$droppable)- aDragAndDropManager_dropTargets.push(aElements[nIndex]);-+ for (var oRect2, nArea, nIndex = 0, nLength = aElements.length; nIndex < nLength; nIndex++)+ if (aElements[nIndex].$droppable) {+ oRect2 = fElement_getBoundingClientRect(aElements[nIndex]);+ nArea = (oRect2.right - oRect2.left) * (oRect2.bottom - oRect2.top);+ //skip invisible+ if (nArea > 0)+ aDragAndDropManager_dropTargets.push({+ elm: aElements[nIndex],+ rect: oRect2,+ area: nArea,+ intersection: 0+ });+ }
//
nDragAndDropManager_dragState = nDragAndDropManager_STATE_DRAGGED;
@@ -274,41 +283,32 @@
nDragAndDropManager_scrollTop = oScroll.top;
}
- var oDropTarget = null,- oRect2,- nAreaSource =(oRect.right - oRect.left) * (oRect.bottom - oRect.top),- nAreaTarget,- nAreaTargetMin = nInfinity,- nIntersection,- nPartialMax = 0;-- for (var nIndex = 0, nLength = aDragAndDropManager_dropTargets.length; nIndex < nLength; nIndex++) {- // if source is the target, continue- if (aDragAndDropManager_dropTargets[nIndex] == oDragAndDropManager_dragSource)- continue;-- // if target contains source, continue- if (fNode_compareDocumentPosition(aDragAndDropManager_dropTargets[nIndex], oDragAndDropManager_dragSource) & 8 /* cNode.DOCUMENT_POSITION_CONTAINS */)- continue;-- oRect2 = fElement_getBoundingClientRect(aDragAndDropManager_dropTargets[nIndex]);- nAreaTarget =(oRect2.right - oRect2.left) * (oRect2.bottom - oRect2.top);- nIntersection = fDragAndDropManager_intersectRectangle(oRect, oRect2);- if (nIntersection < nAreaSource) {- // partial intersection- if (nIntersection > nPartialMax) {- nPartialMax = nIntersection;- oDropTarget = aDragAndDropManager_dropTargets[nIndex];- }- }- else {- // complete intersection- if (nAreaTarget < nAreaTargetMin) {- nAreaTargetMin = nAreaTarget;- oDropTarget = aDragAndDropManager_dropTargets[nIndex];+ var aCandidates = aDragAndDropManager_dropTargets.filter(function(one) {+ if (one.area === 0 || one.elm == oDragAndDropManager_dragSource ||+ fNode_compareDocumentPosition(one.elm, oDragAndDropManager_dragSource) & 8)+ return false;+ one.intersection = fDragAndDropManager_intersectRectangle(oRect, one.rect);+ return one.intersection > 0;+ });+ var oElm, rel, oldLen = 0;+ //filter out related candidates (leave the deepest)+ while(aCandidates.length > 1 && oldLen !== aCandidates.length) {+ oElm = aCandidates[0].elm;+ oldLen = aCandidates.length; //to break the loop if no changes in the candidates array+ for (var ind = aCandidates.length - 1; ind > 0; ind--) {+ rel = fNode_compareDocumentPosition(oElm, aCandidates[ind].elm);+ if (rel & 8) {+ aCandidates.splice(ind, 1);+ } else if (rel & 16) {+ aCandidates.splice(0, 1);+ break;
}
}
}
+ //find maximum intersection among candidates+ var oDropTarget = aCandidates.reduce(function(prev, cand) {+ return cand.intersection > prev.intersection ? cand : prev;+ }, {intersection: 0}).elm;
// if there was a drop target and it is different from a new one
if (oDragAndDropManager_dropTarget) {
The bug show case - http://codepen.io/tedbeer/pen/MwXEZg
It happens when a drop zone inside another drop zone is bigger than the parent.
DnD manager looks for a drop target and selectы the smallest. It does not take into account that a child node can be bigger than a parent node.
I propose changing the algorithm a bit:
The pen using patched amplesdk - http://codepen.io/tedbeer/pen/KpeBBz
Here the patch implementing the algorithm and solving the problem: