Skip to content

Commit

Permalink
Add VNode::html_from_raw
Browse files Browse the repository at this point in the history
  • Loading branch information
hamza1311 committed Aug 24, 2022
1 parent 72213ee commit 609e3c5
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 1 deletion.
3 changes: 2 additions & 1 deletion packages/yew/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ serde = { version = "1", features = ["derive"] }
tokio = { version = "1.19", features = ["sync"] }
tokio-stream = { version = "0.1.9", features = ["sync"] }
tracing = "0.1.36"
html_parser = { version = "0.6", optional = true }

[dependencies.web-sys]
version = "^0.3.59"
Expand Down Expand Up @@ -96,7 +97,7 @@ features = [

[features]
tokio = ["tokio/rt", "tokio/time", "dep:num_cpus", "dep:tokio-util"]
ssr = ["dep:html-escape", "dep:base64ct", "dep:bincode"]
ssr = ["dep:html-escape", "dep:base64ct", "dep:bincode", "dep:html_parser"]
csr = []
hydration = ["csr", "dep:bincode"]
default = []
Expand Down
94 changes: 94 additions & 0 deletions packages/yew/src/virtual_dom/vnode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,71 @@ impl VNode {
pub fn has_key(&self) -> bool {
self.key().is_some()
}

#[cfg(any(feature = "csr", feature = "hydration"))]
pub fn from_raw_html(html: &str) -> Self {
let div = gloo::utils::document().create_element("div").unwrap();
div.set_inner_html(html);
VNode::VRef(div.into())
}

#[cfg(feature = "ssr")]
pub fn from_raw_html(html: &str) -> Self {
use html_parser::{Dom, Node};

use super::{ApplyAttributeAs, Attributes};
use crate::{AttrValue, Classes};
fn dom_node_to_vnode(node: Node) -> VNode {
match node {
Node::Text(text) => VNode::from(VText::new(text)),
Node::Element(element) => {
let mut tag = VTag::new(element.name);
if !element.attributes.is_empty() {
let attributes = element
.attributes
.into_iter()
.map(|(key, value)| {
(
AttrValue::from(key),
(
AttrValue::from(value.unwrap_or_default()),
ApplyAttributeAs::Attribute,
),
)
})
.collect();
tag.set_attributes(Attributes::IndexMap(attributes));
}
if let Some(id) = element.id {
tag.add_attribute("id", id)
}
if !element.classes.is_empty() {
tag.add_attribute("class", Classes::from(element.classes).to_string())
};
tag.add_children(
element
.children
.into_iter()
.map(dom_node_to_vnode)
.collect::<Vec<_>>(),
);
VNode::from(tag)
}
Node::Comment(_) => VNode::default(),
}
}

let dom = Dom::parse(html).map(|it| {
let vnodes = it
.children
.into_iter()
.map(dom_node_to_vnode)
.collect::<Vec<_>>();
VNode::from(VList::with_children(vnodes, None))
});
// error handling??
dom.unwrap()
}
}

impl Default for VNode {
Expand Down Expand Up @@ -202,3 +267,32 @@ mod feat_ssr {
}
}
}

#[cfg(test)]
mod tests {
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::wasm_bindgen_test as test;
#[cfg(target_arch = "wasm32")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);

use super::*;
use crate::html;

const HTML: &str = r#"<div><a>a link</a><button>click me</button></div><p>paragraph</p>"#;
// const HTML: &str = r#"<div><a href="https://yew.rs">a link</a><button>click me</button></div><p>paragraph</p>"#;

#[test]
fn from_raw_html_works() {
let vnode = html! {
<><div>{"div"}</div></>
};

eprintln!("{:#?}", vnode);

let from_raw = VNode::from_raw_html("<div>div</div>");
eprintln!();
eprintln!("{:#?}", from_raw);

assert_eq!(vnode, from_raw);
}
}

0 comments on commit 609e3c5

Please sign in to comment.