accessibility_scraper/html/
tree_sink.rs1use super::Html;
2use crate::node::{Doctype, Element, Node, ProcessingInstruction, Text};
3use crate::tendril_util::make as make_tendril;
4use ego_tree::NodeId;
5use fast_html5ever::tendril::StrTendril;
6use fast_html5ever::tree_builder::{ElementFlags, NodeOrText, QuirksMode, TreeSink};
7use fast_html5ever::Attribute;
8use fast_html5ever::{ExpandedName, QualName};
9use std::borrow::Cow;
10
11impl TreeSink for Html {
13    type Output = Self;
14    type Handle = NodeId;
15
16    fn finish(self) -> Self {
17        self
18    }
19
20    fn parse_error(&mut self, msg: Cow<'static, str>) {
22        #[cfg(feature = "errors")]
23        self.errors.push(msg);
24        #[cfg(not(feature = "errors"))]
25        let _ = msg;
26    }
27
28    fn set_quirks_mode(&mut self, mode: QuirksMode) {
30        self.quirks_mode = mode;
31    }
32
33    fn get_document(&mut self) -> Self::Handle {
35        self.tree.root().id()
36    }
37
38    fn same_node(&self, x: &Self::Handle, y: &Self::Handle) -> bool {
40        x == y
41    }
42
43    fn elem_name(&self, target: &Self::Handle) -> ExpandedName {
47        self.tree
48            .get(*target)
49            .unwrap()
50            .value()
51            .as_element()
52            .unwrap()
53            .name
54            .expanded()
55    }
56
57    fn create_element(
63        &mut self,
64        name: QualName,
65        attrs: Vec<Attribute>,
66        _flags: ElementFlags,
67    ) -> Self::Handle {
68        let mut node = self
69            .tree
70            .orphan(Node::Element(Element::new(name.clone(), attrs)));
71        if name.expanded() == expanded_name!(html "template") {
72            node.append(Node::Fragment);
73        }
74        node.id()
75    }
76
77    fn create_comment(&mut self, _text: StrTendril) {
79        }
85
86    fn append_doctype_to_document(
88        &mut self,
89        name: StrTendril,
90        public_id: StrTendril,
91        system_id: StrTendril,
92    ) {
93        let name = make_tendril(name);
94        let public_id = make_tendril(public_id);
95        let system_id = make_tendril(system_id);
96        let doctype = Doctype {
97            name,
98            public_id,
99            system_id,
100        };
101        self.tree.root_mut().append(Node::Doctype(doctype));
102    }
103
104    fn append(&mut self, parent: &Self::Handle, child: NodeOrText<Self::Handle>) {
109        let mut parent = self.tree.get_mut(*parent).unwrap();
110
111        match child {
112            NodeOrText::AppendNode(id) => {
113                parent.append_id(id);
114            }
115
116            NodeOrText::AppendText(text) => {
117                let text = make_tendril(text);
118                let can_concat = parent
119                    .last_child()
120                    .map_or(false, |mut n| n.value().is_text());
121
122                if can_concat {
123                    let mut last_child = parent.last_child().unwrap();
124                    match *last_child.value() {
125                        Node::Text(ref mut t) => t.text.push_tendril(&text),
126                        _ => unreachable!(),
127                    }
128                } else {
129                    parent.append(Node::Text(Text { text }));
130                }
131            }
132        }
133    }
134
135    fn append_before_sibling(
144        &mut self,
145        sibling: &Self::Handle,
146        new_node: NodeOrText<Self::Handle>,
147    ) {
148        if let NodeOrText::AppendNode(id) = new_node {
149            self.tree.get_mut(id).unwrap().detach();
150        }
151
152        let mut sibling = self.tree.get_mut(*sibling).unwrap();
153        if sibling.parent().is_some() {
154            match new_node {
155                NodeOrText::AppendNode(id) => {
156                    sibling.insert_id_before(id);
157                }
158
159                NodeOrText::AppendText(text) => {
160                    let text = make_tendril(text);
161                    let can_concat = sibling
162                        .prev_sibling()
163                        .map_or(false, |mut n| n.value().is_text());
164
165                    if can_concat {
166                        let mut prev_sibling = sibling.prev_sibling().unwrap();
167                        match *prev_sibling.value() {
168                            Node::Text(ref mut t) => t.text.push_tendril(&text),
169                            _ => unreachable!(),
170                        }
171                    } else {
172                        sibling.insert_before(Node::Text(Text { text }));
173                    }
174                }
175            }
176        }
177    }
178
179    fn remove_from_parent(&mut self, target: &Self::Handle) {
181        self.tree.get_mut(*target).unwrap().detach();
182    }
183
184    fn reparent_children(&mut self, node: &Self::Handle, new_parent: &Self::Handle) {
186        self.tree
187            .get_mut(*new_parent)
188            .unwrap()
189            .reparent_from_id_append(*node);
190    }
191
192    fn add_attrs_if_missing(&mut self, target: &Self::Handle, attrs: Vec<Attribute>) {
195        let mut node = self.tree.get_mut(*target).unwrap();
196        let element = match *node.value() {
197            Node::Element(ref mut e) => e,
198            _ => unreachable!(),
199        };
200
201        for attr in attrs {
202            element
203                .attrs
204                .entry(attr.name)
205                .or_insert_with(|| make_tendril(attr.value));
206        }
207    }
208
209    fn get_template_contents(&mut self, target: &Self::Handle) -> Self::Handle {
214        self.tree.get(*target).unwrap().first_child().unwrap().id()
215    }
216
217    fn mark_script_already_started(&mut self, _node: &Self::Handle) {}
219
220    fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> Self::Handle {
222        let target = make_tendril(target);
223        let data = make_tendril(data);
224        self.tree
225            .orphan(Node::ProcessingInstruction(ProcessingInstruction {
226                target,
227                data,
228            }))
229            .id()
230    }
231
232    fn append_based_on_parent_node(
233        &mut self,
234        element: &Self::Handle,
235        prev_element: &Self::Handle,
236        child: NodeOrText<Self::Handle>,
237    ) {
238        if self.tree.get(*element).unwrap().parent().is_some() {
239            self.append_before_sibling(element, child)
240        } else {
241            self.append(prev_element, child)
242        }
243    }
244}