From 32b45e5ba168390e338a343eef6baba5cca9468b Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 25 Feb 2021 18:44:00 -0500 Subject: [PATCH] Feat: move webview logic into library --- README.md | 9 + packages/core/src/context.rs | 1 - packages/core/src/scope.rs | 4 +- packages/core/src/virtual_dom.rs | 11 +- packages/web/src/interpreter.rs | 290 ++---------------- packages/web/src/lib.rs | 10 +- packages/webview/examples/demo.js | 3 - packages/webview/examples/demo.rs | 186 +++-------- packages/webview/{examples => src}/index.html | 41 +-- packages/webview/src/lib.rs | 208 ++++++++++--- 10 files changed, 249 insertions(+), 514 deletions(-) delete mode 100644 packages/webview/examples/demo.js rename packages/webview/{examples => src}/index.html (84%) diff --git a/README.md b/README.md index 42fbbb3ff..091fcabae 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust. ```rust + static Example: FC<()> = |ctx| { let (value, set_value) = use_state(&ctx, || "...?"); @@ -23,6 +24,7 @@ static Example: FC<()> = |ctx| { }) }; + ``` Dioxus can be used to deliver webapps, desktop apps, static pages, liveview apps, Android apps, iOS Apps, and more. At its core, Dioxus is entirely renderer agnostic and has great documentation for creating new renderers for any platform. @@ -86,3 +88,10 @@ Dioxus LiveHost is a paid service dedicated to hosting your Dioxus Apps - whethe For small teams, LiveHost is free 🎉. Check out the pricing page to see if Dioxus LiveHost is good fit for your team. + + + + + + + diff --git a/packages/core/src/context.rs b/packages/core/src/context.rs index 69c6ac1fb..e3e77df80 100644 --- a/packages/core/src/context.rs +++ b/packages/core/src/context.rs @@ -79,7 +79,6 @@ impl<'a> Context<'a> { let safe_nodes = lazy_nodes(self.bump); let unsafe_nodes = unsafe { std::mem::transmute::, VNode<'static>>(safe_nodes) }; self.final_nodes.deref().borrow_mut().replace(unsafe_nodes); - info!("lazy nodes have been generated"); DomTree {} } diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index 8fd737923..cc01f54d3 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -37,7 +37,7 @@ pub struct Scope { pub frames: ActiveFrame, // IE Which listeners need to be woken up? - pub listeners: Vec>, + pub listeners: Vec>, // lying, cheating reference >:( pub props: Box, @@ -55,7 +55,7 @@ impl Scope { // Capture the caller let caller = f as *const (); - let listeners: Vec> = vec![Box::new(|| { + let listeners: Vec> = vec![Box::new(|_| { log::info!("Base listener called"); })]; diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index ccfeb4b70..622e863aa 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -98,12 +98,7 @@ impl VirtualDom { component.run::<()>(); - let old = component.old_frame(); - let new = component.new_frame(); - dbg!(old); - dbg!(new); - - diff_machine.diff_node(old, new); + diff_machine.diff_node(component.old_frame(), component.new_frame()); Ok(diff_machine.consume()) } @@ -136,7 +131,7 @@ impl VirtualDom { let EventTrigger { component_id, listener_id, - event: _, + event: source, } = event; let component = self @@ -151,7 +146,7 @@ impl VirtualDom { .as_ref(); // Run the callback with the user event - listener(); + listener(source); // Mark dirty components. Descend from the highest node until all dirty nodes are updated. let mut affected_components = Vec::new(); diff --git a/packages/web/src/interpreter.rs b/packages/web/src/interpreter.rs index 60769850d..9ada480f2 100644 --- a/packages/web/src/interpreter.rs +++ b/packages/web/src/interpreter.rs @@ -1,6 +1,6 @@ use dioxus_core::changelist::Edit; use fxhash::FxHashMap; -use log::{debug}; +use log::debug; use wasm_bindgen::{closure::Closure, JsCast}; use web_sys::{window, Document, Element, Event, Node}; @@ -8,13 +8,13 @@ use web_sys::{window, Document, Element, Event, Node}; pub struct CacheId(u32); #[derive(Debug)] -pub struct PatchMachine { +pub(crate) struct PatchMachine { container: Element, - pub stack: Stack, + pub(crate) stack: Stack, temporaries: FxHashMap, - templates: FxHashMap, callback: Option>, document: Document, + // templates: FxHashMap, } #[derive(Debug, Default)] @@ -65,10 +65,10 @@ impl PatchMachine { .expect("must have access to the Document"); Self { + // templates: Default::default(), container, stack: Stack::with_capacity(20), temporaries: Default::default(), - templates: Default::default(), callback: None, document, } @@ -77,7 +77,7 @@ impl PatchMachine { pub fn unmount(&mut self) { self.stack.clear(); self.temporaries.clear(); - self.templates.clear(); + // self.templates.clear(); } pub fn start(&mut self) { @@ -92,7 +92,8 @@ impl PatchMachine { } pub fn get_template(&self, id: CacheId) -> Option<&Node> { - self.templates.get(&id) + todo!() + // self.templates.get(&id) } pub fn init_events_trampoline(&mut self, _trampoline: ()) { @@ -379,273 +380,22 @@ impl PatchMachine { } } - // // 0 - // pub fn set_text(&mut self, text: &str) { - // self.stack.top().set_text_content(Some(text)); + // // 24 + // pub fn save_template(&mut self, id: CacheId) { + // let template = self.stack.top(); + // let t = template.clone_node_with_deep(true).unwrap(); + // // self.templates.insert(id, t); // } - // // 1 - // pub fn remove_self_and_next_siblings(&mut self) { - // let node = self.stack.pop(); - // let mut sibling = node.next_sibling(); - - // while let Some(inner) = sibling { - // let temp = inner.next_sibling(); - // if let Some(sibling) = inner.dyn_ref::() { - // sibling.remove(); - // } - // sibling = temp; - // } - // if let Some(node) = node.dyn_ref::() { - // node.remove(); - // } - // } - - // // 2 - // pub fn replace_with(&mut self) { - // let new_node = self.stack.pop(); - // let old_node = self.stack.pop(); - - // if old_node.has_type::() { - // old_node - // .dyn_ref::() - // .unwrap() - // .replace_with_with_node_1(&new_node) - // .unwrap(); - // } else if old_node.has_type::() { - // old_node - // .dyn_ref::() - // .unwrap() - // .replace_with_with_node_1(&new_node) - // .unwrap(); - // } else if old_node.has_type::() { - // old_node - // .dyn_ref::() - // .unwrap() - // .replace_with_with_node_1(&new_node) - // .unwrap(); - // } else { - // panic!("Cannot replace node: {:?}", old_node); - // } - - // self.stack.push(new_node); - // } - - // // 3 - // pub fn set_attribute(&mut self, name: &str, value: &str) { - // let node = self.stack.top(); - - // if let Some(node) = node.dyn_ref::() { - // 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); - // // } - // } - // } - - // // 4 - // pub fn remove_attribute(&mut self, name: &str) { - // let node = self.stack.top(); - // if let Some(node) = node.dyn_ref::() { - // 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); - // // } - // } - // } - - // // 5 - // pub fn push_reverse_child(&mut self, n: u32) { - // let parent = self.stack.top(); - // let children = parent.child_nodes(); - // let child = children.get(children.length() - n - 1).unwrap(); - // self.stack.push(child); - // } - - // // 6 - // pub fn pop_push_child(&mut self, n: u32) { - // self.stack.pop(); - // let parent = self.stack.top(); - // let children = parent.child_nodes(); - // let child = children.get(n).unwrap(); - // self.stack.push(child); - // } - - // // 7 - // pub fn pop(&mut self) { - // self.stack.pop(); - // } - - // // 8 - // pub fn append_child(&mut self) { - // let child = self.stack.pop(); - // self.stack.top().append_child(&child).unwrap(); - // } - - // // 9 - // pub fn create_text_node(&mut self, text: &str) { - // self.stack.push( - // self.document - // .create_text_node(text) - // .dyn_into::() - // .unwrap(), - // ); - // } - - // // 10 - // pub fn create_element(&mut self, tag_name: &str) { - // let el = self - // .document - // .create_element(tag_name) - // .unwrap() - // .dyn_into::() - // .unwrap(); - // self.stack.push(el); - // } - - // // 11 - // pub fn new_event_listener(&mut self, event_type: &str, a: u32, b: u32) { - // let el = self.stack.top(); - - // let el = el - // .dyn_ref::() - // .expect(&format!("not an element: {:?}", el)); - // 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()) - // .unwrap(); - // el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string()) - // .unwrap(); - // } - - // // 12 - // pub fn update_event_listener(&mut self, event_type: &str, a: u32, b: u32) { - // if let Some(el) = self.stack.top().dyn_ref::() { - // el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string()) - // .unwrap(); - // el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string()) - // .unwrap(); - // } - // } - - // // 13 - // pub fn remove_event_listener(&mut self, event_type: &str) { - // if let Some(el) = self.stack.top().dyn_ref::() { - // el.remove_event_listener_with_callback( - // event_type, - // self.callback.as_ref().unwrap().as_ref().unchecked_ref(), - // ) - // .unwrap(); - // } - // } - - // // 16 - // pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) { - // let el = self - // .document - // .create_element_ns(Some(ns), tag_name) - // .unwrap() - // .dyn_into::() - // .unwrap(); - // self.stack.push(el); - // } - - // // 17 - // pub fn save_children_to_temporaries(&mut self, mut temp: u32, start: u32, end: u32) { - // let parent = self.stack.top(); - // let children = parent.child_nodes(); - // for i in start..end { - // self.temporaries.insert(temp, children.get(i).unwrap()); - // temp += 1; - // } - // } - - // // 18 - // pub fn push_child(&mut self, n: u32) { - // let parent = self.stack.top(); - // let child = parent.child_nodes().get(n).unwrap(); - // self.stack.push(child); - // } - - // // 19 - // pub fn push_temporary(&mut self, temp: u32) { - // let t = self.temporaries.get(&temp).unwrap().clone(); + // // 25 + // pub fn push_template(&mut self, id: CacheId) { + // let template = self.get_template(id).unwrap(); + // let t = template.clone_node_with_deep(true).unwrap(); // self.stack.push(t); // } - // // 20 - // pub fn insert_before(&mut self) { - // let before = self.stack.pop(); - // let after = self.stack.pop(); - // after - // .parent_node() - // .unwrap() - // .insert_before(&before, Some(&after)) - // .unwrap(); - // self.stack.push(before); + // pub fn has_template(&self, id: CacheId) -> bool { + // todo!() + // // self.templates.contains_key(&id) // } - - // // 21 - // pub fn pop_push_reverse_child(&mut self, n: u32) { - // self.stack.pop(); - // let parent = self.stack.top(); - // let children = parent.child_nodes(); - // let child = children.get(children.length() - n - 1).unwrap(); - // self.stack.push(child); - // } - - // // 22 - // pub fn remove_child(&mut self, n: u32) { - // let parent = self.stack.top(); - // if let Some(child) = parent.child_nodes().get(n).unwrap().dyn_ref::() { - // child.remove(); - // } - // } - - // // 23 - // pub fn set_class(&mut self, class_name: &str) { - // if let Some(el) = self.stack.top().dyn_ref::() { - // el.set_class_name(class_name); - // } - // } - - // 24 - pub fn save_template(&mut self, id: CacheId) { - let template = self.stack.top(); - let t = template.clone_node_with_deep(true).unwrap(); - self.templates.insert(id, t); - } - - // 25 - pub fn push_template(&mut self, id: CacheId) { - let template = self.get_template(id).unwrap(); - let t = template.clone_node_with_deep(true).unwrap(); - self.stack.push(t); - } - - pub fn has_template(&self, id: CacheId) -> bool { - self.templates.contains_key(&id) - } } diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index bb01d91ce..0d3c116ba 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -19,9 +19,6 @@ pub mod interpreter; /// pub struct WebsysRenderer { internal_dom: VirtualDom, - - // this should be a component index - _event_map: FxHashMap<(u32, u32), u32>, } impl WebsysRenderer { @@ -58,10 +55,7 @@ impl WebsysRenderer { /// Create a new text renderer from an existing Virtual DOM. pub fn from_vdom(dom: VirtualDom) -> Self { // todo: initialize the event registry properly - Self { - internal_dom: dom, - _event_map: FxHashMap::default(), - } + Self { internal_dom: dom } } pub async fn run(&mut self) -> dioxus_core::error::Result<()> { @@ -72,7 +66,7 @@ impl WebsysRenderer { let root_node = body_element.first_child().unwrap(); patch_machine.stack.push(root_node); - // todo: initialize the event registry properly on the root element + // todo: initialize the event registry properly on the root self.internal_dom .rebuild()? diff --git a/packages/webview/examples/demo.js b/packages/webview/examples/demo.js deleted file mode 100644 index 3b6535bfb..000000000 --- a/packages/webview/examples/demo.js +++ /dev/null @@ -1,3 +0,0 @@ -// This file interperets incoming edit messages into the page and renders them. -// This is written in javascript to be slightly easier to work with (instead of having to pre-compile the wasm) -// One day, we'll probably using wasmbindgen for the inner, but a javascripty one is fine too. diff --git a/packages/webview/examples/demo.rs b/packages/webview/examples/demo.rs index 417c57240..92cf8ae13 100644 --- a/packages/webview/examples/demo.rs +++ b/packages/webview/examples/demo.rs @@ -1,152 +1,52 @@ //! An example where the dioxus vdom is running in a native thread, interacting with webview +//! Content is passed from the native thread into the webview -use std::{ - borrow::BorrowMut, - rc::Rc, - sync::{mpsc::channel, Arc}, -}; +use dioxus_core::prelude::*; -// use async_std::{channel, task::block_on}; - -use dioxus_core::{dodriodiff::DiffMachine, prelude::bumpalo::Bump, prelude::*, scope}; -use scope::Scope; -use web_view::Handle; -static HTML_CONTENT: &'static str = include_str!("./index.html"); - -enum InnerEvent { - Initiate(Handle<()>), -} - -// async_std::task::spawn(async { -// #[async_std::main] -fn main() -> anyhow::Result<()> { - let (sender, receiver) = channel::(); - // let (sender, receiver) = channel::unbounded::(); - - // let task = async_std::task::spawn(async move { - let mut view = web_view::builder() - .title("My Project") - .content(web_view::Content::Html(HTML_CONTENT)) - .size(320, 480) - .resizable(true) - .debug(true) - .user_data(()) - .invoke_handler(|view, arg| { - // todo: handle events here - println!("handling invoker"); - let handle = view.handle(); - sender.send(InnerEvent::Initiate(handle)); - Ok(()) - }) - .build() - .unwrap(); - - println!("building the diff"); - let bump = Bump::new(); - let mut diff_machine = DiffMachine::new(&bump); - let old = html! {
}(&bump); - - // let mut scope = Scope::new(TEST, (), None); - // scope.run::<()>(); - let new = html! { -
-
-
-
- // Title -
- "Jon's awesome site!!11" -
- - // Subtext / description -
- "He worked so hard on it :)" -
- -
- // Main number -
- "1337" +fn main(){ + dioxus_webview::launch( + // Customize the webview + |builder| { + builder + .title("Test Dioxus App") + .size(320, 480) + .resizable(true) + .debug(true) + }, + // Props + (), + // Draw the root component + |ctx, _props| { + ctx.view(html! { +
+
+
+
+ // Title +
"Jon's awesome site!!11"
+ + // Subtext / description +
"He worked so hard on it :)"
+ +
+ // Main number +
+ "1337" +
+
+ + // Try another +
- - // Try another -
-
-
- }(&bump); - - diff_machine.diff_node(&old, &new); - - let edits = diff_machine.consume(); - let ready_edits = serde_json::to_string(&edits)?; - let ref_edits = Arc::new(ready_edits); - - loop { - view.step().expect("should not fail"); - // if let Some(evt) = receiver.try_recv() {} - if let Ok(event) = receiver.try_recv() { - match event { - InnerEvent::Initiate(handle) => { - // println!("awesome, things worked"); - let ediits = ref_edits.clone(); - // println!("{}", ediits); - handle - .dispatch(move |view| { - view.eval(format!("EditListReceived(`{}`);", ediits).as_str())?; - - Ok(()) - }) - .expect("Dispatch failed"); - // let g = handle.(); - } - } - } - // let event = receiver.try_recv(); - - // view.eval("alert('omg');")?; - // view.step().expect("webview should not fail")?; - } + }) + }, + ).expect("Webview finished"); } -// static TEST: FC<()> = |ctx, props| { -// ctx.view(html! { -//
-//
-//
-//
-// // Title -//
-// "Jon's awesome site!!11" -//
- -// // Subtext / description -//
-// "He worked so hard on it :)" -//
- -//
-// // Main number -//
-// "1337" -//
-//
- -// // Try another -// -//
-//
-//
-//
-// }) -// }; diff --git a/packages/webview/examples/index.html b/packages/webview/src/index.html similarity index 84% rename from packages/webview/examples/index.html rename to packages/webview/src/index.html index d38b856d9..1fa75f741 100644 --- a/packages/webview/examples/index.html +++ b/packages/webview/src/index.html @@ -12,34 +12,6 @@