Skip to content

Commit

Permalink
Add VNode::from_html_unchecked (#2842)
Browse files Browse the repository at this point in the history
* Add VNode::html_from_raw

* Add docs for VNode::html_from_raw

* feature lock to available flags

* Actually raw

* Formatting + docs

* Tests

* More tests + docs

* fmt

* clippy

* CI

* No <div> around multi top-level nodes

* Update docs

* Fix braw detach

* Clippy & fmt

* Fix compile errors

* I hope you get attacked by Cow, Clippy

* Address review

* Reduce DOM calls

* improve detach bundle impl

* Add more tests

* Update example

* fmt

* Apply review suggestions

* fmt

* fix ci

* fix braw shift with multiple nodes

* rename function name

* fmt

* this should've been there

* ci be green
  • Loading branch information
hamza1311 committed Nov 8, 2022
1 parent a5f844d commit 90c7ff1
Show file tree
Hide file tree
Showing 13 changed files with 810 additions and 28 deletions.
4 changes: 0 additions & 4 deletions examples/inner_html/src/document.html
Expand Up @@ -4,10 +4,6 @@ <h2>Inline HTML with SVG</h2>
Rust source code. The code queries the DOM, creates a new element, and applies
this snippet of HTML to the element's innerHTML.
</p>
<p>
If you look at your browser's console you can see the DOM element (logged to
the console).
</p>
<svg height="250" width="500">
<polygon
points="220,10 300,210 170,250 123,234"
Expand Down
14 changes: 3 additions & 11 deletions examples/inner_html/src/main.rs
@@ -1,27 +1,19 @@
use web_sys::console;
use yew::{Component, Context, Html};

const HTML: &str = include_str!("document.html");

pub struct App {
pub value: i64,
}
pub struct App;

impl Component for App {
type Message = ();
type Properties = ();

fn create(_ctx: &Context<Self>) -> Self {
Self { value: 0 }
Self
}

fn view(&self, _ctx: &Context<Self>) -> Html {
let div = gloo::utils::document().create_element("div").unwrap();
div.set_inner_html(HTML);
// See <https://github.com/yewstack/yew/issues/1546>
console::log_1(&div);

Html::VRef(div.into())
Html::from_html_unchecked(HTML.into())
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/yew/Cargo.toml
Expand Up @@ -56,6 +56,7 @@ features = [
"FocusEvent",
"HtmlElement",
"HtmlInputElement",
"HtmlCollection",
"HtmlTextAreaElement",
"InputEvent",
"InputEventInit",
Expand Down Expand Up @@ -91,6 +92,7 @@ version = "0.3"
features = [
"ShadowRootInit",
"ShadowRootMode",
"HtmlButtonElement"
]

[features]
Expand Down
25 changes: 24 additions & 1 deletion packages/yew/src/dom_bundle/bnode.rs
Expand Up @@ -4,7 +4,7 @@ use std::fmt;

use web_sys::{Element, Node};

use super::{BComp, BList, BPortal, BSubtree, BSuspense, BTag, BText};
use super::{BComp, BList, BPortal, BRaw, BSubtree, BSuspense, BTag, BText};
use crate::dom_bundle::{Reconcilable, ReconcileTarget};
use crate::html::{AnyScope, NodeRef};
use crate::virtual_dom::{Key, VNode};
Expand All @@ -25,6 +25,8 @@ pub(super) enum BNode {
Ref(Node),
/// A suspendible document fragment.
Suspense(Box<BSuspense>),
/// A raw HTML string, represented by [`AttrValue`](crate::AttrValue).
Raw(BRaw),
}

impl BNode {
Expand All @@ -38,6 +40,7 @@ impl BNode {
Self::Text(_) => None,
Self::Portal(bportal) => bportal.key(),
Self::Suspense(bsusp) => bsusp.key(),
Self::Raw(_) => None,
}
}
}
Expand All @@ -58,6 +61,7 @@ impl ReconcileTarget for BNode {
}
Self::Portal(bportal) => bportal.detach(root, parent, parent_to_detach),
Self::Suspense(bsusp) => bsusp.detach(root, parent, parent_to_detach),
Self::Raw(raw) => raw.detach(root, parent, parent_to_detach),
}
}

Expand All @@ -76,6 +80,7 @@ impl ReconcileTarget for BNode {
}
Self::Portal(ref vportal) => vportal.shift(next_parent, next_sibling),
Self::Suspense(ref vsuspense) => vsuspense.shift(next_parent, next_sibling),
Self::Raw(ref braw) => braw.shift(next_parent, next_sibling),
}
}
}
Expand Down Expand Up @@ -120,6 +125,10 @@ impl Reconcilable for VNode {
vsuspsense.attach(root, parent_scope, parent, next_sibling);
(node_ref, suspsense.into())
}
VNode::VRaw(vraw) => {
let (node_ref, raw) = vraw.attach(root, parent_scope, parent, next_sibling);
(node_ref, raw.into())
}
}
}

Expand Down Expand Up @@ -176,6 +185,9 @@ impl Reconcilable for VNode {
VNode::VSuspense(vsuspsense) => {
vsuspsense.reconcile_node(root, parent_scope, parent, next_sibling, bundle)
}
VNode::VRaw(vraw) => {
vraw.reconcile_node(root, parent_scope, parent, next_sibling, bundle)
}
}
}
}
Expand Down Expand Up @@ -222,6 +234,13 @@ impl From<BSuspense> for BNode {
}
}

impl From<BRaw> for BNode {
#[inline]
fn from(braw: BRaw) -> Self {
Self::Raw(braw)
}
}

impl fmt::Debug for BNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Expand All @@ -232,6 +251,7 @@ impl fmt::Debug for BNode {
Self::Ref(ref vref) => write!(f, "VRef ( \"{}\" )", crate::utils::print_node(vref)),
Self::Portal(ref vportal) => vportal.fmt(f),
Self::Suspense(ref bsusp) => bsusp.fmt(f),
Self::Raw(ref braw) => braw.fmt(f),
}
}
}
Expand Down Expand Up @@ -285,6 +305,9 @@ mod feat_hydration {
vsuspense.hydrate(root, parent_scope, parent, fragment);
(node_ref, suspense.into())
}
VNode::VRaw(_) => {
panic!("VRaw is not hydratable (raw HTML string cannot be hydrated)")
}
}
}
}
Expand Down

0 comments on commit 90c7ff1

Please sign in to comment.