Feat: begin WIP on html macro
This commit is contained in:
1 parent
b0a87e5d73
commit
a8b1225c48
11 files changed
+255
-102
No files matched your search
@@ -19,11 +19,9 @@
|
||||
//!
|
||||
//!
|
||||
|
||||
|
||||
|
||||
use bumpalo::Bump;
|
||||
|
||||
use crate::innerlude::{Listener};
|
||||
use crate::innerlude::Listener;
|
||||
|
||||
/// The `Edit` represents a single modifcation of the renderer tree.
|
||||
///
|
||||
@@ -308,14 +306,19 @@ impl<'a> EditMachine<'a> {
|
||||
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());
|
||||
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);
|
||||
// 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) {
|
||||
@@ -326,19 +329,25 @@ impl<'a> EditMachine<'a> {
|
||||
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);
|
||||
}
|
||||
|
||||
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());
|
||||
self.emitter
|
||||
.push(Edit::RemoveEventListener { event_type: 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());
|
||||
}
|
||||
|
||||
|
||||
@@ -63,13 +63,9 @@ pub struct DiffMachine<'a> {
|
||||
need_to_diff: FxHashSet<Index>,
|
||||
}
|
||||
|
||||
enum NeedToDiff {
|
||||
PropsChanged,
|
||||
Subscription,
|
||||
}
|
||||
|
||||
impl<'a> DiffMachine<'a> {
|
||||
pub fn new(bump: &'a Bump) -> Self {
|
||||
log::debug!("starsting diff machine");
|
||||
Self {
|
||||
change_list: EditMachine::new(bump),
|
||||
immediate_queue: Vec::new(),
|
||||
@@ -83,6 +79,7 @@ impl<'a> DiffMachine<'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.
|
||||
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,
|
||||
namespace,
|
||||
}) => {
|
||||
log::info!("Creating {:#?}", node);
|
||||
if let Some(namespace) = namespace {
|
||||
self.change_list.create_element_ns(tag_name, namespace);
|
||||
} else {
|
||||
@@ -1001,7 +999,6 @@ enum KeyedPrefixResult {
|
||||
}
|
||||
|
||||
mod support {
|
||||
|
||||
|
||||
// // Get or create the template.
|
||||
// //
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//! The goal here is to provide a consistent event interface across all renderer types
|
||||
use generational_arena::Index;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EventTrigger {
|
||||
pub component_id: Index,
|
||||
pub listener_id: u32,
|
||||
@@ -18,6 +19,7 @@ impl EventTrigger {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VirtualEvent {
|
||||
// Real events
|
||||
ClipboardEvent(ClipboardEvent),
|
||||
@@ -42,19 +44,35 @@ pub enum VirtualEvent {
|
||||
|
||||
// these should reference the underlying event
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClipboardEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct CompositionEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct KeyboardEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct FocusEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct FormEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct GenericEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct MouseEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct PointerEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct SelectionEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct TouchEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct UIEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct WheelEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct MediaEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct ImageEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct AnimationEvent {}
|
||||
#[derive(Debug)]
|
||||
pub struct TransitionEvent {}
|
||||
@@ -1070,7 +1070,8 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
|
||||
/// // 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,
|
||||
event: &'static str,
|
||||
callback: impl Fn(()) + 'a,
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
//!
|
||||
//! These VNodes should be *very* cheap and *very* fast to construct - building a full tree should be insanely quick.
|
||||
|
||||
|
||||
|
||||
use bumpalo::Bump;
|
||||
pub use vcomponent::VComponent;
|
||||
pub use velement::VElement;
|
||||
@@ -97,7 +95,7 @@ mod vnode {
|
||||
|
||||
mod velement {
|
||||
use super::*;
|
||||
use std::{fmt::Debug};
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VElement<'a> {
|
||||
@@ -199,6 +197,29 @@ mod velement {
|
||||
.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.
|
||||
///
|
||||
@@ -265,9 +286,7 @@ mod vtext {
|
||||
/// Only supports the functional syntax
|
||||
mod vcomponent {
|
||||
use crate::innerlude::FC;
|
||||
use std::{marker::PhantomData};
|
||||
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VComponent<'src> {
|
||||
|
||||
@@ -219,10 +219,29 @@ impl ActiveFrame {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
// #[cfg(test)]
|
||||
mod tests {
|
||||
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]
|
||||
fn test_scope() {
|
||||
let example: FC<()> = |ctx, props| {
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
//!
|
||||
//! TODO:
|
||||
//! - [ ] Support for VComponents
|
||||
//! - [ ] Support for inline format in text
|
||||
//! - [ ] Support for expressions in attribute positions
|
||||
//! - [ ] Support for iterators
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
|
||||
use ::{
|
||||
proc_macro::TokenStream,
|
||||
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]
|
||||
pub fn html(s: TokenStream) -> TokenStream {
|
||||
let html: HtmlRender = match syn::parse(s) {
|
||||
@@ -19,8 +36,10 @@ pub fn html(s: TokenStream) -> TokenStream {
|
||||
html.to_token_stream().into()
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Parse any stream coming from the html! macro
|
||||
// ==============================================
|
||||
struct HtmlRender {
|
||||
// ctx: Ident,
|
||||
kind: NodeOrList,
|
||||
}
|
||||
|
||||
@@ -58,6 +77,9 @@ impl ToTokens for HtmlRender {
|
||||
}
|
||||
}
|
||||
|
||||
/// =============================================
|
||||
/// Parse any child as a node or list of nodes
|
||||
/// =============================================
|
||||
enum NodeOrList {
|
||||
Node(Node),
|
||||
List(NodeList),
|
||||
@@ -115,6 +137,9 @@ impl Parse for Node {
|
||||
}
|
||||
}
|
||||
|
||||
/// =======================================
|
||||
/// Parse the VNode::Element type
|
||||
/// =======================================
|
||||
struct Element {
|
||||
name: Ident,
|
||||
attrs: Vec<Attr>,
|
||||
@@ -214,6 +239,9 @@ impl Parse for Element {
|
||||
}
|
||||
}
|
||||
|
||||
/// =======================================
|
||||
/// Parse a VElement's Attributes
|
||||
/// =======================================
|
||||
struct Attr {
|
||||
name: Ident,
|
||||
ty: AttrType,
|
||||
@@ -285,6 +313,10 @@ enum AttrType {
|
||||
// todo Bool(MaybeExpr<LitBool>)
|
||||
}
|
||||
|
||||
/// =======================================
|
||||
/// Parse just plain text
|
||||
/// =======================================
|
||||
///
|
||||
struct TextNode(MaybeExpr<LitStr>);
|
||||
|
||||
impl Parse for TextNode {
|
||||
|
||||
@@ -28,6 +28,7 @@ features = [
|
||||
"Document",
|
||||
"Element",
|
||||
"HtmlElement",
|
||||
"HtmlInputElement",
|
||||
"EventTarget",
|
||||
"HtmlCollection",
|
||||
"Node",
|
||||
@@ -39,6 +40,7 @@ features = [
|
||||
"InputEvent",
|
||||
"DocumentType",
|
||||
"CharacterData",
|
||||
"HtmlOptionElement",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
|
||||
@@ -4,17 +4,38 @@ use dioxus_core::prelude::*;
|
||||
use dioxus_web::*;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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>
|
||||
// })
|
||||
};
|
||||
@@ -1,22 +1,42 @@
|
||||
use dioxus_core::changelist::Edit;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use dioxus_core::{changelist::Edit, events::EventTrigger};
|
||||
use fxhash::FxHashMap;
|
||||
use log::debug;
|
||||
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)]
|
||||
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)]
|
||||
pub(crate) struct PatchMachine {
|
||||
container: Element,
|
||||
pub(crate) stack: Stack,
|
||||
|
||||
root: Element,
|
||||
|
||||
temporaries: FxHashMap<u32, Node>,
|
||||
callback: Option<Closure<dyn FnMut(&Event)>>,
|
||||
|
||||
// callback: RootCallback,
|
||||
// callback: Option<Closure<dyn Fn(EventTrigger)>>,
|
||||
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)]
|
||||
pub struct Stack {
|
||||
list: Vec<Node>,
|
||||
@@ -30,13 +50,13 @@ impl Stack {
|
||||
}
|
||||
|
||||
pub fn push(&mut self, node: Node) {
|
||||
debug!("stack-push: {:?}", node);
|
||||
// debug!("stack-push: {:?}", node);
|
||||
self.list.push(node);
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Node {
|
||||
let res = self.list.pop().unwrap();
|
||||
debug!("stack-pop: {:?}", res);
|
||||
// debug!("stack-pop: {:?}", res);
|
||||
|
||||
res
|
||||
}
|
||||
@@ -46,10 +66,10 @@ impl Stack {
|
||||
}
|
||||
|
||||
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() {
|
||||
Some(a) => a,
|
||||
None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
|
||||
@@ -58,19 +78,23 @@ impl Stack {
|
||||
}
|
||||
|
||||
impl PatchMachine {
|
||||
pub fn new(container: Element) -> Self {
|
||||
pub fn new(root: Element, event_callback: impl Fn(EventTrigger)) -> Self {
|
||||
let document = window()
|
||||
.expect("must have access to the window")
|
||||
.document()
|
||||
.expect("must have access to the Document");
|
||||
|
||||
// attach all listeners to the container element
|
||||
|
||||
// templates: Default::default(),
|
||||
Self {
|
||||
// templates: Default::default(),
|
||||
container,
|
||||
root,
|
||||
stack: Stack::with_capacity(20),
|
||||
temporaries: Default::default(),
|
||||
callback: None,
|
||||
// callback: None,
|
||||
document,
|
||||
callback_id: 0,
|
||||
callback_map: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +105,7 @@ impl PatchMachine {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -96,9 +120,9 @@ impl PatchMachine {
|
||||
// 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| {
|
||||
// let target = event
|
||||
// .target()
|
||||
@@ -107,12 +131,12 @@ impl PatchMachine {
|
||||
// .expect("not a valid element");
|
||||
// let typ = event.type_();
|
||||
// let a: u32 = target
|
||||
// .get_attribute(&format!("dodrio-a-{}", typ))
|
||||
// .get_attribute(&format!("dioxus-a-{}", typ))
|
||||
// .and_then(|v| v.parse().ok())
|
||||
// .unwrap_or_default();
|
||||
|
||||
// let b: u32 = target
|
||||
// .get_attribute(&format!("dodrio-b-{}", typ))
|
||||
// .get_attribute(&format!("dioxus-b-{}", typ))
|
||||
// .and_then(|v| v.parse().ok())
|
||||
// .unwrap_or_default();
|
||||
|
||||
@@ -180,40 +204,44 @@ impl PatchMachine {
|
||||
Edit::SetAttribute { name, value } => {
|
||||
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();
|
||||
|
||||
// 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
|
||||
Edit::RemoveAttribute { name } => {
|
||||
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();
|
||||
|
||||
// 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
|
||||
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 = el
|
||||
.dyn_ref::<Element>()
|
||||
.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);
|
||||
el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
|
||||
el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
|
||||
.unwrap();
|
||||
el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
|
||||
el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// 12
|
||||
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>() {
|
||||
el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
|
||||
el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
|
||||
.unwrap();
|
||||
el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
|
||||
el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
@@ -296,11 +331,11 @@ impl PatchMachine {
|
||||
// 13
|
||||
Edit::RemoveEventListener { event_type } => {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,16 +62,16 @@ impl WebsysRenderer {
|
||||
let (sender, mut receiver) = mpsc::unbounded::<EventTrigger>();
|
||||
|
||||
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();
|
||||
patch_machine.stack.push(root_node);
|
||||
|
||||
// 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
|
||||
// TODO! Connect the sender to the virtual dom's suspense system
|
||||
|
||||
Reference in new issue
Block a user