yewstack / yew

Rust / Wasm framework for creating reliable and efficient web applications
https://yew.rs
Apache License 2.0
30.9k stars 1.43k forks source link

Does drag-and-drop work in Chrome? #914

Closed stevepryde closed 4 years ago

stevepryde commented 4 years ago

Trying to create a simple drag-and-drop demo. It works in Firefox but not Chrome

Firefox: 72.0.2 Chrome: 79.0.3945.130 OS: Manjaro Linux.

Other versions:

[dependencies]
yew = "0.11.0"
stdweb = "0.4.20"

What I've tried

It seems to work using HTML/JS. The only difference with the yew-generated HTML is that it doesn't include the ondragstart in the HTML. I assume this event handler is attached later?

Here's the basics of what I'm doing (I've removed some html but the main elements are there):

pub struct DragDropComponent {
    label: String,
    ondragstart: Callback<DragStartEvent>,
    ondrop: Callback<DragDropEvent>,
    ondragover: Callback<DragOverEvent>
}

pub enum DragDropMsg {
    DragButton1,
    DropTarget(String),
    DragOver(String),
}

impl Component for DragDropComponent {
    type Message = DragDropMsg;
    type Properties = ();

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        DragDropComponent {
            ondragstart: link.callback(|e: DragStartEvent| {
                if let Some(x) = e.data_transfer() {
                    x.set_data("text", "BUTTON 1");
                }

                DragDropMsg::DragButton1
            }),
            ondrop: link.callback(|e: DragDropEvent| {
                e.prevent_default();
                match e.data_transfer() {
                    Some(x) => {
                        let text = x.get_data("text");
                        DragDropMsg::DropTarget(text)
                    }
                    None => DragDropMsg::DropTarget(String::from("UNKNOWN")),
                }
            }),
            ondragover: link.callback(|e: DragOverEvent| {
                e.prevent_default();
                match e.data_transfer() {
                    Some(x) => {
                        let text = x.get_data("text");
                        DragDropMsg::DragOver(text)
                    }
                    None => DragDropMsg::DragOver(String::from("UNKNOWN")),
                }
            }),
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            DragDropMsg::DragButton1 => {
                self.label = String::from("Button 1 dragging");
                true
            }
            DragDropMsg::DropTarget(x) => {
                self.label = format!("Dropped {}", x);
                true
            }
            DragDropMsg::DragOver(x) => {
                self.label = format!("Dragging {}", x);
                true
            }
        }
    }

    fn view(&self) -> Html {
        html! {
            <snip>
                    <button class="pure-button pure-button-primary" id="buttondrag1"
                        draggable="true"
                        ondragstart=&self.ondragstart>
                        { "BUTTON 1" }
                    </button>
                <div class="pure-u-2-3 label" id="dragdrop-result"
                    ondrop=&self.ondrop
                    ondragover=&self.ondragover>
                    {&self.label}
                </div>
        }
    }
jstarry commented 4 years ago

@stevepryde thanks for the question! Could you add some details on what isn't working in Chrome?

We don't have any special handling for drag/drop.. we are relying on stdweb for that functionality. So it's unlikely to be a Yew issue.

If you're feeling adventurous, you could try out the web-sys branch and see if that fixes your issue (implying that it's a stdweb bug)

Your Cargo.toml would look like this:

yew = { git = "https://github.com/yewstack/yew", branch = "web-sys", features = ["web_sys"] }
stevepryde commented 4 years ago

At a guess, it looks like the ondragstart event is not being recognised by Chrome. The button doesn't appear to be draggable at all in chrome. The draggable="true" attribute appears in the DOM in Chrome so really the only other candidate is the ondragstart event handler. It works fine in Firefox.

Thanks for the suggestions. I'll give the web-sys branch a try and maybe that will point me in the right direction.

stevepryde commented 4 years ago

Well I managed to get it running on the web-sys branch only to find that it still does not work in Chrome (and does work in Firefox).

Cargo.toml now has:

[dependencies]
yew = { git = "https://github.com/yewstack/yew", branch = "web-sys", features = ["web_sys"] }
web-sys = { version = "*", features = ["Window", "DataTransfer", "DragEvent"]}
wasm-bindgen = "^0.2"

The drag event just doesn't start. Interestingly it does pick up the ondragover event when dragging text over the drop target.

stevepryde commented 4 years ago

Also I'm getting warnings in the console about calling prevent_default() in a passive event handler. Wondering if that might be related.

stevepryde commented 4 years ago

Got it working.

It seems the problem may be nothing to do with the framework at all, and something to do with chrome not liking the "draggable" attribute on a button? Could also be a conflict between the pure css library and chrome.

Anyways, I've switched to a div for the draggable element and it works in both chrome and firefox, so I've switched back to the master branch and all is well.

jstarry commented 4 years ago

@stevepryde ah wow, didn't expect that! Thanks for reporting back and happy you got to the bottom of it 👍

stevepryde commented 4 years ago

Well, I almost got to the bottom of it. Drag and drop works manually but it turns out selenium appears to have a bug with drag and drop. It starts the drag but doesn't drop the element, leaving it attached to the mouse cursor.

It doesn't work via python either (same behaviour) and I verified that my code is sending the identical action chains request compared to the python selenium library. There's already an open issue for it on the selenium project.

At least yew is working nice for me :) first time using yew (and wasm) and I was able to have a little demo working in just a few hours. It's been a pretty good experience.

jstarry commented 4 years ago

Good to hear! If there were any places you feel the documentation could have been better, please let me know. I want the experience to be really smooth for newcomers :)