/// HTML drag/drop will fire a bubbling `dragleave` event over all children of a
/// `dragleave`-listened-to element, so we need to filter out the events from the
/// children elements with this esoteric DOM arcana.
HTML drag/drop will fire a bubbling `dragleave` event over all children of a
`dragleave`-listened-to element, so we need to filter out the events from the
children elements with this esoteric DOM arcana.
HTML drag / drop will fire a bubbling ` dragleave ` event over all children of a ` dragleave ` - listened - to element so we need to filter out the events from the children elements with this esoteric DOM arcana .
pub fn dragleave_helper(callback: impl Fn() + 'static) -> Callback<DragEvent> {
    Callback::from({
        move |event: DragEvent| {
            event.stop_propagation();
            event.prevent_default();
            let mut related_target = event
                .related_target()
                .or_else(|| Some(JsValue::UNDEFINED.unchecked_into::<EventTarget>()))
                .and_then(|x| x.dyn_into::<Element>().ok());
            let current_target = event
                .current_target()
                .unwrap()
                .unchecked_into::<HtmlElement>();
            // This is a wild chrome bug. `dragleave` can fire with the `relatedTarget`
            // property set to an element inside the closed `ShadowRoot` hosted by a
            // browser-native `<select>` tag, which fails the `.contains()` check
            // below.  This mystery `ShadowRoot` has a structure that looks like this
            // (tested in Chrome 92), which we try to detect as best we can below.
            //
            // ```html
            // <div aria-hidden="true">Selected Text Here</siv>
            // <slot name="user-agent-custom-assign-slot"></slot>
            // ```
            //
            // This is pretty course though, since there is no guarantee this structure
            // will be maintained in future Chrome versions; the `.expect()` in this
            // method chain should at least warn us if this regresses.
            //
            // Wait - you don't believe me?  Throw a debugger statement inside this
            // conditional and drag a column over a pivot-mode active columns list.
            if related_target
                .as_ref()
                .map(|x| x.has_attribute("aria-hidden"))
                .unwrap_or_default()
            {
                related_target = Some(
                    related_target
                        .unwrap()
                        .parent_node()
                        .unwrap()
                        .dyn_ref::<ShadowRoot>()
                        .expect("Chrome drag/drop bug detection failed")
                        .host()
                        .unchecked_into::<Element>(),
                )
            }
            match related_target {
                Some(ref related) => {
                    if !current_target.contains(Some(related)) {
                        callback();
                    }
                }
                None => {
                    // Safari (OSX and iOS) don't set `relatedTarget`, so we need to
                    // read a memoized value from the `"dragenter"` event.
                    let dataset = current_target.dataset();
                    if dataset.get("safaridragleave").is_some() {
                        dataset.delete("safaridragleave");
                    } else {
                        callback();
                    }
                }
            };
        }
    })
}
pub fn dragleave_helper ( callback : impl Fn ( ) + ' static ) -> Callback < DragEvent > { Callback :: from ( { move | event : DragEvent | { event . stop_propagation ( ) ; event . prevent_default ( ) ; let mut related_target = event . related_target ( ) . or_else ( | | Some ( JsValue :: UNDEFINED . unchecked_into :: < EventTarget > ( ) ) ) . and_then ( | x | x . dyn_into :: < Element > ( ) . ok ( ) ) ; let current_target = event . current_target ( ) . unwrap ( ) . unchecked_into :: < HtmlElement > ( ) ; // This is a wild chrome bug. `dragleave` can fire with the `relatedTarget` // property set to an element inside the closed `ShadowRoot` hosted by a // browser-native `<select>` tag, which fails the `.contains()` check // below.  This mystery `ShadowRoot` has a structure that looks like this // (tested in Chrome 92), which we try to detect as best we can below. // // ```html // <div aria-hidden="true">Selected Text Here</siv> // <slot name="user-agent-custom-assign-slot"></slot> // ``` // // This is pretty course though, since there is no guarantee this structure // will be maintained in future Chrome versions; the `.expect()` in this // method chain should at least warn us if this regresses. // // Wait - you don't believe me?  Throw a debugger statement inside this // conditional and drag a column over a pivot-mode active columns list. if related_target . as_ref ( ) . map ( | x | x . has_attribute ( " " ) ) . unwrap_or_default ( ) { related_target = Some ( related_target . unwrap ( ) . parent_node ( ) . unwrap ( ) . dyn_ref :: < ShadowRoot > ( ) . expect ( " " ) . host ( ) . unchecked_into :: < Element > ( ) , ) } match related_target { Some ( ref related ) => { if ! current_target . contains ( Some ( related ) ) { callback ( ) ; } } None => { // Safari (OSX and iOS) don't set `relatedTarget`, so we need to // read a memoized value from the `"dragenter"` event. let dataset = current_target . dataset ( ) ; if dataset . get ( " " ) . is_some ( ) { dataset . delete ( " " ) ; } else { callback ( ) ; } } } ; } } ) }
HTML drag/drop will fire a bubbling `dragleave` event over all children of a
`dragleave`-listened-to element, so we need to filter out the events from the
children elements with this esoteric DOM arcana.
HTML drag / drop will fire a bubbling ` dragleave ` event over all children of a ` dragleave ` - listened - to element so we need to filter out the events from the children elements with this esoteric DOM arcana .
callback
impl Fn() + 'static