Replace DragEvent data by a global state
authorGreg Burri <greg.burri@gmail.com>
Wed, 15 Jan 2025 09:42:50 +0000 (10:42 +0100)
committerGreg Burri <greg.burri@gmail.com>
Wed, 15 Jan 2025 09:42:50 +0000 (10:42 +0100)
frontend/src/recipe_edit.rs

index df491d7..9f5f721 100644 (file)
@@ -1,4 +1,4 @@
-use std::rc;
+use std::{cell::RefCell, rc, sync::Mutex};
 
 use gloo::{
     console::log,
@@ -401,8 +401,9 @@ fn create_group_element(group: &ron_api::Group) -> Element {
             if modal_dialog::show(&format!("Are you sure to delete the group '{}'", name)).await {
                 let body = ron_api::RemoveRecipeGroup { group_id };
                 let _ = request::delete::<(), _>("recipe/remove_group", body).await;
-                by_id::<Element>(&format!("group-{}", group_id)).remove();
-                by_id::<Element>(&format!("dropzone-group-{}", group_id)).remove();
+                let group_element = by_id::<Element>(&format!("group-{}", group_id));
+                group_element.next_element_sibling().unwrap().remove();
+                group_element.remove();
             }
         });
     })
@@ -534,8 +535,9 @@ fn create_step_element(group_element: &Element, step: &ron_api::Step) -> Element
             if modal_dialog::show(&format!("Are you sure to delete the step '{}'", action)).await {
                 let body = ron_api::RemoveRecipeStep { step_id };
                 let _ = request::delete::<(), _>("recipe/remove_step", body).await;
-                by_id::<Element>(&format!("step-{}", step_id)).remove();
-                by_id::<Element>(&format!("dropzone-step-{}", step_id)).remove();
+                let step_element = by_id::<Element>(&format!("step-{}", step_id));
+                step_element.next_element_sibling().unwrap().remove();
+                step_element.remove();
             }
         });
     })
@@ -674,9 +676,6 @@ fn create_ingredient_element(step_element: &Element, ingredient: &ron_api::Ingre
     ingredient_element
 }
 
-// "text/plain" is avoided to prevent dropping to a input text box.
-const DRAG_AND_DROP_MIME_TYPE: &str = "recipes/element-id";
-
 enum CursorPosition {
     UpperPart,
     LowerPart,
@@ -700,6 +699,12 @@ fn get_parent_with_id_starting_with(mut element: Element, prefix: &str) -> Eleme
     element
 }
 
+// It replaces 'event.data_transfer().unwrap().get_data()/set_data()' because
+// Chrome prevent to read this during draghover event which is the correct behavior
+// according the specifications:
+// * https://html.spec.whatwg.org/multipage/dnd.html#the-drag-data-store
+static DATA_DRAGGED: Mutex<RefCell<String>> = Mutex::new(RefCell::new(String::new()));
+
 /// Set an element as draggable and add an element before and after
 /// cloned from "#hidden-templates .dropzone".
 /// All elements set as draggable in a given container can be dragged
@@ -731,11 +736,9 @@ where
         EventListenerOptions::enable_prevent_default(),
         move |event| {
             let event: &DragEvent = event.dyn_ref::<DragEvent>().unwrap();
-            let drag_data = event
-                .data_transfer()
-                .unwrap()
-                .get_data(DRAG_AND_DROP_MIME_TYPE)
-                .unwrap();
+
+            let drag_data_lock = DATA_DRAGGED.lock().unwrap();
+            let drag_data = drag_data_lock.borrow();
 
             if drag_data.starts_with(&prefix_copied) {
                 let element: Element = by_id(&drag_data);
@@ -777,11 +780,9 @@ where
     let prefix_copied = prefix.to_string();
     EventListener::new(element, "dragleave", move |event| {
         let event: &DragEvent = event.dyn_ref::<DragEvent>().unwrap();
-        let drag_data = event
-            .data_transfer()
-            .unwrap()
-            .get_data(DRAG_AND_DROP_MIME_TYPE)
-            .unwrap();
+
+        let drag_data_lock = DATA_DRAGGED.lock().unwrap();
+        let drag_data = drag_data_lock.borrow();
 
         if drag_data.starts_with(&prefix_copied) {
             let element: Element = by_id(&drag_data);
@@ -812,11 +813,9 @@ where
     let prefix_copied = prefix.to_string();
     EventListener::new(element, "drop", move |event| {
         let event: &DragEvent = event.dyn_ref::<DragEvent>().unwrap();
-        let drag_data = event
-            .data_transfer()
-            .unwrap()
-            .get_data(DRAG_AND_DROP_MIME_TYPE)
-            .unwrap();
+
+        let drag_data_lock = DATA_DRAGGED.lock().unwrap();
+        let drag_data = drag_data_lock.borrow();
 
         if drag_data.starts_with(&prefix_copied) {
             let target: Element = event.current_target().unwrap().dyn_into().unwrap();
@@ -899,11 +898,10 @@ where
                     dp.set_class_name("dropzone active");
                 }
             }
-            event
-                .data_transfer()
-                .unwrap()
-                .set_data(DRAG_AND_DROP_MIME_TYPE, &target_element.id())
-                .unwrap();
+
+            let drag_data_lock = DATA_DRAGGED.lock().unwrap();
+            drag_data_lock.replace(target_element.id());
+
             event.data_transfer().unwrap().set_effect_allowed("move");
         }
     })
@@ -938,11 +936,9 @@ where
             EventListenerOptions::enable_prevent_default(),
             move |event| {
                 let event: &DragEvent = event.dyn_ref::<DragEvent>().unwrap();
-                let drag_data = event
-                    .data_transfer()
-                    .unwrap()
-                    .get_data(DRAG_AND_DROP_MIME_TYPE)
-                    .unwrap();
+
+                let drag_data_lock = DATA_DRAGGED.lock().unwrap();
+                let drag_data = drag_data_lock.borrow();
 
                 if drag_data.starts_with(&prefix_copied) {
                     let element: Element = by_id(&drag_data);
@@ -973,11 +969,9 @@ where
         let prefix_copied = prefix.to_string();
         EventListener::new(dropzone, "dragleave", move |event| {
             let event: &DragEvent = event.dyn_ref::<DragEvent>().unwrap();
-            let drag_data = event
-                .data_transfer()
-                .unwrap()
-                .get_data(DRAG_AND_DROP_MIME_TYPE)
-                .unwrap();
+
+            let drag_data_lock = DATA_DRAGGED.lock().unwrap();
+            let drag_data = drag_data_lock.borrow();
 
             if drag_data.starts_with(&prefix_copied) {
                 let element: Element = by_id(&drag_data);
@@ -1005,11 +999,9 @@ where
         let prefix_copied = prefix.to_string();
         EventListener::new(dropzone, "drop", move |event| {
             let event: &DragEvent = event.dyn_ref::<DragEvent>().unwrap();
-            let drag_data = event
-                .data_transfer()
-                .unwrap()
-                .get_data(DRAG_AND_DROP_MIME_TYPE)
-                .unwrap();
+
+            let drag_data_lock = DATA_DRAGGED.lock().unwrap();
+            let drag_data = drag_data_lock.borrow();
 
             if drag_data.starts_with(&prefix_copied) {
                 let target: Element = event.current_target().unwrap().dyn_into().unwrap();