diff --git a/app/javascript/application.js b/app/javascript/application.js index 8680aae..54a9026 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -2,12 +2,15 @@ // https://github.com/rails/importmap-rails import "@hotwired/turbo-rails" + +/* Hide page before loaded for testing purposes */ function showPage(event) { document.documentElement.style.visibility="visible" } document.addEventListener('turbo:load', showPage) +/* Turbo stream actions */ Turbo.StreamElement.prototype.enableElement = function(element) { element.removeAttribute("disabled") element.removeAttribute("aria-disabled") @@ -15,7 +18,6 @@ Turbo.StreamElement.prototype.enableElement = function(element) { element.removeAttribute("tabindex") } - Turbo.StreamActions.disable = function() { this.targetElements.forEach((e) => { e.setAttribute("disabled", "disabled") @@ -51,3 +53,89 @@ Turbo.StreamActions.close_form = function() { e.remove() }) } + + +/* Items table drag and drop support */ +function processKey(event) { + if (event.key == "Escape") { + event.currentTarget.querySelector("a[name=cancel]").click(); + } +} +window.processKey = processKey; + +var lastEnterTime; +function dragStart(event) { + lastEnterTime = event.timeStamp; + var row = event.currentTarget; + row.closest("table").querySelectorAll("thead tr").forEach((tr) => { + tr.toggleAttribute("hidden"); + }); + event.dataTransfer.setData("text/plain", row.getAttribute("data-drag-path")); + var rowRectangle = row.getBoundingClientRect(); + event.dataTransfer.setDragImage(row, event.x - rowRectangle.left, event.y - rowRectangle.top); + event.dataTransfer.dropEffect = "move"; +} +window.dragStart = dragStart; + +/* +* Drag tracking assumptions (based on FF 122.0 experience): +* * Enter/Leave events at the same timeStamp may not be logically ordered +* (e.g. E -> E -> L, not E -> L -> E), +* * not every Enter event has corresponding Leave event, especially during +* rapid pointer moves +* NOTE: sometimes Leave is not emitted when pointer goes fast over table +* and outside. This should probably be fixed in browser, than patched here. +*/ +function dragEnter(event) { + //console.log(event.timeStamp + " " + event.type + ": " + event.currentTarget.id); + dragLeave(event); + lastEnterTime = event.timeStamp; + const id = event.currentTarget.getAttribute("data-drop-id"); + document.getElementById(id).classList.add("dropzone"); +} +window.dragEnter = dragEnter; + +function dragOver(event) { + event.preventDefault(); +} +window.dragOver = dragOver; + +function dragLeave(event) { + //console.log(event.timeStamp + " " + event.type + ": " + event.currentTarget.id); + // Leave has been accounted for by Enter at the same timestamp, processed earlier + if (event.timeStamp <= lastEnterTime) return; + event.currentTarget.closest("table").querySelectorAll(".dropzone").forEach((tr) => { + tr.classList.remove("dropzone"); + }) +} +window.dragLeave = dragLeave; + +function dragEnd(event) { + dragLeave(event); + event.currentTarget.closest("table").querySelectorAll("thead tr").forEach((tr) => { + tr.toggleAttribute("hidden"); + }); +} +window.dragEnd = dragEnd; + +function drop(event) { + event.preventDefault(); + + var params = new URLSearchParams(); + var id_param = event.currentTarget.getAttribute("data-drop-id-param"); + var id = event.currentTarget.getAttribute("data-drop-id").split("_").pop(); + params.append(id_param, id); + + fetch(event.dataTransfer.getData("text/plain"), { + body: params, + headers: { + "Accept": "text/vnd.turbo-stream.html", + "X-CSRF-Token": document.head.querySelector("meta[name=csrf-token]").content, + "X-Requested-With": "XMLHttpRequest" + }, + method: "POST" + }) + .then(response => response.text()) + .then(html => Turbo.renderStreamMessage(html)) +} +window.drop = drop; diff --git a/app/views/quantities/_quantity.html.erb b/app/views/quantities/_quantity.html.erb index bd6a394..1ee0efa 100644 --- a/app/views/quantities/_quantity.html.erb +++ b/app/views/quantities/_quantity.html.erb @@ -1,9 +1,10 @@ <%= tag.tr id: dom_id(quantity), - ondragstart: 'dragStart(event)', ondragend: 'dragEnd(event)', - ondragover: 'dragOver(event)', ondrop: 'drop(event)', - ondragenter: 'dragEnter(event)', ondragleave: 'dragLeave(event)', - data: {drag_path: rebase_quantity_path(quantity), - drop_id: dom_id(quantity.parent || quantity)} do %> + ondragstart: "dragStart(event)", ondragend: "dragEnd(event)", + ondragover: "dragOver(event)", ondrop: "drop(event)", + ondragenter: "dragEnter(event)", ondragleave: "dragLeave(event)", + data: {drag_path: reparent_quantity_path(quantity), + drop_id: dom_id(quantity.parent || quantity), + drop_id_param: "quantity[parent_id]"} do %> <%= link_to quantity, edit_quantity_path(quantity), onclick: 'this.blur();', diff --git a/app/views/quantities/index.html.erb b/app/views/quantities/index.html.erb index 1ae631d..6b0d909 100644 --- a/app/views/quantities/index.html.erb +++ b/app/views/quantities/index.html.erb @@ -19,10 +19,10 @@ <% end %> - <%= tag.tr id: 'quantity_', hidden: true, - ondragover: 'dragOver(event)', ondrop: 'drop(event)', - ondragenter: 'dragEnter(event)', ondragleave: 'dragLeave(event)', - data: {drop_id: 'quantity_'} do %> + <%= tag.tr id: "quantity_", hidden: true, + ondragover: "dragOver(event)", ondrop: "drop(event)", + ondragenter: "dragEnter(event)", ondragleave: "dragLeave(event)", + data: {drop_id: "quantity_", drop_id_param: "quantity[parent_id]"} do %> <%= t '.top_level_drop' %> <% end %> @@ -30,81 +30,3 @@ <%= render(@quantities) || render_no_items %> - -<%= javascript_tag do %> - function processKey(event) { - if (event.key == "Escape") { - event.currentTarget.querySelector("a[name=cancel]").click(); - } - } - - var lastEnterTime; - function dragStart(event) { - lastEnterTime = event.timeStamp; - var row = event.currentTarget; - row.closest("table").querySelectorAll("thead tr").forEach((tr) => { - tr.toggleAttribute("hidden"); - }); - event.dataTransfer.setData("text/plain", row.getAttribute("data-drag-path")); - var rowRectangle = row.getBoundingClientRect(); - event.dataTransfer.setDragImage(row, event.x - rowRectangle.left, event.y - rowRectangle.top); - event.dataTransfer.dropEffect = "move"; - } - - /* - * Drag tracking assumptions (based on FF 122.0 experience): - * * Enter/Leave events at the same timeStamp may not be logically ordered - * (e.g. E -> E -> L, not E -> L -> E), - * * not every Enter event has corresponding Leave event, especially during - * rapid pointer moves - * NOTE: sometimes Leave is not emitted when pointer goes fast over table - * and outside. This should probably be fixed in browser, than patched here. - */ - function dragEnter(event) { - //console.log(event.timeStamp + " " + event.type + ": " + event.currentTarget.id); - dragLeave(event); - lastEnterTime = event.timeStamp; - const id = event.currentTarget.getAttribute("data-drop-id"); - document.getElementById(id).classList.add("dropzone"); - } - - function dragOver(event) { - event.preventDefault(); - } - - function dragLeave(event) { - //console.log(event.timeStamp + " " + event.type + ": " + event.currentTarget.id); - // Leave has been accounted for by Enter at the same timestamp, processed earlier - if (event.timeStamp <= lastEnterTime) return; - event.currentTarget.closest("table").querySelectorAll(".dropzone").forEach((tr) => { - tr.classList.remove("dropzone"); - }) - } - - function dragEnd(event) { - dragLeave(event); - event.currentTarget.closest("table").querySelectorAll("thead tr").forEach((tr) => { - tr.toggleAttribute("hidden"); - }); - } - - function drop(event) { - event.preventDefault(); - - var params = new URLSearchParams(); - var parent_id = event.currentTarget.getAttribute("data-drop-id").split("_").pop(); - params.append("quantity[parent_id]", parent_id); - - fetch(event.dataTransfer.getData("text/plain"), { - body: params, - headers: { - "Accept": "text/vnd.turbo-stream.html", - "X-CSRF-Token": document.head.querySelector("meta[name=csrf-token]").content, - "X-Requested-With": "XMLHttpRequest" - }, - method: "POST" - }) - .then(response => response.text()) - .then(html => Turbo.renderStreamMessage(html)) - } -<% end %> diff --git a/app/views/units/_unit.html.erb b/app/views/units/_unit.html.erb index d75a89c..dad60d4 100644 --- a/app/views/units/_unit.html.erb +++ b/app/views/units/_unit.html.erb @@ -1,8 +1,10 @@ <%= tag.tr id: dom_id(unit), - ondragstart: 'dragStart(event)', ondragend: 'dragEnd(event)', - ondragover: 'dragOver(event)', ondrop: 'drop(event)', - ondragenter: 'dragEnter(event)', ondragleave: 'dragLeave(event)', - data: {drag_path: rebase_unit_path(unit), drop_id: dom_id(unit.base || unit)} do %> + ondragstart: "dragStart(event)", ondragend: "dragEnd(event)", + ondragover: "dragOver(event)", ondrop: "drop(event)", + ondragenter: "dragEnter(event)", ondragleave: "dragLeave(event)", + data: {drag_path: rebase_unit_path(unit), + drop_id: dom_id(unit.base || unit), + drop_id_param: "unit[base_id]"} do %> <%= link_to unit, edit_unit_path(unit), onclick: 'this.blur();', data: {turbo_stream: true} %> diff --git a/app/views/units/index.html.erb b/app/views/units/index.html.erb index 249bac3..8b42c2d 100644 --- a/app/views/units/index.html.erb +++ b/app/views/units/index.html.erb @@ -19,10 +19,10 @@ <% end %> - <%= tag.tr id: 'unit_', hidden: true, - ondragover: 'dragOver(event)', ondrop: 'drop(event)', - ondragenter: 'dragEnter(event)', ondragleave: 'dragLeave(event)', - data: {drop_id: 'unit_'} do %> + <%= tag.tr id: "unit_", hidden: true, + ondragover: "dragOver(event)", ondrop: "drop(event)", + ondragenter: "dragEnter(event)", ondragleave: "dragLeave(event)", + data: {drop_id: "unit_", drop_id_param: "unit[base_id]"} do %> <%= t '.top_level_drop' %> <% end %> @@ -30,81 +30,3 @@ <%= render(@units) || render_no_items %> - -<%= javascript_tag do %> - function processKey(event) { - if (event.key == "Escape") { - event.currentTarget.querySelector("a[name=cancel]").click(); - } - } - - var lastEnterTime; - function dragStart(event) { - lastEnterTime = event.timeStamp; - var row = event.currentTarget; - row.closest("table").querySelectorAll("thead tr").forEach((tr) => { - tr.toggleAttribute("hidden"); - }); - event.dataTransfer.setData("text/plain", row.getAttribute("data-drag-path")); - var rowRectangle = row.getBoundingClientRect(); - event.dataTransfer.setDragImage(row, event.x - rowRectangle.left, event.y - rowRectangle.top); - event.dataTransfer.dropEffect = "move"; - } - - /* - * Drag tracking assumptions (based on FF 122.0 experience): - * * Enter/Leave events at the same timeStamp may not be logically ordered - * (e.g. E -> E -> L, not E -> L -> E), - * * not every Enter event has corresponding Leave event, especially during - * rapid pointer moves - * NOTE: sometimes Leave is not emitted when pointer goes fast over table - * and outside. This should probably be fixed in browser, than patched here. - */ - function dragEnter(event) { - //console.log(event.timeStamp + " " + event.type + ": " + event.currentTarget.id); - dragLeave(event); - lastEnterTime = event.timeStamp; - const id = event.currentTarget.getAttribute("data-drop-id"); - document.getElementById(id).classList.add("dropzone"); - } - - function dragOver(event) { - event.preventDefault(); - } - - function dragLeave(event) { - //console.log(event.timeStamp + " " + event.type + ": " + event.currentTarget.id); - // Leave has been accounted for by Enter at the same timestamp, processed earlier - if (event.timeStamp <= lastEnterTime) return; - event.currentTarget.closest("table").querySelectorAll(".dropzone").forEach((tr) => { - tr.classList.remove("dropzone"); - }) - } - - function dragEnd(event) { - dragLeave(event); - event.currentTarget.closest("table").querySelectorAll("thead tr").forEach((tr) => { - tr.toggleAttribute("hidden"); - }); - } - - function drop(event) { - event.preventDefault(); - - var params = new URLSearchParams(); - var base_id = event.currentTarget.getAttribute("data-drop-id").split("_").pop(); - params.append("unit[base_id]", base_id); - - fetch(event.dataTransfer.getData("text/plain"), { - body: params, - headers: { - "Accept": "text/vnd.turbo-stream.html", - "X-CSRF-Token": document.head.querySelector("meta[name=csrf-token]").content, - "X-Requested-With": "XMLHttpRequest" - }, - method: "POST" - }) - .then(response => response.text()) - .then(html => Turbo.renderStreamMessage(html)) - } -<% end %>