Skip to main content

blitz_dom/
query_selector.rs

1use blitz_traits::node_id::NodeId;
2use selectors::SelectorList;
3use smallvec::SmallVec;
4use style::dom::{TDocument, TNode};
5use style::dom_apis::{
6    MayUseInvalidation, QueryAll, QueryFirst, element_closest, element_matches, query_selector,
7};
8use style::selector_parser::{SelectorImpl, SelectorParser};
9use style_traits::ParseError;
10
11use crate::{BaseDocument, Node};
12
13impl BaseDocument {
14    /// Find the node with the specified id attribute (if one exists).
15    /// If multiple nodes have the same id, the first in tree order is returned.
16    pub fn get_element_by_id(&self, id: &str) -> Option<NodeId> {
17        match self.nodes_to_id.get(id)?.as_slice() {
18            [] => None,
19            [node_id] => Some(*node_id),
20            candidates => self.first_in_tree_order(candidates),
21        }
22    }
23
24    /// Find the first of `candidates` in tree order
25    fn first_in_tree_order(&self, candidates: &[NodeId]) -> Option<NodeId> {
26        let mut stack = vec![self.root_node_id];
27        while let Some(node_id) = stack.pop() {
28            if candidates.contains(&node_id) {
29                return Some(node_id);
30            }
31            stack.extend(self.nodes[node_id].children.iter().rev().copied());
32        }
33        None
34    }
35
36    /// Add a node to the id-to-node map
37    pub(crate) fn add_to_id_map(&mut self, id: &str, node_id: NodeId) {
38        if id.is_empty() {
39            return;
40        }
41        let node_ids = self.nodes_to_id.entry(id.to_string()).or_default();
42        if !node_ids.contains(&node_id) {
43            node_ids.push(node_id);
44        }
45    }
46
47    /// Remove a node from the id-to-node map
48    pub(crate) fn remove_from_id_map(&mut self, id: &str, node_id: NodeId) {
49        if let Some(node_ids) = self.nodes_to_id.get_mut(id) {
50            node_ids.retain(|nid| *nid != node_id);
51            if node_ids.is_empty() {
52                self.nodes_to_id.remove(id);
53            }
54        }
55    }
56
57    /// Find the first node that matches the selector specified as a string
58    /// Returns:
59    ///   - Err(_) if parsing the selector fails
60    ///   - Ok(None) if nothing matches
61    ///   - Ok(Some(node_id)) with the first node ID that matches if one is found
62    pub fn query_selector(&self, selector: &str) -> Result<Option<NodeId>, ParseError> {
63        self.query_selector_in(self.root_node_id, selector)
64    }
65
66    /// Find the first descendant of `scope` that matches the selector specified
67    /// as a string.
68    ///
69    /// The scope node itself is never matched. Selector parts may match nodes
70    /// outside the scope while evaluating relationships between descendants.
71    ///
72    /// Returns:
73    ///   - `Err(_)` if parsing the selector fails
74    ///   - `Ok(None)` if nothing matches
75    ///   - `Ok(Some(node_id))` with the first matching descendant ID otherwise
76    pub fn query_selector_in(
77        &self,
78        scope: NodeId,
79        selector: &str,
80    ) -> Result<Option<NodeId>, ParseError> {
81        let selector_list = self.try_parse_selector_list(selector)?;
82        Ok(self.query_selector_in_raw(scope, &selector_list))
83    }
84
85    /// Find the first descendant of the document root that matches the
86    /// selector(s) specified in `selector_list`.
87    ///
88    /// The document root itself is never matched. Selector parts may match
89    /// nodes outside the scope while evaluating relationships between
90    /// descendants.
91    pub fn query_selector_raw(&self, selector_list: &SelectorList<SelectorImpl>) -> Option<NodeId> {
92        self.query_selector_in_raw(self.root_node_id, selector_list)
93    }
94
95    /// Find the first descendant of `scope` that matches the selector(s)
96    /// specified in `selector_list`.
97    ///
98    /// The scope node itself is never matched. Selector parts may match nodes
99    /// outside the scope while evaluating relationships between descendants.
100    pub fn query_selector_in_raw(
101        &self,
102        scope: NodeId,
103        selector_list: &SelectorList<SelectorImpl>,
104    ) -> Option<NodeId> {
105        let root_node = &self.nodes[scope];
106        let mut result = None;
107        query_selector::<&Node, QueryFirst>(
108            root_node,
109            selector_list,
110            &mut result,
111            self.may_use_invalidation_for(scope),
112        );
113
114        result.map(|node| node.id)
115    }
116
117    /// Find all nodes that match the selector specified as a string
118    /// Returns:
119    ///   - `Err(_)` if parsing the selector fails
120    ///   - `Ok(SmallVec<usize>)` with all matching nodes otherwise
121    pub fn query_selector_all(&self, selector: &str) -> Result<SmallVec<[NodeId; 32]>, ParseError> {
122        self.query_selector_all_in(self.root_node_id, selector)
123    }
124
125    /// Find all descendants of `scope` that match the selector specified as a
126    /// string, in tree order.
127    ///
128    /// The scope node itself is never matched. Selector parts may match nodes
129    /// outside the scope while evaluating relationships between descendants.
130    ///
131    /// Returns:
132    ///   - `Err(_)` if parsing the selector fails
133    ///   - `Ok(_)` with all matching descendant IDs otherwise
134    pub fn query_selector_all_in(
135        &self,
136        scope: NodeId,
137        selector: &str,
138    ) -> Result<SmallVec<[NodeId; 32]>, ParseError> {
139        let selector_list = self.try_parse_selector_list(selector)?;
140        Ok(self.query_selector_all_in_raw(scope, &selector_list))
141    }
142
143    /// Find all descendants of the document root that match the selector(s)
144    /// specified in `selector_list`, in tree order.
145    ///
146    /// The document root itself is never matched. Selector parts may match
147    /// nodes outside the scope while evaluating relationships between
148    /// descendants.
149    pub fn query_selector_all_raw(
150        &self,
151        selector_list: &SelectorList<SelectorImpl>,
152    ) -> SmallVec<[NodeId; 32]> {
153        self.query_selector_all_in_raw(self.root_node_id, selector_list)
154    }
155
156    /// Find all descendants of `scope` that match the selector(s) specified in
157    /// `selector_list`, in tree order.
158    ///
159    /// The scope node itself is never matched. Selector parts may match nodes
160    /// outside the scope while evaluating relationships between descendants.
161    pub fn query_selector_all_in_raw(
162        &self,
163        scope: NodeId,
164        selector_list: &SelectorList<SelectorImpl>,
165    ) -> SmallVec<[NodeId; 32]> {
166        let root_node = &self.nodes[scope];
167        let mut results = SmallVec::new();
168        query_selector::<&Node, QueryAll>(
169            root_node,
170            selector_list,
171            &mut results,
172            self.may_use_invalidation_for(scope),
173        );
174
175        results.iter().map(|node| node.id).collect()
176    }
177
178    fn may_use_invalidation_for(&self, scope: NodeId) -> MayUseInvalidation {
179        if scope == self.root_node_id {
180            MayUseInvalidation::Yes
181        } else {
182            MayUseInvalidation::No
183        }
184    }
185
186    /// Test whether the node identified by `node_id` matches the selector
187    /// specified as a string.
188    ///
189    /// Non-element nodes never match.
190    pub fn matches_selector(&self, node_id: NodeId, selector: &str) -> Result<bool, ParseError> {
191        let selector_list = self.try_parse_selector_list(selector)?;
192        Ok(self.nodes[node_id].matches_selector_raw(&selector_list))
193    }
194
195    /// Find the closest matching element at or above the node identified by
196    /// `node_id`.
197    ///
198    /// Non-element nodes never match and return `None`.
199    pub fn closest(&self, node_id: NodeId, selector: &str) -> Result<Option<NodeId>, ParseError> {
200        let selector_list = self.try_parse_selector_list(selector)?;
201        Ok(self.nodes[node_id].closest_raw(&selector_list))
202    }
203
204    pub fn try_parse_selector_list(
205        &self,
206        input: &str,
207    ) -> Result<SelectorList<SelectorImpl>, ParseError> {
208        let url_extra_data = self.url.url_extra_data();
209        SelectorParser::parse_author_origin_no_namespace(input, &url_extra_data)
210    }
211}
212
213impl Node {
214    /// Find the first descendant of this node that matches the selector(s)
215    /// specified in `selector_list`.
216    ///
217    /// The scope node itself is never matched. Selector parts may match nodes
218    /// outside the scope while evaluating relationships between descendants.
219    ///
220    /// Text and comment scope nodes return no matches.
221    pub fn query_selector_raw(&self, selector_list: &SelectorList<SelectorImpl>) -> Option<NodeId> {
222        let mut result = None;
223        query_selector::<&Node, QueryFirst>(
224            self,
225            selector_list,
226            &mut result,
227            MayUseInvalidation::No,
228        );
229        result.map(|node| node.id)
230    }
231
232    /// Find all descendants of this node that match the selector(s) specified
233    /// in `selector_list`, in tree order.
234    ///
235    /// The scope node itself is never matched. Selector parts may match nodes
236    /// outside the scope while evaluating relationships between descendants.
237    ///
238    /// Text and comment scope nodes return no matches.
239    pub fn query_selector_all_raw(
240        &self,
241        selector_list: &SelectorList<SelectorImpl>,
242    ) -> SmallVec<[NodeId; 32]> {
243        let mut results = SmallVec::new();
244        query_selector::<&Node, QueryAll>(
245            self,
246            selector_list,
247            &mut results,
248            MayUseInvalidation::No,
249        );
250        results.iter().map(|node| node.id).collect()
251    }
252
253    /// Test whether this element matches the selector(s) specified in
254    /// `selector_list`.
255    ///
256    /// Non-element nodes never match.
257    pub fn matches_selector_raw(&self, selector_list: &SelectorList<SelectorImpl>) -> bool {
258        if !self.is_element() {
259            return false;
260        }
261
262        element_matches(&self, selector_list, self.owner_doc().quirks_mode())
263    }
264
265    /// Find the closest matching element at or above this element.
266    ///
267    /// Non-element nodes never match and return `None`.
268    pub fn closest_raw(&self, selector_list: &SelectorList<SelectorImpl>) -> Option<NodeId> {
269        if !self.is_element() {
270            return None;
271        }
272
273        element_closest(self, selector_list, self.owner_doc().quirks_mode()).map(|node| node.id)
274    }
275}