Skip to content

Commit

Permalink
bundle for text nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
WorldSEnder committed Jan 5, 2022
1 parent 2d9479a commit 031976c
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 173 deletions.
18 changes: 9 additions & 9 deletions packages/yew/src/dom_bundle/bnode.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! This module contains the bundle version of an abstract node.

use super::{BComp, BList, BPortal, BSuspense, BTag};
use super::{BComp, BList, BPortal, BSuspense, BTag, BText};
use crate::dom_bundle::{DomBundle, Reconcilable};
use crate::html::{AnyScope, NodeRef};
use crate::virtual_dom::{Key, VNode, VText};
use crate::virtual_dom::{Key, VNode};
use gloo::console;
use std::fmt;
use web_sys::{Element, Node};
Expand All @@ -13,7 +13,7 @@ pub enum BNode {
/// A bind between `VTag` and `Element`.
BTag(Box<BTag>),
/// A bind between `VText` and `TextNode`.
BText(VText),
BText(BText),
/// A bind between `VComp` and `Element`.
BComp(BComp),
/// A holder for a list of other nodes.
Expand Down Expand Up @@ -57,7 +57,7 @@ impl DomBundle for BNode {
fn detach(self, parent: &Element) {
match self {
Self::BTag(vtag) => vtag.detach(parent),
Self::BText(vtext) => vtext.detach(parent),
Self::BText(btext) => btext.detach(parent),
Self::BComp(bsusp) => bsusp.detach(parent),
Self::BList(blist) => blist.detach(parent),
Self::BRef(ref node) => {
Expand All @@ -73,7 +73,7 @@ impl DomBundle for BNode {
fn shift(&self, next_parent: &Element, next_sibling: NodeRef) {
match self {
Self::BTag(ref vtag) => vtag.shift(next_parent, next_sibling),
Self::BText(ref vtext) => vtext.shift(next_parent, next_sibling),
Self::BText(ref btext) => btext.shift(next_parent, next_sibling),
Self::BComp(ref bsusp) => bsusp.shift(next_parent, next_sibling),
Self::BList(ref vlist) => vlist.shift(next_parent, next_sibling),
Self::BRef(ref node) => {
Expand Down Expand Up @@ -161,10 +161,10 @@ impl Reconcilable for VNode {
}
}

impl From<VText> for BNode {
impl From<BText> for BNode {
#[inline]
fn from(vtext: VText) -> Self {
Self::BText(vtext)
fn from(btext: BText) -> Self {
Self::BText(btext)
}
}

Expand Down Expand Up @@ -207,7 +207,7 @@ impl fmt::Debug for BNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::BTag(ref vtag) => vtag.fmt(f),
Self::BText(ref vtext) => vtext.fmt(f),
Self::BText(ref btext) => btext.fmt(f),
Self::BComp(ref bsusp) => bsusp.fmt(f),
Self::BList(ref vlist) => vlist.fmt(f),
Self::BRef(ref vref) => write!(f, "VRef ( \"{}\" )", crate::utils::print_node(vref)),
Expand Down
158 changes: 158 additions & 0 deletions packages/yew/src/dom_bundle/btext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
//! This module contains the bundle implementation of text [BText].

use super::{insert_node, BNode, DomBundle, Reconcilable};
use crate::html::AnyScope;
use crate::virtual_dom::{AttrValue, VText};
use crate::NodeRef;
use gloo::console;
use gloo_utils::document;
use web_sys::{Element, Text as TextNode};

/// Bind text to a dom element.
/// Reuses the virtual dom structure of text.
pub struct BText {
text: AttrValue,
text_node: TextNode,
}

impl DomBundle for BText {
/// Remove VText from parent.
fn detach(self, parent: &Element) {
let node = &self.text_node;
if parent.remove_child(node).is_err() {
console::warn!("Node not found to remove VText");
}
}

fn shift(&self, next_parent: &Element, next_sibling: NodeRef) {
let node = &self.text_node;

next_parent
.insert_before(node, next_sibling.get().as_ref())
.unwrap();
}
}

impl Reconcilable for VText {
type Bundle = BText;

fn attach(
self,
_parent_scope: &AnyScope,
parent: &Element,
next_sibling: NodeRef,
) -> (NodeRef, Self::Bundle) {
let Self { text } = self;
let text_node = document().create_text_node(&text);
insert_node(&text_node, parent, next_sibling.get().as_ref());
let node_ref = NodeRef::new(text_node.clone().into());
(node_ref, BText { text, text_node })
}

/// Renders virtual node over existing `TextNode`, but only if value of text has changed.
fn reconcile(
self,
parent_scope: &AnyScope,
parent: &Element,
next_sibling: NodeRef,
ancestor: &mut BNode,
) -> NodeRef {
let btext = match ancestor {
BNode::BText(btext) => btext,
_ => {
let (node_ref, self_) = self.attach(parent_scope, parent, next_sibling);
ancestor.replace(parent, self_.into());
return node_ref;
}
};
let Self { text } = self;
let ancestor_text = std::mem::replace(&mut btext.text, text);
if btext.text != ancestor_text {
btext.text_node.set_node_value(Some(&btext.text));
}
NodeRef::new(btext.text_node.clone().into())
}
}

impl std::fmt::Debug for BText {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "BText {{ text: \"{}\" }}", self.text)
}
}

#[cfg(test)]
mod test {
extern crate self as yew;

use crate::html;

#[cfg(feature = "wasm_test")]
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};

#[cfg(feature = "wasm_test")]
wasm_bindgen_test_configure!(run_in_browser);

#[test]
fn text_as_root() {
html! {
"Text Node As Root"
};

html! {
{ "Text Node As Root" }
};
}
}

#[cfg(test)]
mod layout_tests {
extern crate self as yew;

use crate::html;
use crate::tests::layout_tests::{diff_layouts, TestLayout};

#[cfg(feature = "wasm_test")]
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};

#[cfg(feature = "wasm_test")]
wasm_bindgen_test_configure!(run_in_browser);

#[test]
fn diff() {
let layout1 = TestLayout {
name: "1",
node: html! { "a" },
expected: "a",
};

let layout2 = TestLayout {
name: "2",
node: html! { "b" },
expected: "b",
};

let layout3 = TestLayout {
name: "3",
node: html! {
<>
{"a"}
{"b"}
</>
},
expected: "ab",
};

let layout4 = TestLayout {
name: "4",
node: html! {
<>
{"b"}
{"a"}
</>
},
expected: "ba",
};

diff_layouts(vec![layout1, layout2, layout3, layout4]);
}
}
2 changes: 2 additions & 0 deletions packages/yew/src/dom_bundle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod bnode;
mod bportal;
mod bsuspense;
mod btag;
mod btext;
mod listeners;

#[cfg(debug_assertions)]
Expand All @@ -23,6 +24,7 @@ pub use self::bnode::BNode;
pub use self::bportal::BPortal;
pub use self::bsuspense::BSuspense;
pub use self::btag::BTag;
pub use self::btext::BText;

pub(crate) use self::attributes::{Apply, InputFields, Value};
pub(crate) use self::bcomp::{Mountable, PropsWrapper};
Expand Down

0 comments on commit 031976c

Please sign in to comment.