blitz_dom/
query_selector.rs

1use selectors::SelectorList;
2use smallvec::SmallVec;
3use style::dom_apis::{MayUseInvalidation, QueryAll, QueryFirst, query_selector};
4use style::selector_parser::{SelectorImpl, SelectorParser};
5use style::stylesheets::UrlExtraData;
6use style_traits::ParseError;
7use url::Url;
8
9use crate::{BaseDocument, Node};
10
11impl BaseDocument {
12    /// Find the first node that matches the selector specified as a string
13    /// Returns:
14    ///   - Err(_) if parsing the selector fails
15    ///   - Ok(None) if nothing matches
16    ///   - Ok(Some(node_id)) with the first node ID that matches if one is found
17    pub fn query_selector<'input>(
18        &self,
19        selector: &'input str,
20    ) -> Result<Option<usize>, ParseError<'input>> {
21        let selector_list = self.try_parse_selector_list(selector)?;
22        Ok(self.query_selector_raw(&selector_list))
23    }
24
25    /// Find the first node that matches the selector(s) specified in selector_list
26    pub fn query_selector_raw(&self, selector_list: &SelectorList<SelectorImpl>) -> Option<usize> {
27        let root_node = self.root_node();
28        let mut result = None;
29        query_selector::<&Node, QueryFirst>(
30            root_node,
31            selector_list,
32            &mut result,
33            MayUseInvalidation::Yes,
34        );
35
36        result.map(|node| node.id)
37    }
38
39    /// Find all nodes that match the selector specified as a string
40    /// Returns:
41    ///   - Err(_) if parsing the selector fails
42    ///   - Ok(SmallVec<usize>) with all matching nodes otherwise
43    pub fn query_selector_all<'input>(
44        &self,
45        selector: &'input str,
46    ) -> Result<SmallVec<[usize; 32]>, ParseError<'input>> {
47        let selector_list = self.try_parse_selector_list(selector)?;
48        Ok(self.query_selector_all_raw(&selector_list))
49    }
50
51    /// Find all nodes that match the selector(s) specified in selector_list
52    pub fn query_selector_all_raw(
53        &self,
54        selector_list: &SelectorList<SelectorImpl>,
55    ) -> SmallVec<[usize; 32]> {
56        let root_node = self.root_node();
57        let mut results = SmallVec::new();
58        query_selector::<&Node, QueryAll>(
59            root_node,
60            selector_list,
61            &mut results,
62            MayUseInvalidation::Yes,
63        );
64
65        results.iter().map(|node| node.id).collect()
66    }
67
68    pub fn try_parse_selector_list<'input>(
69        &self,
70        input: &'input str,
71    ) -> Result<SelectorList<SelectorImpl>, ParseError<'input>> {
72        let url_extra_data = UrlExtraData::from(self.base_url.clone().unwrap_or_else(|| {
73            "data:text/css;charset=utf-8;base64,"
74                .parse::<Url>()
75                .unwrap()
76        }));
77        SelectorParser::parse_author_origin_no_namespace(input, &url_extra_data)
78    }
79}