Skip to main content

rdom_core/
insert_adjacent.rs

1//! HTML-spec sugar over the lower-level `insert_adjacent` primitive:
2//! `insert_adjacent_element` and `insert_adjacent_text`. Same semantics as
3//! `Element.insertAdjacentElement` / `insertAdjacentText` in browsers.
4//!
5//! `insert_adjacent_html` is intentionally NOT included here: markup parsing
6//! belongs in `rdom-parser`, which will add `insert_adjacent_html` as an
7//! extension method once Phase 15 lands.
8
9use crate::dom::Dom;
10use crate::error::Result;
11use crate::node_id::NodeId;
12use crate::tree::AdjacentPosition;
13
14impl<Ext> Dom<Ext> {
15    /// Insert `new_element` adjacent to `reference`. Returns the inserted
16    /// element's id on success. Errors if `reference` has no parent for
17    /// `BeforeBegin`/`AfterEnd`, or if the hierarchy would cycle.
18    pub fn insert_adjacent_element(
19        &mut self,
20        reference: NodeId,
21        position: AdjacentPosition,
22        new_element: NodeId,
23    ) -> Result<NodeId> {
24        self.insert_adjacent(reference, position, new_element)?;
25        Ok(new_element)
26    }
27}
28
29impl<Ext: Default> Dom<Ext> {
30    /// Insert a freshly-created Text node containing `text` adjacent to
31    /// `reference`. Returns the new Text node's id.
32    pub fn insert_adjacent_text(
33        &mut self,
34        reference: NodeId,
35        position: AdjacentPosition,
36        text: &str,
37    ) -> Result<NodeId> {
38        let t = self.create_text_node(text);
39        self.insert_adjacent(reference, position, t)?;
40        Ok(t)
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use crate::{AdjacentPosition, Dom};
47
48    #[test]
49    fn insert_adjacent_element_before_begin() {
50        let mut dom: Dom = Dom::new();
51        let root = dom.root();
52        let ref_el = dom.create_element("mid");
53        let before = dom.create_element("before");
54        dom.append_child(root, ref_el).unwrap();
55        let ret = dom
56            .insert_adjacent_element(ref_el, AdjacentPosition::BeforeBegin, before)
57            .unwrap();
58        assert_eq!(ret, before);
59        assert_eq!(dom.node(root).first_child().map(|n| n.id()), Some(before));
60    }
61
62    #[test]
63    fn insert_adjacent_element_after_end() {
64        let mut dom: Dom = Dom::new();
65        let root = dom.root();
66        let ref_el = dom.create_element("mid");
67        let after = dom.create_element("after");
68        dom.append_child(root, ref_el).unwrap();
69        dom.insert_adjacent_element(ref_el, AdjacentPosition::AfterEnd, after)
70            .unwrap();
71        assert_eq!(dom.node(root).last_child().map(|n| n.id()), Some(after));
72    }
73
74    #[test]
75    fn insert_adjacent_element_returns_id() {
76        let mut dom: Dom = Dom::new();
77        let root = dom.root();
78        let parent = dom.create_element("p");
79        dom.append_child(root, parent).unwrap();
80        let child = dom.create_element("c");
81        let id = dom
82            .insert_adjacent_element(parent, AdjacentPosition::BeforeEnd, child)
83            .unwrap();
84        assert_eq!(id, child);
85    }
86
87    #[test]
88    fn insert_adjacent_text_creates_text_node() {
89        let mut dom: Dom = Dom::new();
90        let root = dom.root();
91        let el = dom.create_element("div");
92        dom.append_child(root, el).unwrap();
93        let tid = dom
94            .insert_adjacent_text(el, AdjacentPosition::AfterBegin, "hello")
95            .unwrap();
96        assert_eq!(dom.node(tid).node_value(), Some("hello"));
97        assert_eq!(dom.node(el).first_child().map(|n| n.id()), Some(tid));
98    }
99
100    #[test]
101    fn insert_adjacent_text_at_all_positions() {
102        for pos in [
103            AdjacentPosition::BeforeBegin,
104            AdjacentPosition::AfterBegin,
105            AdjacentPosition::BeforeEnd,
106            AdjacentPosition::AfterEnd,
107        ] {
108            let mut dom: Dom = Dom::new();
109            let root = dom.root();
110            let el = dom.create_element("span");
111            dom.append_child(root, el).unwrap();
112            let t = dom.insert_adjacent_text(el, pos, "t").unwrap();
113            assert_eq!(dom.node(t).node_value(), Some("t"));
114        }
115    }
116
117    #[test]
118    fn insert_adjacent_element_errors_on_orphan_before_begin() {
119        let mut dom: Dom = Dom::new();
120        let orphan = dom.create_element("orphan"); // no parent
121        let other = dom.create_element("other");
122        assert!(
123            dom.insert_adjacent_element(orphan, AdjacentPosition::BeforeBegin, other)
124                .is_err()
125        );
126    }
127}