Skip to main content

nipper_trunk/
element.rs

1use crate::dom_tree::{Node, NodeData};
2use crate::matcher::InnerSelector;
3use markup5ever::{namespace_url, ns};
4use selectors::attr::AttrSelectorOperation;
5use selectors::attr::CaseSensitivity;
6use selectors::attr::NamespaceConstraint;
7use selectors::context::MatchingContext;
8use selectors::matching::ElementSelectorFlags;
9use selectors::parser::SelectorImpl;
10use selectors::OpaqueElement;
11use std::ops::Deref;
12
13impl<'a> selectors::Element for Node<'a> {
14    type Impl = InnerSelector;
15
16    // Converts self into an opaque representation.
17    fn opaque(&self) -> OpaqueElement {
18        OpaqueElement::new(&self.id)
19    }
20
21    fn parent_element(&self) -> Option<Self> {
22        self.parent()
23    }
24
25    // Whether the parent node of this element is a shadow root.
26    fn parent_node_is_shadow_root(&self) -> bool {
27        false
28    }
29
30    // The host of the containing shadow root, if any.
31    fn containing_shadow_host(&self) -> Option<Self> {
32        None
33    }
34
35    // Whether we're matching on a pseudo-element.
36    fn is_pseudo_element(&self) -> bool {
37        false
38    }
39
40    // Skips non-element nodes.
41    fn prev_sibling_element(&self) -> Option<Self> {
42        self.prev_element_sibling()
43    }
44
45    // Skips non-element nodes.
46    fn next_sibling_element(&self) -> Option<Self> {
47        self.next_element_sibling()
48    }
49
50    fn is_html_element_in_html_document(&self) -> bool {
51        self.query(|node| {
52            if let NodeData::Element(ref e) = node.data {
53                return e.name.ns == ns!(html);
54            }
55
56            false
57        })
58    }
59
60    fn has_local_name(&self, local_name: &<Self::Impl as SelectorImpl>::BorrowedLocalName) -> bool {
61        self.query(|node| {
62            if let NodeData::Element(ref e) = node.data {
63                return &e.name.local == local_name;
64            }
65
66            false
67        })
68    }
69
70    // Empty string for no namespace.
71    fn has_namespace(&self, ns: &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl) -> bool {
72        self.query(|node| {
73            if let NodeData::Element(ref e) = node.data {
74                return &e.name.ns == ns;
75            }
76
77            false
78        })
79    }
80
81    // Whether this element and the `other` element have the same local name and namespace.
82    fn is_same_type(&self, other: &Self) -> bool {
83        self.tree.compare_node(&self.id, &other.id, |a, b| {
84            if let NodeData::Element(ref e1) = a.data {
85                return match b.data {
86                    NodeData::Element(ref e2) => e1.name == e2.name,
87                    _ => false,
88                };
89            }
90
91            false
92        })
93    }
94
95    fn attr_matches(
96        &self,
97        ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
98        local_name: &<Self::Impl as SelectorImpl>::LocalName,
99        operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>,
100    ) -> bool {
101        self.query(|node| {
102            if let NodeData::Element(ref e) = node.data {
103                return e.attrs.iter().any(|attr| match *ns {
104                    NamespaceConstraint::Specific(url) if *url != attr.name.ns => false,
105                    _ => *local_name == attr.name.local && operation.eval_str(&attr.value),
106                });
107            }
108
109            false
110        })
111    }
112
113    fn match_non_ts_pseudo_class<F>(
114        &self,
115        _pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
116        _context: &mut MatchingContext<Self::Impl>,
117        _flags_setter: &mut F,
118    ) -> bool
119    where
120        F: FnMut(&Self, ElementSelectorFlags),
121    {
122        false
123    }
124
125    fn match_pseudo_element(
126        &self,
127        _pe: &<Self::Impl as SelectorImpl>::PseudoElement,
128        _context: &mut MatchingContext<Self::Impl>,
129    ) -> bool {
130        false
131    }
132
133    // Whether this element is a `link`.
134    fn is_link(&self) -> bool {
135        self.query(|node| {
136            if let NodeData::Element(ref e) = node.data {
137                return &e.name.local == "link";
138            }
139
140            false
141        })
142    }
143
144    // Whether the element is an HTML element.
145    fn is_html_slot_element(&self) -> bool {
146        true
147    }
148
149    fn has_id(
150        &self,
151        name: &<Self::Impl as SelectorImpl>::Identifier,
152        case_sensitivity: CaseSensitivity,
153    ) -> bool {
154        self.query(|node| {
155            if let NodeData::Element(ref e) = node.data {
156                return e.attrs.iter().any(|attr| {
157                    attr.name.local.deref() == "id"
158                        && case_sensitivity.eq(name.as_bytes(), attr.value.as_bytes())
159                });
160            }
161
162            false
163        })
164    }
165
166    fn has_class(
167        &self,
168        name: &<Self::Impl as SelectorImpl>::ClassName,
169        case_sensitivity: CaseSensitivity,
170    ) -> bool {
171        self.query(|node| {
172            if let NodeData::Element(ref e) = node.data {
173                return e
174                    .attrs
175                    .iter()
176                    .find(|a| a.name.local.deref() == "class")
177                    .map_or(vec![], |a| a.value.deref().split_whitespace().collect())
178                    .iter()
179                    .any(|c| case_sensitivity.eq(name.as_bytes(), c.as_bytes()));
180            }
181
182            false
183        })
184    }
185
186    // Returns the mapping from the `exportparts` attribute in the regular direction, that is, inner-tree->outer-tree.
187    fn exported_part(
188        &self,
189        _name: &<Self::Impl as SelectorImpl>::PartName,
190    ) -> Option<<Self::Impl as SelectorImpl>::PartName> {
191        None
192    }
193
194    // Returns the mapping from the `exportparts` attribute in the regular direction, that is, outer-tree->inner-tree.
195    fn imported_part(
196        &self,
197        _name: &<Self::Impl as SelectorImpl>::PartName,
198    ) -> Option<<Self::Impl as SelectorImpl>::PartName> {
199        None
200    }
201
202    fn is_part(&self, _name: &<Self::Impl as SelectorImpl>::PartName) -> bool {
203        false
204    }
205
206    // Whether this element matches `:empty`.
207    fn is_empty(&self) -> bool {
208        !self
209            .children()
210            .iter()
211            .any(|child| child.is_element() || child.is_text())
212    }
213
214    // Whether this element matches `:root`, i.e. whether it is the root element of a document.
215    fn is_root(&self) -> bool {
216        self.is_document()
217    }
218}