Feat: desktop app wired up

This commit is contained in:
Jonathan Kelley committed 2021-02-18 20:04:25 -05:00
1 parent bcbb93b697
commit b3e6886351
10 files changed
+744 -269

No files matched your search

+13 -7
View File
@@ -19,6 +19,8 @@
//! //!
//! //!
use std::ops::{Deref, DerefMut};
use bumpalo::Bump; use bumpalo::Bump;
use crate::innerlude::{Listener, VirtualDom}; use crate::innerlude::{Listener, VirtualDom};
@@ -32,8 +34,9 @@ use crate::innerlude::{Listener, VirtualDom};
/// ///
/// ///
/// ///
/// /// todo@ jon: allow serde to be optional
#[derive(Debug)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
pub enum Edit<'d> { pub enum Edit<'d> {
SetText { text: &'d str }, SetText { text: &'d str },
RemoveSelfAndNextSiblings {}, RemoveSelfAndNextSiblings {},
@@ -59,20 +62,23 @@ pub enum Edit<'d> {
SetClass { class_name: &'d str }, SetClass { class_name: &'d str },
} }
pub struct EditList<'src> { pub type EditList<'src> = Vec<Edit<'src>>;
pub struct EditMachine<'src> {
pub traversal: Traversal, pub traversal: Traversal,
next_temporary: u32, next_temporary: u32,
forcing_new_listeners: bool, forcing_new_listeners: bool,
pub emitter: Vec<Edit<'src>>,
pub emitter: EditList<'src>,
} }
impl<'b> EditList<'b> { impl<'b> EditMachine<'b> {
pub fn new(bump: &'b Bump) -> Self { pub fn new(bump: &'b Bump) -> Self {
Self { Self {
traversal: Traversal::new(), traversal: Traversal::new(),
next_temporary: 0, next_temporary: 0,
forcing_new_listeners: false, forcing_new_listeners: false,
emitter: Vec::new(), emitter: EditList::default(),
} }
} }
@@ -153,7 +159,7 @@ impl<'b> EditList<'b> {
} }
} }
impl<'a> EditList<'a> { impl<'a> EditMachine<'a> {
pub fn next_temporary(&self) -> u32 { pub fn next_temporary(&self) -> u32 {
self.next_temporary self.next_temporary
} }
+4 -4
View File
@@ -37,7 +37,7 @@ use fxhash::{FxHashMap, FxHashSet};
use generational_arena::Index; use generational_arena::Index;
use crate::{ use crate::{
changelist::{Edit, EditList}, changelist::{Edit, EditList, EditMachine},
innerlude::{Attribute, Listener, Scope, VElement, VNode, VText}, innerlude::{Attribute, Listener, Scope, VElement, VNode, VText},
virtual_dom::LifecycleEvent, virtual_dom::LifecycleEvent,
}; };
@@ -57,7 +57,7 @@ use std::cmp::Ordering;
/// that were modified by the eventtrigger. This prevents doubly evaluating components if they wereboth updated via /// that were modified by the eventtrigger. This prevents doubly evaluating components if they wereboth updated via
/// subscriptions and props changes. /// subscriptions and props changes.
pub struct DiffMachine<'a> { pub struct DiffMachine<'a> {
pub change_list: EditList<'a>, pub change_list: EditMachine<'a>,
immediate_queue: Vec<Index>, immediate_queue: Vec<Index>,
diffed: FxHashSet<Index>, diffed: FxHashSet<Index>,
need_to_diff: FxHashSet<Index>, need_to_diff: FxHashSet<Index>,
@@ -71,14 +71,14 @@ enum NeedToDiff {
impl<'a> DiffMachine<'a> { impl<'a> DiffMachine<'a> {
pub fn new(bump: &'a Bump) -> Self { pub fn new(bump: &'a Bump) -> Self {
Self { Self {
change_list: EditList::new(bump), change_list: EditMachine::new(bump),
immediate_queue: Vec::new(), immediate_queue: Vec::new(),
diffed: FxHashSet::default(), diffed: FxHashSet::default(),
need_to_diff: FxHashSet::default(), need_to_diff: FxHashSet::default(),
} }
} }
pub fn consume(self) -> Vec<Edit<'a>> { pub fn consume(self) -> EditList<'a> {
self.change_list.emitter self.change_list.emitter
} }
+5
View File
@@ -19,6 +19,11 @@ impl EventTrigger {
} }
pub enum VirtualEvent { pub enum VirtualEvent {
// the event to drain the current lifecycle queue
// Used to initate the dom
InitiateEvent,
// Real events
ClipboardEvent, ClipboardEvent,
CompositionEvent, CompositionEvent,
KeyboardEvent, KeyboardEvent,
+16 -20
View File
@@ -21,7 +21,8 @@ use std::{
/// ///
/// Scopes are allocated in a generational arena. As components are mounted/unmounted, they will replace slots of dead components. /// Scopes are allocated in a generational arena. As components are mounted/unmounted, they will replace slots of dead components.
/// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently. /// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently.
pub(crate) struct Scope { pub struct Scope {
// pub(crate) struct Scope {
// TODO @Jon // TODO @Jon
// These hooks are actually references into the hook arena // These hooks are actually references into the hook arena
// These two could be combined with "OwningRef" to remove unsafe usage // These two could be combined with "OwningRef" to remove unsafe usage
@@ -50,23 +51,10 @@ pub(crate) struct Scope {
pub caller: *const i32, pub caller: *const i32,
} }
// pub enum ActiveFrame {
// First,
// Second,
// }
// impl ActiveFrame {
// fn next(&mut self) {
// match self {
// ActiveFrame::First => *self = ActiveFrame::Second,
// ActiveFrame::Second => *self = ActiveFrame::First,
// }
// }
// }
impl Scope { impl Scope {
// create a new scope from a function // create a new scope from a function
pub(crate) fn new<T: 'static>( pub fn new<T: 'static>(
// pub(crate) fn new<T: 'static>(
f: FC<T>, f: FC<T>,
props: impl Properties + 'static, props: impl Properties + 'static,
parent: Option<Index>, parent: Option<Index>,
@@ -120,7 +108,7 @@ impl Scope {
/// This function downcasts the function pointer based on the stored props_type /// This function downcasts the function pointer based on the stored props_type
/// ///
/// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized) /// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
pub(crate) fn run<'bump, P: Properties + Sized + 'static>(&'bump mut self) { pub fn run<'bump, P: Properties + Sized + 'static>(&'bump mut self) {
let frame = { let frame = {
let frame = self.frames.next(); let frame = self.frames.next();
frame.bump.reset(); frame.bump.reset();
@@ -164,14 +152,12 @@ impl Scope {
let unsafe_node = unsafe { std::mem::transmute::<VNode<'bump>, VNode<'static>>(nodes) }; let unsafe_node = unsafe { std::mem::transmute::<VNode<'bump>, VNode<'static>>(nodes) };
frame.head_node = unsafe_node; frame.head_node = unsafe_node;
todo!()
} }
/// Accessor to get the root node and its children (safely)\ /// Accessor to get the root node and its children (safely)\
/// Scope is self-referntial, so we are forced to use the 'static lifetime to cheat /// Scope is self-referntial, so we are forced to use the 'static lifetime to cheat
pub fn current_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> { pub fn current_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> {
todo!() self.frames.current_head_node()
} }
pub fn prev_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> { pub fn prev_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> {
todo!() todo!()
@@ -196,6 +182,16 @@ impl ActiveFrame {
} }
} }
fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
let cur_idx = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);
let raw_node = &self.frames[cur_idx];
unsafe {
let unsafe_head = &raw_node.head_node;
let safe_node = std::mem::transmute::<&VNode<'static>, &VNode<'b>>(unsafe_head);
safe_node
}
}
fn next(&mut self) -> &mut BumpFrame { fn next(&mut self) -> &mut BumpFrame {
self.idx.fetch_add(1, std::sync::atomic::Ordering::Relaxed); self.idx.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let cur = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed); let cur = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);
+9 -7
View File
@@ -1,8 +1,9 @@
// use crate::{changelist::EditList, nodes::VNode}; // use crate::{changelist::EditList, nodes::VNode};
use crate::{dodriodiff::DiffMachine, nodes::VNode}; use crate::{changelist::{self, EditList}, dodriodiff::DiffMachine, nodes::VNode};
use crate::{events::EventTrigger, innerlude::*}; use crate::{events::EventTrigger, innerlude::*};
use any::Any; use any::Any;
use bumpalo::Bump; use bumpalo::Bump;
use changelist::EditMachine;
use generational_arena::{Arena, Index}; use generational_arena::{Arena, Index};
use std::{ use std::{
any::{self, TypeId}, any::{self, TypeId},
@@ -105,6 +106,10 @@ impl VirtualDom {
/// This lets services external to the virtual dom interact directly with the component and event system. /// This lets services external to the virtual dom interact directly with the component and event system.
pub fn queue_update() {} pub fn queue_update() {}
pub fn start(&mut self) -> Result<EditList> {
todo!()
}
/// Pop an event off the event queue and process it /// Pop an event off the event queue and process it
/// Update the root props, and progress /// Update the root props, and progress
/// Takes a bump arena to allocate into, making the diff phase as fast as possible /// Takes a bump arena to allocate into, making the diff phase as fast as possible
@@ -115,7 +120,7 @@ impl VirtualDom {
.borrow_mut() .borrow_mut()
.pop_front() .pop_front()
.ok_or(Error::NoEvent)?; .ok_or(Error::NoEvent)?;
self.process_event(event) self.process_lifecycle(event)
} }
/// This method is the most sophisticated way of updating the virtual dom after an external event has been triggered. /// This method is the most sophisticated way of updating the virtual dom after an external event has been triggered.
@@ -171,7 +176,7 @@ impl VirtualDom {
new_evt new_evt
} { } {
affected_components.push(event.component_index); affected_components.push(event.component_index);
self.process_event(event)?; self.process_lifecycle(event)?;
} }
let diff_bump = Bump::new(); let diff_bump = Bump::new();
@@ -180,9 +185,6 @@ impl VirtualDom {
Ok(()) Ok(())
} }
pub async fn progress_completely(&mut self) -> Result<()> {
Ok(())
}
/// Using mutable access to the Virtual Dom, progress a given lifecycle event /// Using mutable access to the Virtual Dom, progress a given lifecycle event
/// ///
/// ///
@@ -190,7 +192,7 @@ impl VirtualDom {
/// ///
/// ///
/// ///
fn process_event( fn process_lifecycle(
&mut self, &mut self,
LifecycleEvent { LifecycleEvent {
component_index: index, component_index: index,
+223 -223
View File
@@ -380,257 +380,257 @@ impl PatchMachine {
} }
} }
// 0 // // 0
pub fn set_text(&mut self, text: &str) { // pub fn set_text(&mut self, text: &str) {
self.stack.top().set_text_content(Some(text)); // self.stack.top().set_text_content(Some(text));
} // }
// 1 // // 1
pub fn remove_self_and_next_siblings(&mut self) { // pub fn remove_self_and_next_siblings(&mut self) {
let node = self.stack.pop(); // let node = self.stack.pop();
let mut sibling = node.next_sibling(); // let mut sibling = node.next_sibling();
while let Some(inner) = sibling { // while let Some(inner) = sibling {
let temp = inner.next_sibling(); // let temp = inner.next_sibling();
if let Some(sibling) = inner.dyn_ref::<Element>() { // if let Some(sibling) = inner.dyn_ref::<Element>() {
sibling.remove(); // sibling.remove();
} // }
sibling = temp; // sibling = temp;
} // }
if let Some(node) = node.dyn_ref::<Element>() { // if let Some(node) = node.dyn_ref::<Element>() {
node.remove(); // node.remove();
} // }
} // }
// 2 // // 2
pub fn replace_with(&mut self) { // pub fn replace_with(&mut self) {
let new_node = self.stack.pop(); // let new_node = self.stack.pop();
let old_node = self.stack.pop(); // let old_node = self.stack.pop();
if old_node.has_type::<Element>() { // if old_node.has_type::<Element>() {
old_node // old_node
.dyn_ref::<Element>() // .dyn_ref::<Element>()
.unwrap() // .unwrap()
.replace_with_with_node_1(&new_node) // .replace_with_with_node_1(&new_node)
.unwrap(); // .unwrap();
} else if old_node.has_type::<web_sys::CharacterData>() { // } else if old_node.has_type::<web_sys::CharacterData>() {
old_node // old_node
.dyn_ref::<web_sys::CharacterData>() // .dyn_ref::<web_sys::CharacterData>()
.unwrap() // .unwrap()
.replace_with_with_node_1(&new_node) // .replace_with_with_node_1(&new_node)
.unwrap(); // .unwrap();
} else if old_node.has_type::<web_sys::DocumentType>() { // } else if old_node.has_type::<web_sys::DocumentType>() {
old_node // old_node
.dyn_ref::<web_sys::DocumentType>() // .dyn_ref::<web_sys::DocumentType>()
.unwrap() // .unwrap()
.replace_with_with_node_1(&new_node) // .replace_with_with_node_1(&new_node)
.unwrap(); // .unwrap();
} else { // } else {
panic!("Cannot replace node: {:?}", old_node); // panic!("Cannot replace node: {:?}", old_node);
} // }
self.stack.push(new_node); // self.stack.push(new_node);
} // }
// 3 // // 3
pub fn set_attribute(&mut self, name: &str, value: &str) { // pub fn set_attribute(&mut self, name: &str, value: &str) {
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::<Element>() {
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: // // TODO:
// if name == "value" { // // if name == "value" {
// node.set_value(value); // // node.set_value(value);
// } // // }
// if name == "checked" { // // if name == "checked" {
// node.set_checked(true); // // node.set_checked(true);
// } // // }
// if name == "selected" { // // if name == "selected" {
// node.set_selected(true); // // node.set_selected(true);
// } // // }
} // }
} // }
// 4 // // 4
pub fn remove_attribute(&mut self, name: &str) { // pub fn remove_attribute(&mut self, name: &str) {
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::<Element>() {
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: // // TODO:
// if name == "value" { // // if name == "value" {
// node.set_value(""); // // node.set_value("");
// } // // }
// if name == "checked" { // // if name == "checked" {
// node.set_checked(false); // // node.set_checked(false);
// } // // }
// if name == "selected" { // // if name == "selected" {
// node.set_selected(false); // // node.set_selected(false);
// } // // }
} // }
} // }
// 5 // // 5
pub fn push_reverse_child(&mut self, n: u32) { // pub fn push_reverse_child(&mut self, n: u32) {
let parent = self.stack.top(); // let parent = self.stack.top();
let children = parent.child_nodes(); // let children = parent.child_nodes();
let child = children.get(children.length() - n - 1).unwrap(); // let child = children.get(children.length() - n - 1).unwrap();
self.stack.push(child); // self.stack.push(child);
} // }
// 6 // // 6
pub fn pop_push_child(&mut self, n: u32) { // pub fn pop_push_child(&mut self, n: u32) {
self.stack.pop(); // self.stack.pop();
let parent = self.stack.top(); // let parent = self.stack.top();
let children = parent.child_nodes(); // let children = parent.child_nodes();
let child = children.get(n).unwrap(); // let child = children.get(n).unwrap();
self.stack.push(child); // self.stack.push(child);
} // }
// 7 // // 7
pub fn pop(&mut self) { // pub fn pop(&mut self) {
self.stack.pop(); // self.stack.pop();
} // }
// 8 // // 8
pub fn append_child(&mut self) { // pub fn append_child(&mut self) {
let child = self.stack.pop(); // let child = self.stack.pop();
self.stack.top().append_child(&child).unwrap(); // self.stack.top().append_child(&child).unwrap();
} // }
// 9 // // 9
pub fn create_text_node(&mut self, text: &str) { // pub fn create_text_node(&mut self, text: &str) {
self.stack.push( // self.stack.push(
self.document // self.document
.create_text_node(text) // .create_text_node(text)
.dyn_into::<Node>() // .dyn_into::<Node>()
.unwrap(), // .unwrap(),
); // );
} // }
// 10 // // 10
pub fn create_element(&mut self, tag_name: &str) { // pub fn create_element(&mut self, tag_name: &str) {
let el = self // let el = self
.document // .document
.create_element(tag_name) // .create_element(tag_name)
.unwrap() // .unwrap()
.dyn_into::<Node>() // .dyn_into::<Node>()
.unwrap(); // .unwrap();
self.stack.push(el); // self.stack.push(el);
} // }
// 11 // // 11
pub fn new_event_listener(&mut self, event_type: &str, a: u32, b: u32) { // pub fn new_event_listener(&mut self, event_type: &str, a: u32, b: u32) {
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( // el.add_event_listener_with_callback(
event_type, // event_type,
self.callback.as_ref().unwrap().as_ref().unchecked_ref(), // self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
) // )
.unwrap(); // .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!("dodrio-a-{}", event_type), &a.to_string())
.unwrap(); // .unwrap();
el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string()) // el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
.unwrap(); // .unwrap();
} // }
// 12 // // 12
pub fn update_event_listener(&mut self, event_type: &str, a: u32, b: u32) { // pub fn update_event_listener(&mut self, event_type: &str, a: u32, b: u32) {
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!("dodrio-a-{}", event_type), &a.to_string())
.unwrap(); // .unwrap();
el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string()) // el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
.unwrap(); // .unwrap();
} // }
} // }
// 13 // // 13
pub fn remove_event_listener(&mut self, event_type: &str) { // pub fn remove_event_listener(&mut self, event_type: &str) {
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( // el.remove_event_listener_with_callback(
event_type, // event_type,
self.callback.as_ref().unwrap().as_ref().unchecked_ref(), // self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
) // )
.unwrap(); // .unwrap();
} // }
} // }
// 16 // // 16
pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) { // pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) {
let el = self // let el = self
.document // .document
.create_element_ns(Some(ns), tag_name) // .create_element_ns(Some(ns), tag_name)
.unwrap() // .unwrap()
.dyn_into::<Node>() // .dyn_into::<Node>()
.unwrap(); // .unwrap();
self.stack.push(el); // self.stack.push(el);
} // }
// 17 // // 17
pub fn save_children_to_temporaries(&mut self, mut temp: u32, start: u32, end: u32) { // pub fn save_children_to_temporaries(&mut self, mut temp: u32, start: u32, end: u32) {
let parent = self.stack.top(); // let parent = self.stack.top();
let children = parent.child_nodes(); // let children = parent.child_nodes();
for i in start..end { // for i in start..end {
self.temporaries.insert(temp, children.get(i).unwrap()); // self.temporaries.insert(temp, children.get(i).unwrap());
temp += 1; // temp += 1;
} // }
} // }
// 18 // // 18
pub fn push_child(&mut self, n: u32) { // pub fn push_child(&mut self, n: u32) {
let parent = self.stack.top(); // let parent = self.stack.top();
let child = parent.child_nodes().get(n).unwrap(); // let child = parent.child_nodes().get(n).unwrap();
self.stack.push(child); // self.stack.push(child);
} // }
// 19 // // 19
pub fn push_temporary(&mut self, temp: u32) { // pub fn push_temporary(&mut self, temp: u32) {
let t = self.temporaries.get(&temp).unwrap().clone(); // let t = self.temporaries.get(&temp).unwrap().clone();
self.stack.push(t); // self.stack.push(t);
} // }
// 20 // // 20
pub fn insert_before(&mut self) { // pub fn insert_before(&mut self) {
let before = self.stack.pop(); // let before = self.stack.pop();
let after = self.stack.pop(); // let after = self.stack.pop();
after // after
.parent_node() // .parent_node()
.unwrap() // .unwrap()
.insert_before(&before, Some(&after)) // .insert_before(&before, Some(&after))
.unwrap(); // .unwrap();
self.stack.push(before); // self.stack.push(before);
} // }
// 21 // // 21
pub fn pop_push_reverse_child(&mut self, n: u32) { // pub fn pop_push_reverse_child(&mut self, n: u32) {
self.stack.pop(); // self.stack.pop();
let parent = self.stack.top(); // let parent = self.stack.top();
let children = parent.child_nodes(); // let children = parent.child_nodes();
let child = children.get(children.length() - n - 1).unwrap(); // let child = children.get(children.length() - n - 1).unwrap();
self.stack.push(child); // self.stack.push(child);
} // }
// 22 // // 22
pub fn remove_child(&mut self, n: u32) { // pub fn remove_child(&mut self, n: u32) {
let parent = self.stack.top(); // let parent = self.stack.top();
if let Some(child) = parent.child_nodes().get(n).unwrap().dyn_ref::<Element>() { // if let Some(child) = parent.child_nodes().get(n).unwrap().dyn_ref::<Element>() {
child.remove(); // child.remove();
} // }
} // }
// 23 // // 23
pub fn set_class(&mut self, class_name: &str) { // pub fn set_class(&mut self, class_name: &str) {
if let Some(el) = self.stack.top().dyn_ref::<Element>() { // if let Some(el) = self.stack.top().dyn_ref::<Element>() {
el.set_class_name(class_name); // el.set_class_name(class_name);
} // }
} // }
// 24 // 24
pub fn save_template(&mut self, id: CacheId) { pub fn save_template(&mut self, id: CacheId) {
+8 -1
View File
@@ -9,6 +9,13 @@ edition = "2018"
[dependencies] [dependencies]
web-view = "0.7.2" web-view = "0.7.2"
dioxus-core = { path = "../core" } dioxus-core = { path = "../core" }
anyhow = "1.0.38"
argh = "0.1.4"
serde = "1.0.120"
serde_json = "1.0.61"
async-std = { version = "1.9.0", features = ["attributes"] }
thiserror = "1.0.23"
log = "0.4.13"
fern = { version = "0.6.0", features = ["colored"] }
[build-dependencies] [build-dependencies]
+3
View File
@@ -0,0 +1,3 @@
// 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.
+139 -7
View File
@@ -1,20 +1,152 @@
//! An example where the dioxus vdom is running in a native thread, interacting with webview //! An example where the dioxus vdom is running in a native thread, interacting with webview
fn main() { use std::{
let html_content = "<div>Hello world!</div>"; borrow::BorrowMut,
rc::Rc,
sync::{mpsc::channel, Arc},
};
web_view::builder() // 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::<InnerEvent>();
// let (sender, receiver) = channel::unbounded::<InnerEvent>();
// let task = async_std::task::spawn(async move {
let mut view = web_view::builder()
.title("My Project") .title("My Project")
.content(web_view::Content::Html(html_content)) .content(web_view::Content::Html(HTML_CONTENT))
.size(320, 480) .size(320, 480)
.resizable(true) .resizable(true)
.debug(true) .debug(true)
.user_data(()) .user_data(())
.invoke_handler(|view, arg| { .invoke_handler(|view, arg| {
// // todo: handle events here
println!("handling invoker");
let handle = view.handle();
sender.send(InnerEvent::Initiate(handle));
Ok(()) Ok(())
}) })
.run() .build()
.unwrap(); .unwrap();
println!("building the diff");
let bump = Bump::new();
let mut diff_machine = DiffMachine::new(&bump);
let old = html! {<div> </div>}(&bump);
// let mut scope = Scope::new(TEST, (), None);
// scope.run::<()>();
let new = html! {
<div>
<div class="flex items-center justify-center flex-col">
<div class="flex items-center justify-center">
<div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
// Title
<div class="font-bold text-xl">
"Jon's awesome site!!11"
</div>
// Subtext / description
<div class="text-sm text-gray-500">
"He worked so hard on it :)"
</div>
<div class="flex flex-row items-center justify-center mt-6">
// Main number
<div class="font-medium text-6xl">
"1337"
</div>
</div>
// Try another
<div class="flex flex-row justify-between mt-6">
// <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
"Legit made my own React"
// </a>
</div>
</div>
</div>
</div>
</div>
}(&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")?;
}
} }
// static TEST: FC<()> = |ctx, props| {
// ctx.view(html! {
// <div>
// <div class="flex items-center justify-center flex-col">
// <div class="flex items-center justify-center">
// <div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
// // Title
// <div class="font-bold text-xl">
// "Jon's awesome site!!11"
// </div>
// // Subtext / description
// <div class="text-sm text-gray-500">
// "He worked so hard on it :)"
// </div>
// <div class="flex flex-row items-center justify-center mt-6">
// // Main number
// <div class="font-medium text-6xl">
// "1337"
// </div>
// </div>
// // Try another
// <div class="flex flex-row justify-between mt-6">
// // <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
// "Legit made my own React"
// // </a>
// </div>
// </div>
// </div>
// </div>
// </div>
// })
// };
+324
View File
@@ -0,0 +1,324 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
<meta charset="UTF-8" />
<link
href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"
rel="stylesheet"
/>
</head>
<body>
<div></div>
</body>
<script>
// #[derive(Debug, serde::Serialize, serde::Deserialize)]
// pub enum Edit<'d> {
// SetText { text: &'d str },
// RemoveSelfAndNextSiblings {},
// ReplaceWith,
// SetAttribute { name: &'d str, value: &'d str },
// RemoveAttribute { name: &'d str },
// PushReverseChild { n: u32 },
// PopPushChild { n: u32 },
// Pop,
// AppendChild,
// CreateTextNode { text: &'d str },
// CreateElement { tag_name: &'d str },
// NewEventListener { event_type: &'d str, a: u32, b: u32 },
// UpdateEventListener { event_type: &'d str, a: u32, b: u32 },
// RemoveEventListener { event_type: &'d str },
// CreateElementNs { tag_name: &'d str, ns: &'d str },
// SaveChildrenToTemporaries { temp: u32, start: u32, end: u32 },
// PushChild { n: u32 },
// PushTemporary { temp: u32 },
// InsertBefore,
// PopPushReverseChild { n: u32 },
// RemoveChild { n: u32 },
// SetClass { class_name: &'d str },
// }
// const interpreter = new Interpreter();
class Interpreter {
constructor(root) {
this.stack = [root];
}
top() {
return this.stack[this.stack.length - 1];
}
pop() {
return this.stack.pop();
}
}
class OPTABLE {
// 0
SetText(edit, interp) {
interp.top(interp.stack).textContent = edit.text;
}
// 1
RemoveSelfAndNextSiblings(edit) {
const node = interp.pop();
let sibling = node.nextSibling;
while (sibling) {
const temp = sibling.nextSibling;
sibling.remove();
sibling = temp;
}
node.remove();
}
// 2
ReplaceWith(edit, interp) {
const newNode = interp.pop();
const oldNode = interp.pop();
oldNode.replaceWith(newNode);
interp.stack.push(newNode);
}
// 3
SetAttribute(edit, interp) {
const name = edit.name;
const value = edit.value;
const node = interp.top(interp.stack);
node.setAttribute(name, value);
// Some attributes are "volatile" and don't work through `setAttribute`.
if ((name === "value", interp)) {
node.value = value;
}
if ((name === "checked", interp)) {
node.checked = true;
}
if ((name === "selected", interp)) {
node.selected = true;
}
}
// 4
RemoveAttribute(edit, interp) {
const name = edit.name;
const node = interp.top(interp.stack);
node.removeAttribute(name);
// Some attributes are "volatile" and don't work through `removeAttribute`.
if ((name === "value", interp)) {
node.value = null;
}
if ((name === "checked", interp)) {
node.checked = false;
}
if ((name === "selected", interp)) {
node.selected = false;
}
}
// 5
PushReverseChild(edit, interp) {
const n = edit.n;
const parent = interp.top(interp.stack);
const children = parent.childNodes;
const child = children[children.length - n - 1];
interp.stack.push(child);
}
// 6
PopPushChild(edit, interp) {
const n = edit.n;
interp.pop();
const parent = interp.top(interp.stack);
const children = parent.childNodes;
const child = children[n];
interp.stack.push(child);
}
// 7
Pop(edit, interp) {
interp.pop();
}
// 8
AppendChild(edit, interp) {
console.log(interp.stack);
const child = interp.pop();
console.log(interp.stack);
interp.top().appendChild(child);
}
// 9
CreateTextNode(edit, interp) {
// interp.stack.push(document.createTextNode("asd"));
console.log(interp.stack);
interp.stack.push(document.createTextNode(edit.text));
console.log(interp.stack);
}
// 10
CreateElement(edit, interp) {
const tagName = edit.tag_name;
interp.stack.push(document.createElement(tagName));
}
// 11
NewEventListener(edit, interp) {
// todo!
const eventId = mem32[i++];
const eventType = interp.getCachedString(eventId);
const a = mem32[i++];
const b = mem32[i++];
const el = interp.top(interp.stack);
el.addEventListener(eventType, interp.eventHandler);
el[`dodrio-a-${eventType}`] = a;
el[`dodrio-b-${eventType}`] = b;
}
// 12
UpdateEventListener(edit, interp) {
// todo!
const eventId = mem32[i++];
const eventType = interp.getCachedString(eventId);
const el = interp.top(interp.stack);
el[`dodrio-a-${eventType}`] = mem32[i++];
el[`dodrio-b-${eventType}`] = mem32[i++];
}
// 13
RemoveEventListener(edit, interp) {
// todo!
const eventId = mem32[i++];
const eventType = interp.getCachedString(eventId);
const el = interp.top(interp.stack);
el.removeEventListener(eventType, interp.eventHandler);
}
// 14
AddCachedString(edit, interp) {
// todo!
const pointer = mem32[i++];
const length = mem32[i++];
const id = mem32[i++];
const str = string(mem8, pointer, length);
interp.addCachedString(str, id);
}
// 15
DropCachedString(edit, interp) {
// todo!
const id = mem32[i++];
interp.dropCachedString(id);
}
// 16
CreateElementNS(edit, interp) {
// const tagNameId = mem32[i++];
// const tagName = interp.getCachedString(tagNameId);
// const nsId = mem32[i++];
// const ns = interp.getCachedString(nsId);
interp.stack.push(document.createElementNS(edit.ns, edit.tag_name));
}
// 17
SaveChildrenToTemporaries(edit, interp) {
// let temp = mem32[i++];
// const start = mem32[i++];
// const end = mem32[i++];
let temp = edit.temp;
const start = edit.start;
const end = edit.end;
const parent = interp.top(interp.stack);
const children = parent.childNodes;
for (let i = start; i < end; i++, interp) {
interp.temporaries[temp++] = children[i];
}
}
// 18
PushChild(edit, interp) {
const parent = interp.top(interp.stack);
// const n = mem32[i++];
const n = edit.n;
const child = parent.childNodes[n];
interp.stack.push(child);
}
// 19
PushTemporary(edit, interp) {
// const temp = mem32[i++];
const temp = edit.temp;
interp.stack.push(interp.temporaries[temp]);
}
// 20
InsertBefore(edit, interp) {
const before = interp.pop();
const after = interp.pop();
after.parentNode.insertBefore(before, after);
interp.stack.push(before);
}
// 21
PopPushReverseChild(edit, interp) {
// const n = mem32[i++];
const n = edit.n;
interp.pop();
const parent = interp.top(interp.stack);
const children = parent.childNodes;
const child = children[children.length - n - 1];
interp.stack.push(child);
}
// 22
RemoveChild(edit, interp) {
// const n = mem32[i++];
const n = edit.n;
const parent = interp.top(interp.stack);
const child = parent.childNodes[n];
child.remove();
}
// 23
SetClass(edit, interp) {
// const classId = mem32[i++];
const className = edit.class_name;
interp.top(interp.stack).className = className;
}
// 24
SaveTemplate(edit, interp) {
const id = mem32[i++];
const template = interp.top(interp.stack);
interp.saveTemplate(id, template.cloneNode(true));
}
// 25
PushTemplate(edit, interp) {
const id = mem32[i++];
const template = interp.getTemplate(id);
interp.stack.push(template.cloneNode(true));
}
}
let op = new OPTABLE();
const c = window.document.body.firstChild;
console.log("First child");
console.log(c);
const interpreter = new Interpreter(window.document.body);
function EditListReceived(rawEditList) {
let editList = JSON.parse(rawEditList);
console.log(editList);
editList.forEach(function (edit, index) {
// console.log("processing edit");
const name = edit.type;
console.log(name);
const f = op[name];
f(edit, interpreter);
});
}
external.invoke("initiate");
</script>
</html>