Feat: desktop app wired up

This commit is contained in:
Jonathan Kelley 2021-02-18 20:04:25 -05:00
parent bcbb93b697
commit b3e6886351
10 changed files with 744 additions and 269 deletions

View file

@ -19,6 +19,8 @@
//!
//!
use std::ops::{Deref, DerefMut};
use bumpalo::Bump;
use crate::innerlude::{Listener, VirtualDom};
@ -32,8 +34,9 @@ use crate::innerlude::{Listener, VirtualDom};
///
///
///
///
#[derive(Debug)]
/// todo@ jon: allow serde to be optional
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
pub enum Edit<'d> {
SetText { text: &'d str },
RemoveSelfAndNextSiblings {},
@ -59,20 +62,23 @@ pub enum Edit<'d> {
SetClass { class_name: &'d str },
}
pub struct EditList<'src> {
pub type EditList<'src> = Vec<Edit<'src>>;
pub struct EditMachine<'src> {
pub traversal: Traversal,
next_temporary: u32,
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 {
Self {
traversal: Traversal::new(),
next_temporary: 0,
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 {
self.next_temporary
}

View file

@ -37,7 +37,7 @@ use fxhash::{FxHashMap, FxHashSet};
use generational_arena::Index;
use crate::{
changelist::{Edit, EditList},
changelist::{Edit, EditList, EditMachine},
innerlude::{Attribute, Listener, Scope, VElement, VNode, VText},
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
/// subscriptions and props changes.
pub struct DiffMachine<'a> {
pub change_list: EditList<'a>,
pub change_list: EditMachine<'a>,
immediate_queue: Vec<Index>,
diffed: FxHashSet<Index>,
need_to_diff: FxHashSet<Index>,
@ -71,14 +71,14 @@ enum NeedToDiff {
impl<'a> DiffMachine<'a> {
pub fn new(bump: &'a Bump) -> Self {
Self {
change_list: EditList::new(bump),
change_list: EditMachine::new(bump),
immediate_queue: Vec::new(),
diffed: FxHashSet::default(),
need_to_diff: FxHashSet::default(),
}
}
pub fn consume(self) -> Vec<Edit<'a>> {
pub fn consume(self) -> EditList<'a> {
self.change_list.emitter
}

View file

@ -19,6 +19,11 @@ impl EventTrigger {
}
pub enum VirtualEvent {
// the event to drain the current lifecycle queue
// Used to initate the dom
InitiateEvent,
// Real events
ClipboardEvent,
CompositionEvent,
KeyboardEvent,

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.
/// 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
// These hooks are actually references into the hook arena
// These two could be combined with "OwningRef" to remove unsafe usage
@ -50,23 +51,10 @@ pub(crate) struct Scope {
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 {
// 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>,
props: impl Properties + 'static,
parent: Option<Index>,
@ -120,7 +108,7 @@ impl Scope {
/// 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)
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 = self.frames.next();
frame.bump.reset();
@ -164,14 +152,12 @@ impl Scope {
let unsafe_node = unsafe { std::mem::transmute::<VNode<'bump>, VNode<'static>>(nodes) };
frame.head_node = unsafe_node;
todo!()
}
/// 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
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> {
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 {
self.idx.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let cur = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);

View file

@ -1,8 +1,9 @@
// 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 any::Any;
use bumpalo::Bump;
use changelist::EditMachine;
use generational_arena::{Arena, Index};
use std::{
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.
pub fn queue_update() {}
pub fn start(&mut self) -> Result<EditList> {
todo!()
}
/// Pop an event off the event queue and process it
/// Update the root props, and progress
/// Takes a bump arena to allocate into, making the diff phase as fast as possible
@ -115,7 +120,7 @@ impl VirtualDom {
.borrow_mut()
.pop_front()
.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.
@ -171,7 +176,7 @@ impl VirtualDom {
new_evt
} {
affected_components.push(event.component_index);
self.process_event(event)?;
self.process_lifecycle(event)?;
}
let diff_bump = Bump::new();
@ -180,9 +185,6 @@ impl VirtualDom {
Ok(())
}
pub async fn progress_completely(&mut self) -> Result<()> {
Ok(())
}
/// 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,
LifecycleEvent {
component_index: index,

View file

@ -380,257 +380,257 @@ impl PatchMachine {
}
}
// 0
pub fn set_text(&mut self, text: &str) {
self.stack.top().set_text_content(Some(text));
}
// // 0
// pub fn set_text(&mut self, text: &str) {
// self.stack.top().set_text_content(Some(text));
// }
// 1
pub fn remove_self_and_next_siblings(&mut self) {
let node = self.stack.pop();
let mut sibling = node.next_sibling();
// // 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::<Element>() {
sibling.remove();
}
sibling = temp;
}
if let Some(node) = node.dyn_ref::<Element>() {
node.remove();
}
}
// while let Some(inner) = sibling {
// let temp = inner.next_sibling();
// if let Some(sibling) = inner.dyn_ref::<Element>() {
// sibling.remove();
// }
// sibling = temp;
// }
// if let Some(node) = node.dyn_ref::<Element>() {
// node.remove();
// }
// }
// 2
pub fn replace_with(&mut self) {
let new_node = self.stack.pop();
let old_node = self.stack.pop();
// // 2
// pub fn replace_with(&mut self) {
// let new_node = self.stack.pop();
// let old_node = self.stack.pop();
if old_node.has_type::<Element>() {
old_node
.dyn_ref::<Element>()
.unwrap()
.replace_with_with_node_1(&new_node)
.unwrap();
} else if old_node.has_type::<web_sys::CharacterData>() {
old_node
.dyn_ref::<web_sys::CharacterData>()
.unwrap()
.replace_with_with_node_1(&new_node)
.unwrap();
} else if old_node.has_type::<web_sys::DocumentType>() {
old_node
.dyn_ref::<web_sys::DocumentType>()
.unwrap()
.replace_with_with_node_1(&new_node)
.unwrap();
} else {
panic!("Cannot replace node: {:?}", old_node);
}
// if old_node.has_type::<Element>() {
// old_node
// .dyn_ref::<Element>()
// .unwrap()
// .replace_with_with_node_1(&new_node)
// .unwrap();
// } else if old_node.has_type::<web_sys::CharacterData>() {
// old_node
// .dyn_ref::<web_sys::CharacterData>()
// .unwrap()
// .replace_with_with_node_1(&new_node)
// .unwrap();
// } else if old_node.has_type::<web_sys::DocumentType>() {
// old_node
// .dyn_ref::<web_sys::DocumentType>()
// .unwrap()
// .replace_with_with_node_1(&new_node)
// .unwrap();
// } else {
// panic!("Cannot replace node: {:?}", old_node);
// }
self.stack.push(new_node);
}
// self.stack.push(new_node);
// }
// 3
pub fn set_attribute(&mut self, name: &str, value: &str) {
let node = self.stack.top();
// // 3
// pub fn set_attribute(&mut self, name: &str, value: &str) {
// let node = self.stack.top();
if let Some(node) = node.dyn_ref::<Element>() {
node.set_attribute(name, value).unwrap();
// if let Some(node) = node.dyn_ref::<Element>() {
// 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);
// }
}
}
// // 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::<Element>() {
node.remove_attribute(name).unwrap();
// // 4
// pub fn remove_attribute(&mut self, name: &str) {
// let node = self.stack.top();
// if let Some(node) = node.dyn_ref::<Element>() {
// 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);
// }
}
}
// // 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);
}
// // 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);
}
// // 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();
}
// // 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();
}
// // 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::<Node>()
.unwrap(),
);
}
// // 9
// pub fn create_text_node(&mut self, text: &str) {
// self.stack.push(
// self.document
// .create_text_node(text)
// .dyn_into::<Node>()
// .unwrap(),
// );
// }
// 10
pub fn create_element(&mut self, tag_name: &str) {
let el = self
.document
.create_element(tag_name)
.unwrap()
.dyn_into::<Node>()
.unwrap();
self.stack.push(el);
}
// // 10
// pub fn create_element(&mut self, tag_name: &str) {
// let el = self
// .document
// .create_element(tag_name)
// .unwrap()
// .dyn_into::<Node>()
// .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();
// // 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::<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();
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();
}
// 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();
// 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::<Element>() {
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::<Element>() {
// 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::<Element>() {
el.remove_event_listener_with_callback(
event_type,
self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
)
.unwrap();
}
}
// // 13
// pub fn remove_event_listener(&mut self, event_type: &str) {
// 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();
// }
// }
// 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::<Node>()
.unwrap();
self.stack.push(el);
}
// // 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::<Node>()
// .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;
}
}
// // 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);
}
// // 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();
self.stack.push(t);
}
// // 19
// pub fn push_temporary(&mut self, temp: u32) {
// let t = self.temporaries.get(&temp).unwrap().clone();
// 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);
}
// // 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);
// }
// 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);
}
// // 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::<Element>() {
child.remove();
}
}
// // 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::<Element>() {
// child.remove();
// }
// }
// 23
pub fn set_class(&mut self, class_name: &str) {
if let Some(el) = self.stack.top().dyn_ref::<Element>() {
el.set_class_name(class_name);
}
}
// // 23
// pub fn set_class(&mut self, class_name: &str) {
// if let Some(el) = self.stack.top().dyn_ref::<Element>() {
// el.set_class_name(class_name);
// }
// }
// 24
pub fn save_template(&mut self, id: CacheId) {

View file

@ -9,6 +9,13 @@ edition = "2018"
[dependencies]
web-view = "0.7.2"
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]

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.

View file

@ -1,20 +1,152 @@
//! An example where the dioxus vdom is running in a native thread, interacting with webview
fn main() {
let html_content = "<div>Hello world!</div>";
use std::{
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")
.content(web_view::Content::Html(html_content))
.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(())
})
.run()
.build()
.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>
// })
// };

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>