@@ -323,6 +323,157 @@ function RemoteFunctions(config) {
323323 delete element . _originalDragOpacity ;
324324 }
325325
326+ // CSS class name for drop markers
327+ let DROP_MARKER_CLASSNAME = "__brackets-drop-marker" ;
328+
329+ /**
330+ * This function creates a marker to indicate a valid drop position
331+ * @param {DOMElement } element - The element where the drop is possible
332+ */
333+ function _createDropMarker ( element ) {
334+ // clean any existing marker from that element
335+ _removeDropMarkerFromElement ( element ) ;
336+
337+ // create the marker element
338+ let marker = window . document . createElement ( "div" ) ;
339+ marker . className = DROP_MARKER_CLASSNAME ;
340+
341+ // position the marker at the top of the element
342+ let rect = element . getBoundingClientRect ( ) ;
343+ let scrollTop = window . pageYOffset || document . documentElement . scrollTop ;
344+ let scrollLeft = window . pageXOffset || document . documentElement . scrollLeft ;
345+
346+ // marker styling
347+ marker . style . position = "absolute" ;
348+ marker . style . top = ( rect . top + scrollTop - 5 ) + "px" ;
349+ marker . style . left = ( rect . left + scrollLeft ) + "px" ;
350+ marker . style . width = rect . width + "px" ;
351+ marker . style . height = "2px" ;
352+ marker . style . backgroundColor = "#4285F4" ;
353+ marker . style . zIndex = "2147483646" ;
354+
355+ element . _dropMarker = marker ; // we need this in the _removeDropMarkerFromElement function
356+ window . document . body . appendChild ( marker ) ;
357+ }
358+
359+ /**
360+ * This function removes a drop marker from a specific element
361+ * @param {DOMElement } element - The element to remove the marker from
362+ */
363+ function _removeDropMarkerFromElement ( element ) {
364+ if ( element . _dropMarker && element . _dropMarker . parentNode ) {
365+ element . _dropMarker . parentNode . removeChild ( element . _dropMarker ) ;
366+ delete element . _dropMarker ;
367+ }
368+ }
369+
370+ /**
371+ * this function is to clear all the drop markers from the document
372+ */
373+ function _clearDropMarkers ( ) {
374+ let markers = window . document . querySelectorAll ( "." + DROP_MARKER_CLASSNAME ) ;
375+ for ( let i = 0 ; i < markers . length ; i ++ ) {
376+ if ( markers [ i ] . parentNode ) {
377+ markers [ i ] . parentNode . removeChild ( markers [ i ] ) ;
378+ }
379+ }
380+
381+ // Also clear any element references
382+ let elements = window . document . querySelectorAll ( "[data-brackets-id]" ) ;
383+ for ( let j = 0 ; j < elements . length ; j ++ ) {
384+ delete elements [ j ] . _dropMarker ;
385+ }
386+ }
387+
388+ /**
389+ * Handle dragover events on the document
390+ * Shows drop markers on valid drop targets
391+ * @param {Event } event - The dragover event
392+ */
393+ function onDragOver ( event ) {
394+ // we set this on dragStart
395+ if ( ! window . _currentDraggedElement ) {
396+ return ;
397+ }
398+
399+ event . preventDefault ( ) ;
400+
401+ // get the element under the cursor
402+ let target = document . elementFromPoint ( event . clientX , event . clientY ) ;
403+ if ( ! target || target === window . _currentDraggedElement ) {
404+ return ;
405+ }
406+
407+ // get the closest element with a data-brackets-id
408+ while ( target && ! target . hasAttribute ( "data-brackets-id" ) ) {
409+ target = target . parentElement ;
410+ }
411+
412+ // skip if no valid target found or if it's the dragged element
413+ if ( ! target || target === window . _currentDraggedElement ) {
414+ return ;
415+ }
416+
417+ // Skip BODY and HTML tags
418+ if ( target . tagName === "BODY" || target . tagName === "HTML" ) {
419+ return ;
420+ }
421+
422+ // before creating a drop marker, make sure that we clear all the drop markers
423+ _clearDropMarkers ( ) ;
424+ _createDropMarker ( target ) ;
425+ }
426+
427+ /**
428+ * Handle drop events on the document
429+ * Processes the drop of a dragged element onto a valid target
430+ * @param {Event } event - The drop event
431+ */
432+ function onDrop ( event ) {
433+ if ( ! window . _currentDraggedElement ) {
434+ return ;
435+ }
436+
437+ event . preventDefault ( ) ;
438+ event . stopPropagation ( ) ;
439+
440+ // get the element under the cursor
441+ let target = document . elementFromPoint ( event . clientX , event . clientY ) ;
442+
443+ // get the closest element with a data-brackets-id
444+ while ( target && ! target . hasAttribute ( "data-brackets-id" ) ) {
445+ target = target . parentElement ;
446+ }
447+
448+ // skip if no valid target found or if it's the dragged element
449+ if ( ! target || target === window . _currentDraggedElement ) {
450+ return ;
451+ }
452+
453+ // Skip BODY and HTML tags
454+ if ( target . tagName === "BODY" || target . tagName === "HTML" ) {
455+ return ;
456+ }
457+
458+ // IDs of the source and target elements
459+ const sourceId = window . _currentDraggedElement . getAttribute ( "data-brackets-id" ) ;
460+ const targetId = target . getAttribute ( "data-brackets-id" ) ;
461+
462+ // send message to the editor
463+ window . _Brackets_MessageBroker . send ( {
464+ livePreviewEditEnabled : true ,
465+ sourceElement : window . _currentDraggedElement ,
466+ targetElement : target ,
467+ sourceId : Number ( sourceId ) ,
468+ targetId : Number ( targetId ) ,
469+ move : true
470+ } ) ;
471+
472+ _clearDropMarkers ( ) ;
473+ _dragEndChores ( window . _currentDraggedElement ) ;
474+ delete window . _currentDraggedElement ;
475+ }
476+
326477 /**
327478 * This function is to calculate the width of the info box based on the number of chars in the box
328479 * @param {String } tagName - the element's tag name
@@ -406,26 +557,16 @@ function RemoteFunctions(config) {
406557 event . stopPropagation ( ) ;
407558 event . dataTransfer . setData ( "text/plain" , this . element . getAttribute ( "data-brackets-id" ) ) ;
408559 _dragStartChores ( this . element ) ;
409- console . log ( "pluto- dragstart: " , this . element . getAttribute ( "data-brackets-id" ) ) ;
410- } ) ;
411-
412- this . element . addEventListener ( "dragover" , ( event ) => {
413- event . preventDefault ( ) ;
414- event . stopPropagation ( ) ;
415- console . log ( "pluto- dragover" ) ;
560+ _clearDropMarkers ( ) ;
561+ window . _currentDraggedElement = this . element ;
416562 } ) ;
417563
418564 this . element . addEventListener ( "dragend" , ( event ) => {
419565 event . preventDefault ( ) ;
420566 event . stopPropagation ( ) ;
421567 _dragEndChores ( this . element ) ;
422- console . log ( "pluto- dragend" ) ;
423- } ) ;
424-
425- this . element . addEventListener ( "drop" , ( event ) => {
426- event . preventDefault ( ) ;
427- event . stopPropagation ( ) ;
428- console . log ( "pluto- drop" ) ;
568+ _clearDropMarkers ( ) ;
569+ delete window . _currentDraggedElement ;
429570 } ) ;
430571 } ,
431572
@@ -1778,6 +1919,8 @@ function RemoteFunctions(config) {
17781919 window . document . addEventListener ( "mouseover" , onElementHover ) ;
17791920 window . document . addEventListener ( "mouseout" , onElementHoverOut ) ;
17801921 window . document . addEventListener ( "click" , onClick ) ;
1922+ window . document . addEventListener ( "dragover" , onDragOver ) ;
1923+ window . document . addEventListener ( "drop" , onDrop ) ;
17811924
17821925 if ( experimental ) {
17831926 window . document . addEventListener ( "keydown" , onKeyDown ) ;
0 commit comments