@@ -595,6 +595,12 @@ function RemoteFunctions(config = {}) {
595595 * @returns {Boolean } true if the nesting is valid
596596 */
597597 function _isValidNesting ( sourceElement , targetElement ) {
598+ if ( ! sourceElement || ! targetElement ) {
599+ return false ;
600+ }
601+ if ( ! sourceElement . tagName || ! targetElement . tagName ) {
602+ return false ;
603+ }
598604 const sourceTag = sourceElement . tagName . toUpperCase ( ) ;
599605 const targetTag = targetElement . tagName . toUpperCase ( ) ;
600606
@@ -1110,44 +1116,69 @@ function RemoteFunctions(config = {}) {
11101116
11111117 /**
11121118 * this function is for finding the best target element on where to drop the dragged element
1113- * for ex: div > image...here both the div and image are of the exact same size, then when user is dragging some
1114- * other element, then almost everytime they want to drop it before/after the div and not like div>newEle+img
11151119 * @param {Element } target - The current target element
1116- * @returns {Element|null } - The outermost parent with all edges aligned, or null
1120+ * @returns {Element } - The outermost parent with all edges aligned
11171121 */
1118- function _findBestParentTarget ( target ) {
1119- if ( ! target ) {
1120- return null ;
1122+ function _findBestParentTarget ( target , sourceElement ) {
1123+ if ( ! target ) { return null ; }
1124+
1125+ let el = target ;
1126+
1127+ const SEMANTIC_CONTAINERS = new Set ( [
1128+ "DIV" , "SECTION" , "ARTICLE" , "ASIDE" , "MAIN" ,
1129+ "HEADER" , "FOOTER" , "NAV" ,
1130+ "UL" , "OL" , "LI"
1131+ ] ) ;
1132+
1133+ function isSemanticContainer ( element ) {
1134+ return element &&
1135+ element . nodeType === 1 &&
1136+ SEMANTIC_CONTAINERS . has ( element . tagName ) ;
11211137 }
11221138
1123- const tolerance = 1 ; // 1px is considered same
1124- let bestParent = null ;
1125- let currentElement = target ;
1126- let parent = currentElement . parentElement ;
1139+ function geometrySuggestsUpgrade ( child , parent ) {
1140+ const tolerance = 2 ;
1141+ const c = child . getBoundingClientRect ( ) ;
1142+ const p = parent . getBoundingClientRect ( ) ;
11271143
1128- while ( parent ) {
1129- if ( parent . hasAttribute ( GLOBALS . DATA_BRACKETS_ID_ATTR ) && isElementEditable ( parent ) ) {
1130- const currentRect = currentElement . getBoundingClientRect ( ) ;
1131- const parentRect = parent . getBoundingClientRect ( ) ;
1144+ const topAligned = Math . abs ( c . top - p . top ) <= tolerance ;
1145+ const bottomAligned = Math . abs ( c . bottom - p . bottom ) <= tolerance ;
11321146
1133- // check if all the edges are same
1134- const topAligned = Math . abs ( currentRect . top - parentRect . top ) <= tolerance ;
1135- const bottomAligned = Math . abs ( currentRect . bottom - parentRect . bottom ) <= tolerance ;
1136- const leftAligned = Math . abs ( currentRect . left - parentRect . left ) <= tolerance ;
1137- const rightAligned = Math . abs ( currentRect . right - parentRect . right ) <= tolerance ;
1147+ const fullyInside =
1148+ c . top >= p . top && c . bottom <= p . bottom &&
1149+ c . left >= p . left && c . right <= p . right ;
11381150
1139- if ( topAligned && bottomAligned && leftAligned && rightAligned ) {
1140- // all edges match, we prefer the parent element
1141- bestParent = parent ;
1142- currentElement = parent ;
1143- } else {
1144- break ;
1151+ return topAligned || bottomAligned || fullyInside ;
1152+ }
1153+
1154+ while ( el && el !== document . body ) {
1155+ const parent = el . parentElement ;
1156+
1157+ // hit element is semantic container
1158+ if ( isSemanticContainer ( el ) ) {
1159+ return el ;
1160+ }
1161+
1162+ // child is valid sibling → allow
1163+ if (
1164+ parent &&
1165+ _isValidNesting ( sourceElement , parent ) &&
1166+ _canAcceptChildren ( parent )
1167+ ) {
1168+ return el ;
1169+ }
1170+
1171+ // climb if parent is semantic and geometry suggests it
1172+ if ( parent && isSemanticContainer ( parent ) ) {
1173+ if ( geometrySuggestsUpgrade ( el , parent ) ) {
1174+ return parent ;
11451175 }
11461176 }
1147- parent = parent . parentElement ;
1177+
1178+ el = parent ;
11481179 }
11491180
1150- return bestParent ;
1181+ return null ;
11511182 }
11521183
11531184 /**
@@ -1197,7 +1228,7 @@ function RemoteFunctions(config = {}) {
11971228 }
11981229
11991230 /**
1200- * Handle dragover events on the document (throttled version)
1231+ * Handle dragover events on the document
12011232 * Shows drop markers on valid drop targets
12021233 * @param {Event } event - The dragover event
12031234 */
@@ -1229,7 +1260,7 @@ function RemoteFunctions(config = {}) {
12291260 }
12301261
12311262 // Check if we should prefer a parent when all edges are aligned
1232- const bestParent = _findBestParentTarget ( target ) ;
1263+ const bestParent = _findBestParentTarget ( target , window . _currentDraggedElement ) ;
12331264 if ( bestParent ) {
12341265 target = bestParent ;
12351266 }
@@ -1306,7 +1337,7 @@ function RemoteFunctions(config = {}) {
13061337 }
13071338
13081339 // Check if we should prefer a parent when all edges are aligned
1309- const bestParent = _findBestParentTarget ( target ) ;
1340+ const bestParent = _findBestParentTarget ( target , window . _currentDraggedElement ) ;
13101341 if ( bestParent ) {
13111342 target = bestParent ;
13121343 }
0 commit comments