Pārlūkot izejas kodu

Feat: begin WIP on html macro

Jonathan Kelley 4 gadi atpakaļ
vecāks
revīzija
a8b1225c48

+ 26 - 17
packages/core/src/changelist.rs

@@ -19,11 +19,9 @@
 //!
 //!
 //!
 //!
 
 
-
-
 use bumpalo::Bump;
 use bumpalo::Bump;
 
 
-use crate::innerlude::{Listener};
+use crate::innerlude::Listener;
 
 
 /// The `Edit` represents a single modifcation of the renderer tree.
 /// The `Edit` represents a single modifcation of the renderer tree.
 ///
 ///
@@ -308,14 +306,19 @@ impl<'a> EditMachine<'a> {
         self.forcing_new_listeners = previous;
         self.forcing_new_listeners = previous;
     }
     }
 
 
-    pub fn new_event_listener(&mut self, _listener: &Listener) {
+    pub fn new_event_listener(&mut self, listener: &Listener) {
         debug_assert!(self.traversal_is_committed());
         debug_assert!(self.traversal_is_committed());
-        todo!("Event listener not wired up yet");
-        // debug!("emit: new_event_listener({:?})", listener);
-        // let (a, b) = listener.get_callback_parts();
-        // debug_assert!(a != 0);
+        // todo!("Event listener not wired up yet");
+        log::debug!("emit: new_event_listener({:?})", listener);
+        let (a, b) = listener.get_callback_parts();
+        debug_assert!(a != 0);
         // let event_id = self.ensure_string(listener.event);
         // let event_id = self.ensure_string(listener.event);
-        // self.emitter.new_event_listener(event_id.into(), a, b);
+        self.emitter.push(Edit::NewEventListener {
+            event_type: listener.event.into(),
+            a,
+            b,
+        });
+        // self.emitter.new_event_listener(listener.event.into(), a, b);
     }
     }
 
 
     pub fn update_event_listener(&mut self, listener: &Listener) {
     pub fn update_event_listener(&mut self, listener: &Listener) {
@@ -326,19 +329,25 @@ impl<'a> EditMachine<'a> {
             return;
             return;
         }
         }
 
 
-        // debug!("emit: update_event_listener({:?})", listener);
-        todo!("Event listener not wired up yet");
-        // let (a, b) = listener.get_callback_parts();
-        // debug_assert!(a != 0);
-        let _event_id = self.ensure_string(listener.event);
+        log::debug!("emit: update_event_listener({:?})", listener);
+        // todo!("Event listener not wired up yet");
+        let (a, b) = listener.get_callback_parts();
+        debug_assert!(a != 0);
+        self.emitter.push(Edit::UpdateEventListener {
+            event_type: listener.event.into(),
+            a,
+            b,
+        });
         // self.emitter.update_event_listener(event_id.into(), a, b);
         // self.emitter.update_event_listener(event_id.into(), a, b);
     }
     }
 
 
-    pub fn remove_event_listener(&mut self, event: &str) {
+    pub fn remove_event_listener(&mut self, event: &'a str) {
         debug_assert!(self.traversal_is_committed());
         debug_assert!(self.traversal_is_committed());
+        self.emitter
+            .push(Edit::RemoveEventListener { event_type: event });
         // debug!("emit: remove_event_listener({:?})", event);
         // debug!("emit: remove_event_listener({:?})", event);
-        let _event_id = self.ensure_string(event);
-        todo!("Event listener not wired up yet");
+        // let _event_id = self.ensure_string(event);
+        // todo!("Event listener not wired up yet");
         // self.emitter.remove_event_listener(event_id.into());
         // self.emitter.remove_event_listener(event_id.into());
     }
     }
 
 

+ 3 - 6
packages/core/src/dodriodiff.rs

@@ -63,13 +63,9 @@ pub struct DiffMachine<'a> {
     need_to_diff: FxHashSet<Index>,
     need_to_diff: FxHashSet<Index>,
 }
 }
 
 
-enum NeedToDiff {
-    PropsChanged,
-    Subscription,
-}
-
 impl<'a> DiffMachine<'a> {
 impl<'a> DiffMachine<'a> {
     pub fn new(bump: &'a Bump) -> Self {
     pub fn new(bump: &'a Bump) -> Self {
+        log::debug!("starsting diff machine");
         Self {
         Self {
             change_list: EditMachine::new(bump),
             change_list: EditMachine::new(bump),
             immediate_queue: Vec::new(),
             immediate_queue: Vec::new(),
@@ -83,6 +79,7 @@ impl<'a> DiffMachine<'a> {
     }
     }
 
 
     pub fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
     pub fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
+        log::debug!("Diffing nodes");
         /*
         /*
         For each valid case, we "commit traversal", meaning we save this current position in the tree.
         For each valid case, we "commit traversal", meaning we save this current position in the tree.
         Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later.
         Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later.
@@ -876,6 +873,7 @@ impl<'a> DiffMachine<'a> {
                 children,
                 children,
                 namespace,
                 namespace,
             }) => {
             }) => {
+                log::info!("Creating {:#?}", node);
                 if let Some(namespace) = namespace {
                 if let Some(namespace) = namespace {
                     self.change_list.create_element_ns(tag_name, namespace);
                     self.change_list.create_element_ns(tag_name, namespace);
                 } else {
                 } else {
@@ -1001,7 +999,6 @@ enum KeyedPrefixResult {
 }
 }
 
 
 mod support {
 mod support {
-    
 
 
     // // Get or create the template.
     // // Get or create the template.
     // //
     // //

+ 18 - 0
packages/core/src/events.rs

@@ -6,6 +6,7 @@
 //! The goal here is to provide a consistent event interface across all renderer types
 //! The goal here is to provide a consistent event interface across all renderer types
 use generational_arena::Index;
 use generational_arena::Index;
 
 
+#[derive(Debug)]
 pub struct EventTrigger {
 pub struct EventTrigger {
     pub component_id: Index,
     pub component_id: Index,
     pub listener_id: u32,
     pub listener_id: u32,
@@ -18,6 +19,7 @@ impl EventTrigger {
     }
     }
 }
 }
 
 
+#[derive(Debug)]
 pub enum VirtualEvent {
 pub enum VirtualEvent {
     // Real events
     // Real events
     ClipboardEvent(ClipboardEvent),
     ClipboardEvent(ClipboardEvent),
@@ -42,19 +44,35 @@ pub enum VirtualEvent {
 
 
 // these should reference the underlying event
 // these should reference the underlying event
 
 
+#[derive(Debug)]
 pub struct ClipboardEvent {}
 pub struct ClipboardEvent {}
+#[derive(Debug)]
 pub struct CompositionEvent {}
 pub struct CompositionEvent {}
+#[derive(Debug)]
 pub struct KeyboardEvent {}
 pub struct KeyboardEvent {}
+#[derive(Debug)]
 pub struct FocusEvent {}
 pub struct FocusEvent {}
+#[derive(Debug)]
 pub struct FormEvent {}
 pub struct FormEvent {}
+#[derive(Debug)]
 pub struct GenericEvent {}
 pub struct GenericEvent {}
+#[derive(Debug)]
 pub struct MouseEvent {}
 pub struct MouseEvent {}
+#[derive(Debug)]
 pub struct PointerEvent {}
 pub struct PointerEvent {}
+#[derive(Debug)]
 pub struct SelectionEvent {}
 pub struct SelectionEvent {}
+#[derive(Debug)]
 pub struct TouchEvent {}
 pub struct TouchEvent {}
+#[derive(Debug)]
 pub struct UIEvent {}
 pub struct UIEvent {}
+#[derive(Debug)]
 pub struct WheelEvent {}
 pub struct WheelEvent {}
+#[derive(Debug)]
 pub struct MediaEvent {}
 pub struct MediaEvent {}
+#[derive(Debug)]
 pub struct ImageEvent {}
 pub struct ImageEvent {}
+#[derive(Debug)]
 pub struct AnimationEvent {}
 pub struct AnimationEvent {}
+#[derive(Debug)]
 pub struct TransitionEvent {}
 pub struct TransitionEvent {}

+ 2 - 1
packages/core/src/nodebuilder.rs

@@ -1070,7 +1070,8 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
 ///     // do something when a click happens...
 ///     // do something when a click happens...
 /// });
 /// });
 /// ```
 /// ```
-pub fn on<'a, 'b, F: 'static>(
+pub fn on<'a, 'b>(
+    // pub fn on<'a, 'b, F: 'static>(
     bump: &'a Bump,
     bump: &'a Bump,
     event: &'static str,
     event: &'static str,
     callback: impl Fn(()) + 'a,
     callback: impl Fn(()) + 'a,

+ 25 - 6
packages/core/src/nodes.rs

@@ -3,8 +3,6 @@
 //!
 //!
 //! These VNodes should be *very* cheap and *very* fast to construct - building a full tree should be insanely quick.
 //! These VNodes should be *very* cheap and *very* fast to construct - building a full tree should be insanely quick.
 
 
-
-
 use bumpalo::Bump;
 use bumpalo::Bump;
 pub use vcomponent::VComponent;
 pub use vcomponent::VComponent;
 pub use velement::VElement;
 pub use velement::VElement;
@@ -97,7 +95,7 @@ mod vnode {
 
 
 mod velement {
 mod velement {
     use super::*;
     use super::*;
-    use std::{fmt::Debug};
+    use std::fmt::Debug;
 
 
     #[derive(Debug)]
     #[derive(Debug)]
     pub struct VElement<'a> {
     pub struct VElement<'a> {
@@ -199,6 +197,29 @@ mod velement {
                 .finish()
                 .finish()
         }
         }
     }
     }
+    pub(crate) type ListenerCallback<'a> = &'a (dyn Fn(()));
+    union CallbackFatPtr<'a> {
+        callback: ListenerCallback<'a>,
+        parts: (u32, u32),
+    }
+    impl Listener<'_> {
+        #[inline]
+        pub(crate) fn get_callback_parts(&self) -> (u32, u32) {
+            assert_eq!(
+                std::mem::size_of::<ListenerCallback>(),
+                std::mem::size_of::<CallbackFatPtr>()
+            );
+
+            unsafe {
+                let fat = CallbackFatPtr {
+                    callback: self.callback,
+                };
+                let (a, b) = fat.parts;
+                debug_assert!(a != 0);
+                (a, b)
+            }
+        }
+    }
 
 
     /// The key for keyed children.
     /// The key for keyed children.
     ///
     ///
@@ -265,9 +286,7 @@ mod vtext {
 /// Only supports the functional syntax
 /// Only supports the functional syntax
 mod vcomponent {
 mod vcomponent {
     use crate::innerlude::FC;
     use crate::innerlude::FC;
-    use std::{marker::PhantomData};
-
-    
+    use std::marker::PhantomData;
 
 
     #[derive(Debug)]
     #[derive(Debug)]
     pub struct VComponent<'src> {
     pub struct VComponent<'src> {

+ 20 - 1
packages/core/src/scope.rs

@@ -219,10 +219,29 @@ impl ActiveFrame {
     }
     }
 }
 }
 
 
-#[cfg(test)]
+// #[cfg(test)]
 mod tests {
 mod tests {
     use super::*;
     use super::*;
 
 
+    static ListenerTest: FC<()> = |ctx, props| {
+        ctx.view(html! {
+            <div onclick={|_| println!("Hell owlrld")}>
+                "hello"
+            </div>
+        })
+    };
+
+    #[test]
+    fn check_listeners() -> Result<()> {
+        let mut scope = Scope::new::<(), ()>(ListenerTest, (), None);
+        scope.run::<()>();
+
+        let nodes = scope.new_frame();
+        dbg!(nodes);
+
+        Ok(())
+    }
+
     #[test]
     #[test]
     fn test_scope() {
     fn test_scope() {
         let example: FC<()> = |ctx, props| {
         let example: FC<()> = |ctx, props| {

+ 33 - 1
packages/html-macro-2/src/lib.rs

@@ -1,3 +1,18 @@
+//!
+//! TODO:
+//! - [ ] Support for VComponents
+//! - [ ] Support for inline format in text
+//! - [ ] Support for expressions in attribute positions
+//! - [ ] Support for iterators
+//!
+//!
+//!
+//!
+//!
+//!
+//!
+//!
+
 use ::{
 use ::{
     proc_macro::TokenStream,
     proc_macro::TokenStream,
     proc_macro2::{Span, TokenStream as TokenStream2},
     proc_macro2::{Span, TokenStream as TokenStream2},
@@ -10,6 +25,8 @@ use ::{
     },
     },
 };
 };
 
 
+/// The html! macro makes it easy for developers to write jsx-style markup in their components.
+/// We aim to keep functional parity with html templates.
 #[proc_macro]
 #[proc_macro]
 pub fn html(s: TokenStream) -> TokenStream {
 pub fn html(s: TokenStream) -> TokenStream {
     let html: HtmlRender = match syn::parse(s) {
     let html: HtmlRender = match syn::parse(s) {
@@ -19,8 +36,10 @@ pub fn html(s: TokenStream) -> TokenStream {
     html.to_token_stream().into()
     html.to_token_stream().into()
 }
 }
 
 
+// ==============================================
+// Parse any stream coming from the html! macro
+// ==============================================
 struct HtmlRender {
 struct HtmlRender {
-    // ctx: Ident,
     kind: NodeOrList,
     kind: NodeOrList,
 }
 }
 
 
@@ -58,6 +77,9 @@ impl ToTokens for HtmlRender {
     }
     }
 }
 }
 
 
+/// =============================================
+/// Parse any child as a node or list of nodes
+/// =============================================
 enum NodeOrList {
 enum NodeOrList {
     Node(Node),
     Node(Node),
     List(NodeList),
     List(NodeList),
@@ -115,6 +137,9 @@ impl Parse for Node {
     }
     }
 }
 }
 
 
+/// =======================================
+/// Parse the VNode::Element type
+/// =======================================
 struct Element {
 struct Element {
     name: Ident,
     name: Ident,
     attrs: Vec<Attr>,
     attrs: Vec<Attr>,
@@ -214,6 +239,9 @@ impl Parse for Element {
     }
     }
 }
 }
 
 
+/// =======================================
+/// Parse a VElement's Attributes
+/// =======================================
 struct Attr {
 struct Attr {
     name: Ident,
     name: Ident,
     ty: AttrType,
     ty: AttrType,
@@ -285,6 +313,10 @@ enum AttrType {
     // todo Bool(MaybeExpr<LitBool>)
     // todo Bool(MaybeExpr<LitBool>)
 }
 }
 
 
+/// =======================================
+/// Parse just plain text
+/// =======================================
+///
 struct TextNode(MaybeExpr<LitStr>);
 struct TextNode(MaybeExpr<LitStr>);
 
 
 impl Parse for TextNode {
 impl Parse for TextNode {

+ 2 - 0
packages/web/Cargo.toml

@@ -28,6 +28,7 @@ features = [
     "Document",
     "Document",
     "Element",
     "Element",
     "HtmlElement",
     "HtmlElement",
+    "HtmlInputElement",
     "EventTarget",
     "EventTarget",
     "HtmlCollection",
     "HtmlCollection",
     "Node",
     "Node",
@@ -39,6 +40,7 @@ features = [
     "InputEvent",
     "InputEvent",
     "DocumentType",
     "DocumentType",
     "CharacterData",
     "CharacterData",
+    "HtmlOptionElement",
 ]
 ]
 
 
 [profile.release]
 [profile.release]

+ 29 - 8
packages/web/examples/basic.rs

@@ -4,17 +4,38 @@ use dioxus_core::prelude::*;
 use dioxus_web::*;
 use dioxus_web::*;
 
 
 fn main() {
 fn main() {
+    // Setup logging
+    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
+    // wasm_logger::init(wasm_logger::Config::with_prefix(
+    //     log::Level::Debug,
+    //     "dioxus_core",
+    // ));
+    console_error_panic_hook::set_once();
+
+    // Run the app
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
 }
 }
 
 
 static App: FC<()> = |ctx, _| {
 static App: FC<()> = |ctx, _| {
-    ctx.view(html! {
-        <div>
-            <div class="flex items-center justify-center flex-col">
-                <div class="font-bold text-xl"> "Count is {}" </div>
-                <button onclick={move |_| log::info!("button1 clicked!")}> "increment" </button>
-                <button onclick={move |_| log::info!("button2 clicked!")}> "decrement" </button>
-            </div>
-        </div>
+    log::info!("Ran component");
+    use dioxus::builder::*;
+    ctx.view(|b| {
+        div(b)
+            .child(text("hello"))
+            .listeners([on(b, "click", |_| {
+                //
+                log::info!("button1 clicked!");
+            })])
+            .finish()
     })
     })
+    // ctx.view(html! {
+    //     <div onclick={move |_| log::info!("button1 clicked!")}>
+    //         "Hello"
+    //         // <div class="flex items-center justify-center flex-col">
+    //         //     <div class="font-bold text-xl"> "Count is ..." </div>
+    //         //     <button onclick={move |_| log::info!("button1 clicked!")}> "increment" </button>
+    //         //     <button onclick={move |_| log::info!("button2 clicked!")}> "decrement" </button>
+    //         // </div>
+    //     </div>
+    // })
 };
 };

+ 92 - 57
packages/web/src/interpreter.rs

@@ -1,22 +1,42 @@
-use dioxus_core::changelist::Edit;
+use std::fmt::Debug;
+
+use dioxus_core::{changelist::Edit, events::EventTrigger};
 use fxhash::FxHashMap;
 use fxhash::FxHashMap;
 use log::debug;
 use log::debug;
 use wasm_bindgen::{closure::Closure, JsCast};
 use wasm_bindgen::{closure::Closure, JsCast};
-use web_sys::{window, Document, Element, Event, Node};
+use web_sys::{window, Document, Element, Event, HtmlInputElement, HtmlOptionElement, Node};
 
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 pub struct CacheId(u32);
 pub struct CacheId(u32);
 
 
+struct RootCallback(Box<dyn Fn(EventTrigger)>);
+impl std::fmt::Debug for RootCallback {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        todo!()
+    }
+}
+
 #[derive(Debug)]
 #[derive(Debug)]
 pub(crate) struct PatchMachine {
 pub(crate) struct PatchMachine {
-    container: Element,
     pub(crate) stack: Stack,
     pub(crate) stack: Stack,
+
+    root: Element,
+
     temporaries: FxHashMap<u32, Node>,
     temporaries: FxHashMap<u32, Node>,
-    callback: Option<Closure<dyn FnMut(&Event)>>,
+
+    // callback: RootCallback,
+    // callback: Option<Closure<dyn Fn(EventTrigger)>>,
     document: Document,
     document: Document,
-    // templates: FxHashMap<CacheId, Node>,
+
+    // every callback gets a monotomically increasing callback ID
+    callback_id: usize,
+
+    // Map of callback_id to component index and listener id
+    callback_map: FxHashMap<usize, (usize, usize)>,
 }
 }
 
 
+// templates: FxHashMap<CacheId, Node>,
+
 #[derive(Debug, Default)]
 #[derive(Debug, Default)]
 pub struct Stack {
 pub struct Stack {
     list: Vec<Node>,
     list: Vec<Node>,
@@ -30,13 +50,13 @@ impl Stack {
     }
     }
 
 
     pub fn push(&mut self, node: Node) {
     pub fn push(&mut self, node: Node) {
-        debug!("stack-push: {:?}", node);
+        // debug!("stack-push: {:?}", node);
         self.list.push(node);
         self.list.push(node);
     }
     }
 
 
     pub fn pop(&mut self) -> Node {
     pub fn pop(&mut self) -> Node {
         let res = self.list.pop().unwrap();
         let res = self.list.pop().unwrap();
-        debug!("stack-pop: {:?}", res);
+        // debug!("stack-pop: {:?}", res);
 
 
         res
         res
     }
     }
@@ -46,10 +66,10 @@ impl Stack {
     }
     }
 
 
     pub fn top(&self) -> &Node {
     pub fn top(&self) -> &Node {
-        log::info!(
-            "Called top of stack with {} items remaining",
-            self.list.len()
-        );
+        // log::info!(
+        //     "Called top of stack with {} items remaining",
+        //     self.list.len()
+        // );
         match self.list.last() {
         match self.list.last() {
             Some(a) => a,
             Some(a) => a,
             None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
             None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
@@ -58,19 +78,23 @@ impl Stack {
 }
 }
 
 
 impl PatchMachine {
 impl PatchMachine {
-    pub fn new(container: Element) -> Self {
+    pub fn new(root: Element, event_callback: impl Fn(EventTrigger)) -> Self {
         let document = window()
         let document = window()
             .expect("must have access to the window")
             .expect("must have access to the window")
             .document()
             .document()
             .expect("must have access to the Document");
             .expect("must have access to the Document");
 
 
+        // attach all listeners to the container element
+
+        // templates: Default::default(),
         Self {
         Self {
-            // templates: Default::default(),
-            container,
+            root,
             stack: Stack::with_capacity(20),
             stack: Stack::with_capacity(20),
             temporaries: Default::default(),
             temporaries: Default::default(),
-            callback: None,
+            // callback: None,
             document,
             document,
+            callback_id: 0,
+            callback_map: FxHashMap::default(),
         }
         }
     }
     }
 
 
@@ -81,7 +105,7 @@ impl PatchMachine {
     }
     }
 
 
     pub fn start(&mut self) {
     pub fn start(&mut self) {
-        if let Some(child) = self.container.first_child() {
+        if let Some(child) = self.root.first_child() {
             self.stack.push(child);
             self.stack.push(child);
         }
         }
     }
     }
@@ -96,9 +120,9 @@ impl PatchMachine {
         // self.templates.get(&id)
         // self.templates.get(&id)
     }
     }
 
 
-    pub fn init_events_trampoline(&mut self, _trampoline: ()) {
-        todo!("Event trampoline not a thing anymore")
-        // pub fn init_events_trampoline(&mut self, mut trampoline: EventsTrampoline) {
+    /// On any listener wakeup, find the listener that generated the event from th e attribute
+    // pub fn init_events_trampoline(&mut self, _trampoline: ()) {
+    pub fn init_events_trampoline(&mut self, event_channel: impl Fn(EventTrigger)) {
         // self.callback = Some(Closure::wrap(Box::new(move |event: &web_sys::Event| {
         // self.callback = Some(Closure::wrap(Box::new(move |event: &web_sys::Event| {
         //     let target = event
         //     let target = event
         //         .target()
         //         .target()
@@ -107,12 +131,12 @@ impl PatchMachine {
         //         .expect("not a valid element");
         //         .expect("not a valid element");
         //     let typ = event.type_();
         //     let typ = event.type_();
         //     let a: u32 = target
         //     let a: u32 = target
-        //         .get_attribute(&format!("dodrio-a-{}", typ))
+        //         .get_attribute(&format!("dioxus-a-{}", typ))
         //         .and_then(|v| v.parse().ok())
         //         .and_then(|v| v.parse().ok())
         //         .unwrap_or_default();
         //         .unwrap_or_default();
 
 
         //     let b: u32 = target
         //     let b: u32 = target
-        //         .get_attribute(&format!("dodrio-b-{}", typ))
+        //         .get_attribute(&format!("dioxus-b-{}", typ))
         //         .and_then(|v| v.parse().ok())
         //         .and_then(|v| v.parse().ok())
         //         .unwrap_or_default();
         //         .unwrap_or_default();
 
 
@@ -180,40 +204,44 @@ impl PatchMachine {
             Edit::SetAttribute { name, value } => {
             Edit::SetAttribute { name, value } => {
                 let node = self.stack.top();
                 let node = self.stack.top();
 
 
-                if let Some(node) = node.dyn_ref::<Element>() {
+                if let Some(node) = node.dyn_ref::<HtmlInputElement>() {
                     node.set_attribute(name, value).unwrap();
                     node.set_attribute(name, value).unwrap();
 
 
                     // Some attributes are "volatile" and don't work through `setAttribute`.
                     // Some attributes are "volatile" and don't work through `setAttribute`.
-                    // TODO:
-                    // if name == "value" {
-                    //     node.set_value(value);
-                    // }
-                    // if name == "checked" {
-                    //     node.set_checked(true);
-                    // }
-                    // if name == "selected" {
-                    //     node.set_selected(true);
-                    // }
+                    if name == "value" {
+                        node.set_value(value);
+                    }
+                    if name == "checked" {
+                        node.set_checked(true);
+                    }
+                }
+
+                if let Some(node) = node.dyn_ref::<HtmlOptionElement>() {
+                    if name == "selected" {
+                        node.set_selected(true);
+                    }
                 }
                 }
             }
             }
 
 
             // 4
             // 4
             Edit::RemoveAttribute { name } => {
             Edit::RemoveAttribute { name } => {
                 let node = self.stack.top();
                 let node = self.stack.top();
-                if let Some(node) = node.dyn_ref::<Element>() {
+                if let Some(node) = node.dyn_ref::<HtmlInputElement>() {
                     node.remove_attribute(name).unwrap();
                     node.remove_attribute(name).unwrap();
 
 
                     // Some attributes are "volatile" and don't work through `removeAttribute`.
                     // Some attributes are "volatile" and don't work through `removeAttribute`.
-                    // TODO:
-                    // if name == "value" {
-                    //     node.set_value("");
-                    // }
-                    // if name == "checked" {
-                    //     node.set_checked(false);
-                    // }
-                    // if name == "selected" {
-                    //     node.set_selected(false);
-                    // }
+                    if name == "value" {
+                        node.set_value("");
+                    }
+                    if name == "checked" {
+                        node.set_checked(false);
+                    }
+                }
+
+                if let Some(node) = node.dyn_ref::<HtmlOptionElement>() {
+                    if name == "selected" {
+                        node.set_selected(true);
+                    }
                 }
                 }
             }
             }
 
 
@@ -266,29 +294,36 @@ impl PatchMachine {
 
 
             // 11
             // 11
             Edit::NewEventListener { event_type, a, b } => {
             Edit::NewEventListener { event_type, a, b } => {
+                // attach the correct attributes to the element
+                // these will be used by accessing the event's target
+                // This ensures we only ever have one handler attached to the root, but decide
+                // dynamically when we want to call a listener.
+
                 let el = self.stack.top();
                 let el = self.stack.top();
 
 
                 let el = el
                 let el = el
                     .dyn_ref::<Element>()
                     .dyn_ref::<Element>()
                     .expect(&format!("not an element: {:?}", el));
                     .expect(&format!("not an element: {:?}", el));
-                el.add_event_listener_with_callback(
-                    event_type,
-                    self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
-                )
-                .unwrap();
+                // el.add_event_listener_with_callback(
+                //     event_type,
+                //     self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
+                // )
+                // .unwrap();
                 debug!("adding attributes: {}, {}", a, b);
                 debug!("adding attributes: {}, {}", a, b);
-                el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
+                el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
                     .unwrap();
                     .unwrap();
-                el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
+                el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
                     .unwrap();
                     .unwrap();
             }
             }
 
 
             // 12
             // 12
             Edit::UpdateEventListener { event_type, a, b } => {
             Edit::UpdateEventListener { event_type, a, b } => {
+                // update our internal mapping, and then modify the attribute
+
                 if let Some(el) = self.stack.top().dyn_ref::<Element>() {
                 if let Some(el) = self.stack.top().dyn_ref::<Element>() {
-                    el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
+                    el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
                         .unwrap();
                         .unwrap();
-                    el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
+                    el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
                         .unwrap();
                         .unwrap();
                 }
                 }
             }
             }
@@ -296,11 +331,11 @@ impl PatchMachine {
             // 13
             // 13
             Edit::RemoveEventListener { event_type } => {
             Edit::RemoveEventListener { event_type } => {
                 if let Some(el) = self.stack.top().dyn_ref::<Element>() {
                 if let Some(el) = self.stack.top().dyn_ref::<Element>() {
-                    el.remove_event_listener_with_callback(
-                        event_type,
-                        self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
-                    )
-                    .unwrap();
+                    // el.remove_event_listener_with_callback(
+                    //     event_type,
+                    //     self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
+                    // )
+                    // .unwrap();
                 }
                 }
             }
             }
 
 

+ 5 - 5
packages/web/src/lib.rs

@@ -62,16 +62,16 @@ impl WebsysRenderer {
         let (sender, mut receiver) = mpsc::unbounded::<EventTrigger>();
         let (sender, mut receiver) = mpsc::unbounded::<EventTrigger>();
 
 
         let body_element = prepare_websys_dom();
         let body_element = prepare_websys_dom();
-        let mut patch_machine = interpreter::PatchMachine::new(body_element.clone());
+        let mut patch_machine = interpreter::PatchMachine::new(body_element.clone(), |_| {});
         let root_node = body_element.first_child().unwrap();
         let root_node = body_element.first_child().unwrap();
         patch_machine.stack.push(root_node);
         patch_machine.stack.push(root_node);
 
 
         // todo: initialize the event registry properly on the root
         // todo: initialize the event registry properly on the root
 
 
-        self.internal_dom
-            .rebuild()?
-            .iter()
-            .for_each(|edit| patch_machine.handle_edit(edit));
+        self.internal_dom.rebuild()?.iter().for_each(|edit| {
+            log::debug!("patching with  {:?}", edit);
+            patch_machine.handle_edit(edit);
+        });
 
 
         // Event loop waits for the receiver to finish up
         // Event loop waits for the receiver to finish up
         // TODO! Connect the sender to the virtual dom's suspense system
         // TODO! Connect the sender to the virtual dom's suspense system