blitz_dom/
query_selector.rs1use 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 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 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 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 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 pub fn query_selector(&self, selector: &str) -> Result<Option<NodeId>, ParseError> {
63 self.query_selector_in(self.root_node_id, selector)
64 }
65
66 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 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 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 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 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 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 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 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 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 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 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 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 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}