feat: get desktop working with new template strategy

This commit is contained in:
Jonathan Kelley committed 2022-12-05 16:08:41 -08:00
1 parent df4a1b6c7a
commit 7b1cdb7d85
11 files changed
+79 -31

No files matched your search

+3 -3
View File
@@ -40,7 +40,7 @@ impl<'b> VirtualDom {
for (root_idx, root) in template.template.roots.iter().enumerate() {
// We might need to generate an ID for the root node
on_stack += match root {
TemplateNode::DynamicText(id) | TemplateNode::Dynamic(id) => {
TemplateNode::DynamicText { id } | TemplateNode::Dynamic { id } => {
match &template.dynamic_nodes[*id] {
// a dynamic text node doesn't replace a template node, instead we create it on the fly
DynamicNode::Text(VText { id: slot, value }) => {
@@ -70,7 +70,7 @@ impl<'b> VirtualDom {
}
}
TemplateNode::Element { .. } | TemplateNode::Text(_) => {
TemplateNode::Element { .. } | TemplateNode::Text { .. } => {
let this_id = self.next_root(template, root_idx);
template.root_ids[root_idx].set(this_id);
@@ -215,7 +215,7 @@ impl<'b> VirtualDom {
.filter(|root| {
matches!(
root,
TemplateNode::Dynamic(_) | TemplateNode::DynamicText(_)
TemplateNode::Dynamic { .. } | TemplateNode::DynamicText { .. }
)
})
.count();
+1 -1
View File
@@ -911,7 +911,7 @@ fn matching_components<'a>(
.zip(right.template.roots.iter())
.map(|(l, r)| {
let (l, r) = match (l, r) {
(TemplateNode::Dynamic(l), TemplateNode::Dynamic(r)) => (l, r),
(TemplateNode::Dynamic { id: l }, TemplateNode::Dynamic { id: r }) => (l, r),
_ => return None,
};
+1
View File
@@ -13,6 +13,7 @@ use crate::{arena::ElementId, ScopeId, Template};
/// Templates, however, apply to all subtrees, not just target subtree.
///
/// Mutations are the only link between the RealDOM and the VirtualDOM.
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[derive(Debug, Default)]
#[must_use = "not handling edits can lead to visual inconsistencies in UI"]
pub struct Mutations<'a> {
+11 -7
View File
@@ -78,8 +78,8 @@ impl<'a> VNode<'a> {
/// Returns [`None`] if the root is actually a static node (Element/Text)
pub fn dynamic_root(&self, idx: usize) -> Option<&'a DynamicNode<'a>> {
match &self.template.roots[idx] {
TemplateNode::Element { .. } | TemplateNode::Text(_) => None,
TemplateNode::Dynamic(id) | TemplateNode::DynamicText(id) => {
TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => None,
TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => {
Some(&self.dynamic_nodes[*id])
}
}
@@ -132,7 +132,7 @@ pub struct Template<'a> {
///
/// This can be created at compile time, saving the VirtualDom time when diffing the tree
#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize), serde(tag = "type"))]
pub enum TemplateNode<'a> {
/// An statically known element in the dom.
///
@@ -159,15 +159,15 @@ pub enum TemplateNode<'a> {
},
/// This template node is just a piece of static text
Text(&'a str),
Text { text: &'a str },
/// This template node is unknown, and needs to be created at runtime.
Dynamic(usize),
Dynamic { id: usize },
/// This template node is known to be some text, but needs to be created at runtime
///
/// This is separate from the pure Dynamic variant for various optimizations
DynamicText(usize),
DynamicText { id: usize },
}
/// A node created at runtime
@@ -252,7 +252,11 @@ pub struct VText<'a> {
/// An attribute of the TemplateNode, created at compile time
#[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
serde(tag = "type")
)]
pub enum TemplateAttribute<'a> {
/// This attribute is entirely known at compile time, enabling
Static {
+1 -4
View File
@@ -54,8 +54,7 @@ impl DesktopController {
{
let edits = dom.rebuild();
let mut queue = edit_queue.lock().unwrap();
queue.push(serde_json::to_string(&edits.templates).unwrap());
queue.push(serde_json::to_string(&edits.edits).unwrap());
queue.push(serde_json::to_string(&edits).unwrap());
proxy.send_event(UserWindowEvent::EditsReady).unwrap();
}
@@ -116,8 +115,6 @@ impl DesktopController {
let (_id, view) = self.webviews.iter_mut().next().unwrap();
println!("processing pending edits {:?}", new_queue.len());
for edit in new_queue.drain(..) {
view.evaluate_script(&format!("window.interpreter.handleEdits({})", edit))
.unwrap();
-1
View File
@@ -1,6 +1,5 @@
//! Convert a serialized event to an event trigger
use dioxus_core::ElementId;
use dioxus_html::events::*;
use serde::{Deserialize, Serialize};
use serde_json::from_value;
+3 -3
View File
@@ -33,9 +33,9 @@ fn render_template_node(node: &TemplateNode, out: &mut String) -> std::fmt::Resu
}
write!(out, "</{tag}>")?;
}
TemplateNode::Text(t) => write!(out, "{t}")?,
TemplateNode::Dynamic(_) => write!(out, "<pre hidden />")?,
TemplateNode::DynamicText(t) => write!(out, "<!-- --> {t} <!-- -->")?,
TemplateNode::Text { text: t } => write!(out, "{t}")?,
TemplateNode::Dynamic { id: _ } => write!(out, "<pre hidden />")?,
TemplateNode::DynamicText { id: t } => write!(out, "<!-- --> {t} <!-- -->")?,
};
Ok(())
}
+48 -4
View File
@@ -76,9 +76,6 @@ export class Interpreter {
pop() {
return this.stack.pop();
}
SaveTemplate(nodes, name) {
this.templates[name] = nodes;
}
MountToRoot() {
this.AppendChildren(this.stack.length - 1);
}
@@ -213,10 +210,57 @@ export class Interpreter {
}
}
handleEdits(edits) {
for (let edit of edits) {
// a json blob of things
for (let template of edits.templates) {
this.SaveTemplate(template);
}
for (let edit of edits.edits) {
this.handleEdit(edit);
}
}
SaveTemplate(template) {
console.log("saving template", template);
let roots = [];
for (let root of template.roots) {
roots.push(this.MakeTemplateNode(root));
}
console.log("saving template", template.name, roots);
this.templates[template.name] = roots;
}
MakeTemplateNode(node) {
console.log("making template node", node);
switch (node.type) {
case "Text":
return document.createTextNode(node.text);
case "Dynamic":
let dyn = document.createElement("pre");
dyn.hidden = true;
return dyn;
case "DynamicText":
return document.createTextNode("placeholder");
case "Element":
let el;
if (node.namespace != null) {
el = document.createElementNS(node.namespace, node.tag);
} else {
el = document.createElement(node.tag);
}
for (let attr of node.attrs) {
if (attr.type == "Static") {
this.SetAttributeInner(el, attr.name, attr.value, attr.namespace);
}
}
for (let child of node.children) {
el.appendChild(this.MakeTemplateNode(child));
}
return el;
}
}
AssignId(path, id) {
this.nodes[id] = this.LoadChild(path);
}
+5 -3
View File
@@ -245,7 +245,7 @@ impl<'a> DynamicContext<'a> {
BodyNode::Text(text) if text.is_static() => {
let text = text.source.as_ref().unwrap();
quote! { ::dioxus::core::TemplateNode::Text(#text) }
quote! { ::dioxus::core::TemplateNode::Text{ text: #text } }
}
BodyNode::RawExpr(_)
@@ -258,8 +258,10 @@ impl<'a> DynamicContext<'a> {
self.node_paths.push(self.current_path.clone());
match root {
BodyNode::Text(_) => quote! { ::dioxus::core::TemplateNode::DynamicText(#ct) },
_ => quote! { ::dioxus::core::TemplateNode::Dynamic(#ct) },
BodyNode::Text(_) => {
quote! { ::dioxus::core::TemplateNode::DynamicText { id: #ct } }
}
_ => quote! { ::dioxus::core::TemplateNode::Dynamic { id: #ct } },
}
}
}
+2 -2
View File
@@ -81,8 +81,8 @@ impl StringCache {
}
cur_path.pop();
}
TemplateNode::Text(text) => write!(chain, "{}", text)?,
TemplateNode::Dynamic(idx) | TemplateNode::DynamicText(idx) => {
TemplateNode::Text { text } => write!(chain, "{}", text)?,
TemplateNode::Dynamic { id: idx } | TemplateNode::DynamicText { id: idx } => {
chain.segments.push(Segment::Node(*idx))
}
}
+4 -3
View File
@@ -101,9 +101,9 @@ impl WebsysDom {
}
el.dyn_into().unwrap()
}
Text(t) => self.document.create_text_node(t).dyn_into().unwrap(),
DynamicText(_) => self.document.create_text_node("p").dyn_into().unwrap(),
Dynamic(_) => {
Text { text: t } => self.document.create_text_node(t).dyn_into().unwrap(),
DynamicText { id: _ } => self.document.create_text_node("p").dyn_into().unwrap(),
Dynamic { id: _ } => {
let el = self.document.create_element("pre").unwrap();
el.toggle_attribute("hidden");
el.dyn_into().unwrap()
@@ -116,6 +116,7 @@ impl WebsysDom {
let i = &self.interpreter;
for edit in edits.drain(..) {
match edit {
AppendChildren { id, m } => i.AppendChildren(id, m),
AssignId { path, id } => i.AssignId(path, id.0 as u32),
CreatePlaceholder { id } => i.CreatePlaceholder(id.0 as u32),
CreateTextNode { value, id } => i.CreateTextNode(value.into(), id.0 as u32),