1use crate::dom::Dom;
7use crate::error::Result;
8use crate::node::NodeData;
9use crate::node_id::NodeId;
10
11impl<Ext> Dom<Ext> {
12 pub fn text_content(&self, id: NodeId) -> String {
19 let mut out = String::new();
20 self.collect_text(id, &mut out);
21 out
22 }
23
24 fn collect_text(&self, id: NodeId, out: &mut String) {
27 self.walk_subtree(id, &mut |_, data| {
28 if let NodeData::Text { data } = data {
29 out.push_str(data);
30 }
31 });
32 }
33}
34
35impl<Ext: Default> Dom<Ext> {
36 pub fn set_text_content(&mut self, id: NodeId, text: &str) -> Result<()> {
45 use crate::error::DomError;
46 use crate::node::NodeType;
47
48 match &self.node_or_err(id)?.data {
49 NodeData::Element { .. } | NodeData::Fragment => {}
50 NodeData::Text { .. } => {
51 return Err(DomError::WrongNodeType {
52 expected: "Element or Fragment",
53 got: NodeType::Text,
54 });
55 }
56 NodeData::Comment { .. } => {
57 return Err(DomError::WrongNodeType {
58 expected: "Element or Fragment",
59 got: NodeType::Comment,
60 });
61 }
62 }
63
64 let existing: Vec<NodeId> = {
66 let mut out = Vec::new();
67 let mut c = self.get_node(id).and_then(|n| n.first_child);
68 while let Some(cid) = c {
69 out.push(cid);
70 c = self.get_node(cid).and_then(|n| n.next_sibling);
71 }
72 out
73 };
74 for cid in existing {
75 self.drop_subtree(cid)?;
76 }
77
78 if !text.is_empty() {
79 let t = self.create_text_node(text);
80 self.append_child(id, t)?;
81 }
82 Ok(())
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use crate::Dom;
89
90 #[test]
91 fn text_node_returns_own_data() {
92 let mut dom: Dom = Dom::new();
93 let t = dom.create_text_node("hello");
94 assert_eq!(dom.text_content(t), "hello");
95 }
96
97 #[test]
98 fn element_concatenates_descendant_text() {
99 let mut dom: Dom = Dom::new();
100 let div = dom.create_element("div");
101 let a = dom.create_text_node("hello ");
102 let span = dom.create_element("span");
103 let b = dom.create_text_node("world");
104 dom.append_child(span, b).unwrap();
105 dom.append_child(div, a).unwrap();
106 dom.append_child(div, span).unwrap();
107 assert_eq!(dom.text_content(div), "hello world");
108 }
109
110 #[test]
111 fn comment_children_not_included() {
112 let mut dom: Dom = Dom::new();
113 let div = dom.create_element("div");
114 let a = dom.create_text_node("before ");
115 let c = dom.create_comment(" skip me ");
116 let b = dom.create_text_node("after");
117 dom.append_child(div, a).unwrap();
118 dom.append_child(div, c).unwrap();
119 dom.append_child(div, b).unwrap();
120 assert_eq!(dom.text_content(div), "before after");
121 }
122
123 #[test]
124 fn empty_element_empty_text_content() {
125 let mut dom: Dom = Dom::new();
126 let div = dom.create_element("div");
127 assert_eq!(dom.text_content(div), "");
128 }
129
130 #[test]
131 fn set_text_content_replaces_children() {
132 let mut dom: Dom = Dom::new();
133 let div = dom.create_element("div");
134 let old_text = dom.create_text_node("old");
135 let old_span = dom.create_element("span");
136 dom.append_child(div, old_text).unwrap();
137 dom.append_child(div, old_span).unwrap();
138
139 dom.set_text_content(div, "new content").unwrap();
140
141 assert_eq!(dom.node(div).child_element_count(), 0);
142 assert_eq!(
143 dom.node(div).first_child().unwrap().node_value(),
144 Some("new content")
145 );
146 assert_eq!(dom.text_content(div), "new content");
147 }
148
149 #[test]
150 fn set_text_content_empty_clears_children() {
151 let mut dom: Dom = Dom::new();
152 let div = dom.create_element("div");
153 let t = dom.create_text_node("existing");
154 dom.append_child(div, t).unwrap();
155
156 dom.set_text_content(div, "").unwrap();
157
158 assert!(!dom.node(div).has_child_nodes());
159 }
160
161 #[test]
162 fn set_text_content_on_text_errors() {
163 let mut dom: Dom = Dom::new();
164 let t = dom.create_text_node("hi");
165 assert!(dom.set_text_content(t, "bye").is_err());
166 }
167
168 #[test]
169 fn set_text_content_on_fragment_works() {
170 let mut dom: Dom = Dom::new();
171 let frag = dom.create_document_fragment();
172 let old = dom.create_element("span");
173 dom.append_child(frag, old).unwrap();
174
175 dom.set_text_content(frag, "flat text").unwrap();
176 assert_eq!(dom.text_content(frag), "flat text");
177 }
178}