@@ -323,6 +323,22 @@ function RemoteFunctions(config) {
323323 delete element . _originalDragOpacity ;
324324 }
325325
326+ function checkOverlap ( elemWidth , id , classes ) {
327+ if ( elemWidth > 280 ) {
328+ return false ;
329+ }
330+ if ( classes . length >= 3 && elemWidth <= 280 ) {
331+ return true ;
332+ }
333+ if ( ( id || classes . length <= 2 ) && elemWidth <= 250 ) {
334+ return true ;
335+ }
336+ if ( elemWidth <= 180 ) {
337+ return true ;
338+ }
339+ return false ;
340+ }
341+
326342 /**
327343 * This is for the advanced DOM options that appears when a DOM element is clicked
328344 * advanced options like: 'select parent', 'duplicate', 'delete'
@@ -380,10 +396,34 @@ function RemoteFunctions(config) {
380396 const scrollLeft = window . pageXOffset || document . documentElement . scrollLeft ;
381397 const scrollTop = window . pageYOffset || document . documentElement . scrollTop ;
382398
383- const leftPos = elemBounds . right - boxWidth + scrollLeft ;
384- const topPos = ( elemBounds . top - 30 < 0
385- ? elemBounds . top + elemBounds . height + 5
386- : elemBounds . top - 30 ) + scrollTop ;
399+ // get the ID and classes for the element
400+ // we need this to check for overlap issue between the info box and this box
401+ // because when we have classes and ids then the info box tends to stretch in width
402+ const id = this . element . id ;
403+ const classes = this . element . className ? this . element . className . split ( / \s + / ) . filter ( Boolean ) : [ ] ;
404+
405+ const isOverlap = checkOverlap ( elemBounds . width , id , classes ) ;
406+
407+ // default position (right aligned with element)
408+ let leftPos = elemBounds . right - boxWidth + scrollLeft ;
409+
410+ // this will be calculated based on whether we have overlap issue or not
411+ let topPos ;
412+
413+ if ( isOverlap ) {
414+ if ( elemBounds . top > 40 ) { // check if there's enough space at the top
415+ // place at the top
416+ topPos = elemBounds . top - 30 + scrollTop ;
417+ } else {
418+ // at the bottom
419+ topPos = elemBounds . top + elemBounds . height + 5 + scrollTop ;
420+ }
421+ } else {
422+ // no overlap, so it comes just above the element
423+ topPos = ( elemBounds . top - 30 < 0
424+ ? elemBounds . top + elemBounds . height + 5
425+ : elemBounds . top - 30 ) + scrollTop ;
426+ }
387427
388428 // the icons that is displayed in the box
389429 const ICONS = {
@@ -492,8 +532,9 @@ function RemoteFunctions(config) {
492532 } ;
493533
494534 // Node info box to display DOM node ID and classes on hover
495- function NodeInfoBox ( element ) {
535+ function NodeInfoBox ( element , isFromClick ) {
496536 this . element = element ;
537+ this . isFromClick = isFromClick || false ;
497538 this . remove = this . remove . bind ( this ) ;
498539 this . create ( ) ;
499540 }
@@ -545,12 +586,45 @@ function RemoteFunctions(config) {
545586 pushBoxUp += 16 ;
546587 }
547588
548- // Now calculate topPos using the final pushBoxUp value
549- const leftPos = elemBounds . left + scrollLeft ;
550- const topPos = ( elemBounds . top - pushBoxUp < 0
589+ let leftPos = elemBounds . left + scrollLeft ;
590+ let topPos = ( elemBounds . top - pushBoxUp < 0
551591 ? elemBounds . top + elemBounds . height + 5
552592 : elemBounds . top - pushBoxUp ) + scrollTop ;
553593
594+ // we need to check for overlap if this is from a click
595+ if ( this . isFromClick ) {
596+ const isOverlap = checkOverlap ( elemBounds . width , id , classes ) ;
597+
598+ if ( isOverlap ) {
599+ const windowWidth = window . innerWidth ;
600+ const boxWidth = 300 ; // max-width of the box
601+
602+ // Estimate the height of the info box based on its content
603+ // base height for tag name + padding
604+ let estimatedHeight = 20 ;
605+
606+ // height adjustment if ID is present
607+ if ( id ) {
608+ estimatedHeight += 15 ;
609+ }
610+
611+ // height adjustment if classes are present
612+ if ( classes . length > 0 ) {
613+ estimatedHeight += 15 ;
614+ }
615+
616+ // align with the bottom of the info box
617+ topPos = ( elemBounds . top + elemBounds . height - estimatedHeight ) + scrollTop ;
618+
619+ // decide whether position at left or right
620+ if ( elemBounds . left > boxWidth + 10 ) {
621+ leftPos = elemBounds . left - boxWidth - 10 + scrollLeft ;
622+ } else if ( windowWidth - elemBounds . right > boxWidth + 10 ) {
623+ leftPos = elemBounds . right + 10 + scrollLeft ;
624+ }
625+ }
626+ }
627+
554628 const styles = `
555629 .box {
556630 background-color: #4285F4;
@@ -1007,7 +1081,10 @@ function RemoteFunctions(config) {
10071081 if ( _nodeInfoBox ) {
10081082 _nodeInfoBox . remove ( ) ;
10091083 }
1010- _nodeInfoBox = new NodeInfoBox ( event . target ) ;
1084+ // check if this element is already clicked (has more options box)
1085+ // this is needed so that we can check for overlapping issue among the boxes
1086+ const isAlreadyClicked = previouslyClickedElement === event . target && _nodeMoreOptionsBox !== null ;
1087+ _nodeInfoBox = new NodeInfoBox ( event . target , isAlreadyClicked ) ;
10111088 }
10121089 }
10131090 }
@@ -1069,11 +1146,11 @@ function RemoteFunctions(config) {
10691146 if ( _nodeInfoBox ) {
10701147 _nodeInfoBox . remove ( ) ;
10711148 }
1072- _nodeInfoBox = new NodeInfoBox ( event . target ) ;
1149+ _nodeInfoBox = new NodeInfoBox ( event . target , true ) ; // true means that the element was clicked
10731150
10741151 event . target . _originalOutline = event . target . style . outline ;
10751152 event . target . style . outline = "1px solid #4285F4" ;
1076- previouslyClickedElement = event . target ; // add the current element to the previouslyClickedElement
1153+ previouslyClickedElement = event . target ;
10771154 }
10781155 }
10791156
@@ -1175,7 +1252,7 @@ function RemoteFunctions(config) {
11751252
11761253 if ( _nodeInfoBox ) {
11771254 _nodeInfoBox . remove ( ) ;
1178- _nodeInfoBox = new NodeInfoBox ( element ) ;
1255+ _nodeInfoBox = new NodeInfoBox ( element , true ) ; // true means it came from a click
11791256 }
11801257 }
11811258 }
0 commit comments