{+ self.title +}
{+ self.description +}
diff --git a/slhx-js/runtime/slhx.js b/slhx-js/runtime/slhx.js index 8041874..287b97e 100644 --- a/slhx-js/runtime/slhx.js +++ b/slhx-js/runtime/slhx.js @@ -10,6 +10,7 @@ const timers = new WeakMap(); const sseSources = new WeakMap(); const atomStores = new WeakMap(); + const dragKeys = new WeakMap(); function roots() { return Array.from(document.querySelectorAll(`[${ROOT}]`)); @@ -51,11 +52,13 @@ } } - function formDataFor(el) { + function formDataFor(el, eventName) { const form = el.tagName === "FORM" ? el : el.closest("form"); const data = form ? new FormData(form) : new FormData(); const id = handleId(el) || (form && handleId(form)); if (id && !data.has("__h")) data.set("__h", id); + const dragKey = eventName === "drop" && dragKeys.get(rootOf(el)); + if (dragKey && !data.has("work_id")) data.set("work_id", dragKey); for (const { name, value } of Array.from(el.attributes || [])) { if (name.startsWith("data-") && !name.startsWith("data-slhx-") && name !== HID && name !== SID) { data.set(name.slice(5).replace(/-/g, "_"), value); @@ -85,7 +88,7 @@ async function send(el, eventName) { if (el.getAttribute("data-slhx-confirm") && !confirm(el.getAttribute("data-slhx-confirm"))) return; - const { form, data, multipart } = formDataFor(el); + const { form, data, multipart } = formDataFor(el, eventName); const target = form || el; const policy = requestPolicy(target, eventName); const active = pending.get(target); @@ -386,8 +389,21 @@ } function bindRoot(root) { - ["click", "submit", "input", "change"].forEach((name) => { + ["click", "submit", "input", "change", "dragstart", "dragover", "drop"].forEach((name) => { root.addEventListener(name, (event) => { + if (name === "dragstart") { + const item = closestInRoot(event.target, root, "[data-key]"); + if (item) { + dragKeys.set(root, item.getAttribute("data-key")); + if (event.dataTransfer) event.dataTransfer.setData("text/plain", item.getAttribute("data-key")); + } + return; + } + if (name === "dragover") { + const drop = closestInRoot(event.target, root, `[${HID}][data-slhx-on="drop"]`); + if (drop) event.preventDefault(); + return; + } const nav = closestInRoot(event.target, root, "a[data-slhx-nav], [data-slhx-boost] a[href]"); if (name === "click" && nav && sameOriginNav(event, nav)) { event.preventDefault(); diff --git a/slhx-js/tests/runtime.rs b/slhx-js/tests/runtime.rs index a9eae39..8ada1d5 100644 --- a/slhx-js/tests/runtime.rs +++ b/slhx-js/tests/runtime.rs @@ -27,6 +27,18 @@ fn runtime_clicking_submitter_schedules_form_submit() { assert!(source.contains("schedule(form, \"submit\")")); } +#[test] +fn runtime_supports_drag_drop_params_without_user_js() { + // req: htmx_equivalents/002, req: dx/008 + let source = slhx_js::RUNTIME_JS; + + assert!(source.contains("const dragKeys = new WeakMap()")); + assert!(source.contains("dragstart")); + assert!(source.contains("dragover")); + assert!(source.contains("eventName === \"drop\"")); + assert!(source.contains("data.set(\"work_id\", dragKey)")); +} + #[test] fn runtime_supports_queued_request_policy() { let source = slhx_js::RUNTIME_JS;