Skip to content

Commit

Permalink
Namespace support for VRaw. (#3640)
Browse files Browse the repository at this point in the history
* WIP.

* fmt.

* Fix parameter order.

* Cleanup.

* Change the docs.

* WIP test.

* fmt.

* Cast node to element.

* Fix test.

* Fix html in test.

* Typo.
  • Loading branch information
finnbear committed May 10, 2024
1 parent e9739fc commit dbdd3b7
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
48 changes: 43 additions & 5 deletions packages/yew/src/dom_bundle/braw.rs
Expand Up @@ -3,6 +3,7 @@ use web_sys::{Element, Node};

use super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget};
use crate::html::AnyScope;
use crate::virtual_dom::vtag::{MATHML_NAMESPACE, SVG_NAMESPACE};
use crate::virtual_dom::VRaw;
use crate::AttrValue;

Expand All @@ -14,8 +15,10 @@ pub struct BRaw {
}

impl BRaw {
fn create_elements(html: &str) -> Vec<Node> {
let div = gloo::utils::document().create_element("div").unwrap();
fn create_elements(html: &str, parent_namespace: Option<&str>) -> Vec<Node> {
let div = gloo::utils::document()
.create_element_ns(parent_namespace, "div")
.unwrap();
div.set_inner_html(html);
let children = div.child_nodes();
let children = js_sys::Array::from(&children);
Expand Down Expand Up @@ -71,7 +74,21 @@ impl Reconcilable for VRaw {
parent: &Element,
slot: DomSlot,
) -> (DomSlot, Self::Bundle) {
let elements = BRaw::create_elements(&self.html);
let namespace = if parent
.namespace_uri()
.map_or(false, |ns| ns == SVG_NAMESPACE)
{
Some(SVG_NAMESPACE)
} else if parent
.namespace_uri()
.map_or(false, |ns| ns == MATHML_NAMESPACE)
{
Some(MATHML_NAMESPACE)
} else {
None
};

let elements = BRaw::create_elements(&self.html, namespace);
let count = elements.len();
let mut iter = elements.into_iter();
let reference = iter.next();
Expand Down Expand Up @@ -160,7 +177,9 @@ mod tests {
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};

use super::*;
use crate::dom_bundle::utils::{setup_parent, setup_parent_and_sibling, SIBLING_CONTENT};
use crate::dom_bundle::utils::{
setup_parent, setup_parent_and_sibling, setup_parent_svg, SIBLING_CONTENT,
};
use crate::virtual_dom::VNode;

wasm_bindgen_test_configure!(run_in_browser);
Expand All @@ -173,7 +192,26 @@ mod tests {
let elem = VNode::from_html_unchecked(HTML.into());
let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());
assert_braw(&mut elem);
assert_eq!(parent.inner_html(), HTML)
assert_eq!(parent.inner_html(), HTML);
}

#[test]
fn braw_works_svg() {
let (root, scope, parent) = setup_parent_svg();

const HTML: &str = r#"<circle cx="50" cy="50" r="40"></circle>"#;
let elem = VNode::from_html_unchecked(HTML.into());
let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());
assert_braw(&mut elem);
assert_eq!(parent.inner_html(), HTML);
assert_eq!(
parent
.first_child()
.unwrap()
.unchecked_into::<Element>()
.namespace_uri(),
Some(SVG_NAMESPACE.to_owned())
);
}

#[test]
Expand Down
13 changes: 13 additions & 0 deletions packages/yew/src/dom_bundle/utils.rs
Expand Up @@ -64,6 +64,7 @@ mod tests {

use crate::dom_bundle::{BSubtree, DomSlot};
use crate::html::AnyScope;
use crate::virtual_dom::vtag::SVG_NAMESPACE;

pub fn setup_parent() -> (BSubtree, AnyScope, Element) {
let scope = AnyScope::test();
Expand All @@ -75,6 +76,18 @@ mod tests {
(root, scope, parent)
}

pub fn setup_parent_svg() -> (BSubtree, AnyScope, Element) {
let scope = AnyScope::test();
let parent = document()
.create_element_ns(Some(SVG_NAMESPACE), "svg")
.unwrap();
let root = BSubtree::create_root(&parent);

document().body().unwrap().append_child(&parent).unwrap();

(root, scope, parent)
}

pub const SIBLING_CONTENT: &str = "END";

pub(crate) fn setup_parent_and_sibling() -> (BSubtree, AnyScope, Element, DomSlot) {
Expand Down
4 changes: 2 additions & 2 deletions packages/yew/src/virtual_dom/vnode.rs
Expand Up @@ -76,8 +76,8 @@ impl VNode {
///
/// # Behavior in browser
///
/// In the browser, this function creates an element, sets the passed HTML to its `innerHTML`
/// and inserts the contents of it into the DOM.
/// In the browser, this function creates an element with the same XML namespace as the parent,
/// sets the passed HTML to its `innerHTML` and inserts the contents of it into the DOM.
///
/// # Behavior on server
///
Expand Down

0 comments on commit dbdd3b7

Please sign in to comment.