nusa 0.1.9

web-frontend features for kagura
Documentation
use crate::v_node::v_element::{VEvent, VEventHandlers, VEvents, VReferHandler};
use kagura::node::{BasicNodeMsg, Msg};
use kagura::Component;
use wasm_bindgen::JsCast;

pub struct Events {
    events: VEvents,
}

impl Into<VEvents> for Events {
    fn into(self) -> VEvents {
        self.events
    }
}

impl Events {
    pub fn new() -> Self {
        Self {
            events: VEvents::new(),
        }
    }

    pub fn on<Target: Component + 'static>(
        mut self,
        type_: impl Into<String>,
        target: &Target,
        handler: impl FnOnce(VEvent<web_sys::Event>) -> Target::Msg + 'static,
    ) -> Self {
        let type_ = type_.into();
        let target_id = Msg::target_id(target);
        let mut handelrs = if let Some(handlers) = self.events.events.remove(&type_) {
            handlers
        } else {
            VEventHandlers::new()
        };
        handelrs.bubbles.push(Box::new(move |e| {
            let msg = handler(e);
            let msg = BasicNodeMsg::<Target>::ComponentMsg(msg);
            Msg::new(target_id, Box::new(msg))
        }));
        self.events.events.insert(type_, handelrs);
        self
    }

    pub fn capture_on<Target: Component + 'static>(
        mut self,
        type_: impl Into<String>,
        target: &Target,
        handler: impl FnOnce(VEvent<web_sys::Event>) -> Target::Msg + 'static,
    ) -> Self {
        let type_ = type_.into();
        let target_id = Msg::target_id(target);
        let mut handelrs = if let Some(handlers) = self.events.events.remove(&type_) {
            handlers
        } else {
            VEventHandlers::new()
        };
        handelrs.captures.push(Box::new(move |e| {
            let msg = handler(e);
            let msg = BasicNodeMsg::<Target>::ComponentMsg(msg);
            Msg::new(target_id, Box::new(msg))
        }));
        self.events.events.insert(type_, handelrs);
        self
    }

    pub fn refer<Target: Component + 'static>(
        mut self,
        target: &Target,
        handler: impl FnOnce(web_sys::Node) -> Target::Msg + 'static,
    ) -> Self {
        let target_id = Msg::target_id(target);
        let handler = Box::new(move |el| {
            let msg = handler(el);
            let msg = BasicNodeMsg::<Target>::ComponentMsg(msg);
            Msg::new(target_id, Box::new(msg))
        });
        let refer_handler = VReferHandler::new(target_id, handler);
        self.events.refers.push(refer_handler);
        self
    }

    pub fn on_input<Target: Component + 'static>(
        self,
        target: &Target,
        handler: impl FnOnce(String) -> Target::Msg + 'static,
    ) -> Self {
        self.on("input", target, move |e| {
            if let Some(target) = e.target() {
                if let Some(target) = target.dyn_ref::<web_sys::HtmlInputElement>() {
                    return handler(target.value());
                } else if let Some(target) = target.dyn_ref::<web_sys::HtmlTextAreaElement>() {
                    return handler(target.value());
                }
            }
            handler(String::new())
        })
    }
}

macro_rules! event_type {
    ($event_ty:tt as $b_name:ident / $c_name:ident) => {
        pub fn $b_name<Target: Component + 'static>(
            self,
            target: &Target,
            handler: impl FnOnce(VEvent<web_sys::Event>) -> Target::Msg + 'static,
        ) -> Self {
            self.on($event_ty, target, handler)
        }

        pub fn $c_name<Target: Component + 'static>(
            self,
            target: &Target,
            handler: impl FnOnce(VEvent<web_sys::Event>) -> Target::Msg + 'static,
        ) -> Self {
            self.capture_on($event_ty, target, handler)
        }
    };
}

impl Events {
    event_type!("load" as on_load / capture_on_load);

    event_type!("drag" as on_drag / capture_on_drag);
    event_type!("dragend" as on_dragend / capture_on_dragend);
    event_type!("dragenter" as on_dragenter / capture_on_dragenter);
    event_type!("dragstart" as on_dragstart / capture_on_dragstart);
    event_type!("dragleave" as on_dragleave / capture_on_dragleave);
    event_type!("dragover" as on_dragover / capture_on_dragover);
    event_type!("drop" as on_drop / capture_on_drop);

    event_type!("click" as on_click / capture_on_click);
    event_type!("contextmenu" as on_contextmenu / capture_on_contextmenu);
    event_type!("dblclick" as on_dblclick / capture_on_dblclick);
    event_type!("mousedown" as on_mousedown / capture_on_mousedown);
    event_type!("mouseenter" as on_mouseenter / capture_on_mouseenter);
    event_type!("mouseleave" as on_mouseleave / capture_on_mouseleave);
    event_type!("mousemove" as on_mousemove / capture_on_mousemove);
    event_type!("mouseover" as on_mouseover / capture_on_mouseover);
    event_type!("mouseout" as on_mouseout / capture_on_mouseout);
    event_type!("mouseup" as on_mouseup / capture_on_mouseup);

    event_type!("keydown" as on_keydown / capture_on_keydown);
    event_type!("keypress" as on_keypress / capture_on_keypress);
    event_type!("keyup" as on_keyup / capture_on_keyup);
}

impl std::default::Default for Events {
    fn default() -> Self {
        Self::new()
    }
}