DioxusLabs / dioxus

Fullstack app framework for web, desktop, mobile, and more.
https://dioxuslabs.com
Apache License 2.0
20.2k stars 774 forks source link

ondragover event is unresponsive. #1504

Open agreyyy opened 11 months ago

agreyyy commented 11 months ago

ondragover event not firing when it needs to.

the ondragover event should be called when a draggable element gets dragged over the tag with the ondragover event listener. I am having trouble getting any of the ondrag events except for ondragstart to fire when they would in a normal web browser code. Is drag and drop possible in dioxus, I roughly translated this code from reactjs code into rust, I dont undestand why it is not working. I excpect it to println that an element is in the drop zone, but instead it does nothing. Is this a user error or is this functionality not built in to dioxus as of right now?

use dioxus::prelude::*;

fn main() {
    dioxus_desktop::launch(app);
}

fn app(cx:Scope) -> Element {
    let questions = use_ref(cx,||{Vec::<String>::new()});  
    let data_transfer = use_state(cx, || {"".to_string()});

    cx.render(rsx!(
        main {
            style: "background-color: blue; height:100%",
            "DRAG DEMO",

            div {
                style: r#"
                    background-color: red;
                    width: 50%;
                    height:40%;
                "#,
                "DRAGGABLE ELEMENTS",

                div {
                    draggable: true,
                    ondragstart: move |ev| {
                        println!("{:?}",ev);
                        data_transfer.set("ITEM1".to_string());
                    },
                    "ITEM1"
                },

                div {
                    draggable: true,
                    ondragstart: move |ev| {
                        println!("{:?}",ev);
                        data_transfer.set("ITEM2".to_string());
                    },
                    "ITEM2"
                },

            },

            div {
                style: r#"
                    background-color: green;
                    width: 50%;
                    height: 80%;
                "#,
                prevent_default: "ondragover",
                ondragover: move |_ev| {
                    _ev.stop_propagation();
                    println!("IN DROP ZONE");
                },
                ondragenter: move |_ev| {
                    println!("ITEM ENTERED DROP ZONE");
                },
                ondrop: move |_ev| {
                    println!("ITEM DROPPED");
                    let question = data_transfer.get();
                    questions.with_mut(|list| list.push(question.to_owned()));
                },
                "DROP ZONE",
                questions.read().iter().map(|question| {
                    rsx!( div {"{question }"})
                })
            }

        }
    ))    
}

Environment:

Questionnaire

ealmloff commented 11 months ago

This could be something specific to the system browser on Linux Mint. It seems to work correctly on MacOs. I get this log:

IN DROP ZONE
IN DROP ZONE
IN DROP ZONE
IN DROP ZONE
ITEM ENTERED DROP ZONE
IN DROP ZONE
IN DROP ZONE
ITEM DROPPED

If you are interested in debugging this, I think either the event listener is not being added correctly (here), or more likely it is being serialized or deserialized incorrectly.

You could start in the interpreter which handles converting JS events to Dioxus events. It should return a JSON value that represents the event with a structure defined here and some metadata about the element the event was triggered on. That event is then deserialized in the desktop crate.

Natrocx commented 9 months ago

This issue also occurs for me: Environment: Dioxus version: 0.4.0/git main Rust version: 1.73 OS info: Gentoo Linux App platform: desktop

Doing some initial investigation I find the following: The events are properly registered (it shows in the web inspector under "Node"). The events that do not work in dioxus do not work in the web inspector either - setting a breakpoint will never trigger it. The "ondragstart" and "ondragend" (potentially non-exhaustive) events do trigger successfully and also trigger the web inspector breakpoint.

To me this suggests a bug in the webkitgtk or the configuration applied by dioxus. I do not know where to go from here tho.

ealmloff commented 9 months ago

This issue also occurs for me: Environment: Dioxus version: 0.4.0/git main Rust version: 1.73 OS info: Gentoo Linux App platform: desktop

Doing some initial investigation I find the following: The events are properly registered (it shows in the web inspector under "Node"). The events that do not work in dioxus do not work in the web inspector either - setting a breakpoint will never trigger it. The "ondragstart" and "ondragend" (potentially non-exhaustive) events do trigger successfully and also trigger the web inspector breakpoint.

To me this suggests a bug in the webkitgtk or the configuration applied by dioxus. I do not know where to go from here tho.

You could try reproducing the element structure with HTML and adding a JS event listener in your system web browser to rule out an issue in dioxus's/wry's webview configuration.

One note if your code is not identical to the original example code: Make sure you don't call with_file_drop_handler in your code because it will prevent drag events in wry.

Natrocx commented 9 months ago

I have tried running the provided example using dioxus_web and the bug also occured. I was however able to add an event listener through the web-inspector(using js) of my normal browser (Firefox) and the event + breakpoints worked fine. Trying to do the same through the web-inspector on the dioxus_desktop webview was not possible - the listener was displayed as registered but never called and breakpoints also do not work.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drop_event The provided example in MDN also works just fine.

Maybe this is related? https://github.com/tauri-apps/tauri/issues/6695

Natrocx commented 9 months ago

I have opened an issue upstream: https://bugs.webkit.org/show_bug.cgi?id=265857

Natrocx commented 9 months ago

I have found the underlying issue but I'm afraid I don't really understand whats happening in the WebKit code so I guess we will have to wait for the WebKit devs to provide an actual fix.

In the meantime its possible to work around the issue by setting data in the dragstart event as described in the WebKit bug report. Given that dioxus does not currently support the dataTransfer "part" of the DragEvent api, and I'm not sure if its actually worth implementing given the cost of serializing and sending the data as IPC for every access, a workaround has to be created somewhat like so:

    #[cfg(target_os = "linux")]
{
    let eval_workaround = use_eval(cx);
    use_on_create(cx, || {
        to_owned![eval_workaround];
        async move {
        eval_workaround(
            r#"
            let draggableElements = document.querySelectorAll('[draggable="true"]');
            draggableElements.forEach((el) => {
                el.addEventListener("dragstart", (ev) => {
                    ev.dataTransfer.setData("text/plain", ev.target.id);
                });
            });
        "#,
    )
    .unwrap();

    }});
}