Revision control
Copy as Markdown
Other Tools
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
<head>
  <meta charset="utf-8" />
  <title>Test for the drop-indicator custom element</title>
  <style>
    :focus {
      outline: 3px blue solid;
    }
    html {
      height: 100%;
    }
    body {
      height: 100%;
      margin: 0;
    }
    .boxes {
      position: relative;
      flex: 1 0 auto;
      padding: 20px;
      border: 1px solid black;
      display: flex;
      flex-wrap: nowrap;
      align-items: start;
      gap: 3px;
    }
    .boxes.stacked {
      flex-direction: column;
    }
    .boxes span {
      padding: 6px;
      background: #ccc;
      border: 1px solid #999;
      cursor: pointer;
    }
    .marker {
      position: absolute;
      display: block;
      width: 100%;
      height: 2px;
      top: 0;
      left: 0;
      background-color: red;
      z-index: 0;
      pointer-events: none;
    }
    .marker.vertical {
      width: 2px;
      height: 100%;
    }
  </style>
  <script>
    /**
     * Partial duplicate of folderPane::_calculateElementPosition().
     */
    function calculateElementPosition(targetElement) {
      const targetRect = targetElement.getBoundingClientRect();
      const targetTop = Math.round(targetRect.top + targetElement.clientTop);
      const targetInline = Math.round(targetRect.left);
      return { targetTop, targetInline };
    }
    function onDragStart(event) {
      event.dataTransfer.dropEffect = "move";
    }
    function onDragOver(event) {
      if (!event.target.closest("[draggable]")) {
        return;
      }
      const element = event.target;
      const indicator = event.target.closest(".boxes").querySelector("img");
      const { targetTop, targetInline } = calculateElementPosition(element);
      indicator.show(targetTop, targetInline);
      moveMarker(event, targetTop, targetInline);
      event.preventDefault();
    }
    function onDrop(event) {
      const indicator = event.target.closest(".boxes").querySelector("img");
      indicator.hide();
    }
    function moveMarker(event, targetTop, targetInline) {
      const marker = event.target.closest(".boxes").querySelector(".marker");
      marker.style.top = `${targetTop}px`;
      marker.style.left = `${targetInline}px`;
    }
    window.addEventListener("DOMContentLoaded", () => {
      document.getElementById("draggableBoxes").addEventListener("dragstart", onDragStart);
      document.getElementById("draggableBoxes").addEventListener("dragover", onDragOver);
      document.getElementById("draggableBoxes").addEventListener("dragend", onDrop);
      document.getElementById("draggableBoxes").addEventListener("drop", onDrop);
      document.getElementById("draggableBoxes1").addEventListener("dragstart", onDragStart);
      document.getElementById("draggableBoxes1").addEventListener("dragover", onDragOver);
      document.getElementById("draggableBoxes1").addEventListener("dragend", onDrop);
      document.getElementById("draggableBoxes1").addEventListener("drop", onDrop);
    });
  </script>
</head>
<body>
  <div id="draggableBoxes" class="boxes">
    <div class="marker vertical"></div>
    <img is="drop-indicator" id="indicator" />
    <span id="box1" draggable="true">Box 1</span>
    <span id="box2" draggable="true">Box 2</span>
    <span id="box3" draggable="true">Box 3</span>
    <span id="box4" draggable="true">Box 4</span>
  </div>
  <div id="draggableBoxes1" class="boxes stacked">
    <div class="marker"></div>
    <img is="drop-indicator" id="indicator1" horizontal="horizontal" />
    <span id="boxStacked1" draggable="true">Box Stacked 1</span>
    <span id="boxStacked2" draggable="true">Box Stacked 2</span>
    <span id="boxStacked3" draggable="true">Box Stacked 3</span>
    <span id="boxStacked4" draggable="true">Box Stacked 4</span>
  </div>
</body>
</html>