function createDialogDrag({ environment }) { const { document, window } = environment; const panels = ".opportunities-extension-action-form-dialog, .opportunities-extension-preferences-dialog, .opportunities-extension-account-plans-dialog, .oe-org-confirm-panel"; const positions = new WeakMap(); let installed = false, drag = null; function move(panel, dx, dy) { const rect = panel.getBoundingClientRect(); const viewport = window.visualViewport; const left = viewport?.offsetLeft || 0, top = viewport?.offsetTop || 0; const width = viewport?.width || document.documentElement.clientWidth; const height = viewport?.height || document.documentElement.clientHeight; const x = Math.max(left - rect.width * 0.7, Math.min(rect.left + dx, left + width - rect.width * 0.3)); const y = Math.max(top - rect.height * 0.7, Math.min(rect.top + dy, top + height - rect.height * 0.3)); const previous = positions.get(panel) || { x: 0, y: 0 }; const next = { x: previous.x + x - rect.left, y: previous.y + y - rect.top }; positions.set(panel, next); panel.style.position = "relative"; panel.style.left = `${next.x}px`; panel.style.top = `${next.y}px`; panel.setAttribute("data-dialog-moved", "true"); } function stop() { if (!drag) return; const previous = drag; drag = null; previous.panel.removeAttribute("data-dialog-dragging"); if (previous.title.hasPointerCapture?.(previous.id)) previous.title.releasePointerCapture(previous.id); } function install() { if (installed || window.__opportunitiesDialogDragInstalled || !document.addEventListener || !window.addEventListener) return; installed = true; window.__opportunitiesDialogDragInstalled = true; document.addEventListener("pointerdown", event => { if (event.button !== 0 || event.isPrimary === false) return; const title = event.target.closest?.("header, h2, h3"); const panel = title?.closest(panels); if (!panel || !panel.closest(".opportunities-extension-modal") || panel.closest("[inert], [hidden]") || event.target.closest("button, a, input, select, textarea, [role='button'], [contenteditable='true']")) return; // Accept the whole title bar, but not headers inside the dialog's content. const heading = panel.querySelector("h2, h3"); if (!heading || (heading !== title && !title.contains(heading))) return; const rect = panel.getBoundingClientRect(); if (rect.width >= document.documentElement.clientWidth - 2 && rect.height >= document.documentElement.clientHeight - 2) return; stop(); event.preventDefault(); drag = { title, panel, id: event.pointerId, x: event.clientX, y: event.clientY }; panel.setAttribute("data-dialog-dragging", "true"); title.setPointerCapture?.(event.pointerId); }); document.addEventListener("pointermove", event => { if (!drag || event.pointerId !== drag.id) return; if (!drag.panel.isConnected || drag.panel.closest("[hidden], [inert]")) { stop(); return; } event.preventDefault(); move(drag.panel, event.clientX - drag.x, event.clientY - drag.y); drag.x = event.clientX; drag.y = event.clientY; }); for (const name of ["pointerup", "pointercancel", "lostpointercapture"]) { document.addEventListener(name, event => { if (drag?.id === event.pointerId) stop(); }); } window.addEventListener("blur", stop); function resize() { stop(); for (const panel of document.querySelectorAll('[data-dialog-moved="true"]')) { if (panel.getClientRects().length) move(panel, 0, 0); } } window.addEventListener("resize", resize); window.visualViewport?.addEventListener("resize", resize); } return { install }; }