use crate::dom_tree::{Node, NodeData};
use crate::matcher::InnerSelector;
use markup5ever::{namespace_url, ns};
use selectors::attr::AttrSelectorOperation;
use selectors::attr::CaseSensitivity;
use selectors::attr::NamespaceConstraint;
use selectors::context::MatchingContext;
use selectors::matching::ElementSelectorFlags;
use selectors::parser::SelectorImpl;
use selectors::OpaqueElement;
use std::ops::Deref;
impl<'a> selectors::Element for Node<'a> {
type Impl = InnerSelector;
fn opaque(&self) -> OpaqueElement {
OpaqueElement::new(&self.id)
}
fn parent_element(&self) -> Option<Self> {
self.parent()
}
fn parent_node_is_shadow_root(&self) -> bool {
false
}
fn containing_shadow_host(&self) -> Option<Self> {
None
}
fn is_pseudo_element(&self) -> bool {
false
}
fn prev_sibling_element(&self) -> Option<Self> {
self.prev_element_sibling()
}
fn next_sibling_element(&self) -> Option<Self> {
self.next_element_sibling()
}
fn is_html_element_in_html_document(&self) -> bool {
self.query(|node| {
if let NodeData::Element(ref e) = node.data {
return e.name.ns == ns!(html);
}
false
})
}
fn has_local_name(&self, local_name: &<Self::Impl as SelectorImpl>::BorrowedLocalName) -> bool {
self.query(|node| {
if let NodeData::Element(ref e) = node.data {
return &e.name.local == local_name;
}
false
})
}
fn has_namespace(&self, ns: &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl) -> bool {
self.query(|node| {
if let NodeData::Element(ref e) = node.data {
return &e.name.ns == ns;
}
false
})
}
fn is_same_type(&self, other: &Self) -> bool {
self.tree.compare_node(&self.id, &other.id, |a, b| {
if let NodeData::Element(ref e1) = a.data {
return match b.data {
NodeData::Element(ref e2) => e1.name == e2.name,
_ => false,
};
}
false
})
}
fn attr_matches(
&self,
ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
local_name: &<Self::Impl as SelectorImpl>::LocalName,
operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>,
) -> bool {
self.query(|node| {
if let NodeData::Element(ref e) = node.data {
return e.attrs.iter().any(|attr| match *ns {
NamespaceConstraint::Specific(url) if *url != attr.name.ns => false,
_ => *local_name == attr.name.local && operation.eval_str(&attr.value),
});
}
false
})
}
fn match_non_ts_pseudo_class<F>(
&self,
_pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
_context: &mut MatchingContext<Self::Impl>,
_flags_setter: &mut F,
) -> bool
where
F: FnMut(&Self, ElementSelectorFlags),
{
false
}
fn match_pseudo_element(
&self,
_pe: &<Self::Impl as SelectorImpl>::PseudoElement,
_context: &mut MatchingContext<Self::Impl>,
) -> bool {
false
}
fn is_link(&self) -> bool {
self.query(|node| {
if let NodeData::Element(ref e) = node.data {
return &e.name.local == "link";
}
false
})
}
fn is_html_slot_element(&self) -> bool {
true
}
fn has_id(
&self,
name: &<Self::Impl as SelectorImpl>::Identifier,
case_sensitivity: CaseSensitivity,
) -> bool {
self.query(|node| {
if let NodeData::Element(ref e) = node.data {
return e.attrs.iter().any(|attr| {
attr.name.local.deref() == "id"
&& case_sensitivity.eq(name.as_bytes(), attr.value.as_bytes())
});
}
false
})
}
fn has_class(
&self,
name: &<Self::Impl as SelectorImpl>::ClassName,
case_sensitivity: CaseSensitivity,
) -> bool {
self.query(|node| {
if let NodeData::Element(ref e) = node.data {
return e
.attrs
.iter()
.find(|a| a.name.local.deref() == "class")
.map_or(vec![], |a| a.value.deref().split_whitespace().collect())
.iter()
.any(|c| case_sensitivity.eq(name.as_bytes(), c.as_bytes()));
}
false
})
}
fn exported_part(
&self,
_name: &<Self::Impl as SelectorImpl>::PartName,
) -> Option<<Self::Impl as SelectorImpl>::PartName> {
None
}
fn imported_part(
&self,
_name: &<Self::Impl as SelectorImpl>::PartName,
) -> Option<<Self::Impl as SelectorImpl>::PartName> {
None
}
fn is_part(&self, _name: &<Self::Impl as SelectorImpl>::PartName) -> bool {
false
}
fn is_empty(&self) -> bool {
!self
.children()
.iter()
.any(|child| child.is_element() || child.is_text())
}
fn is_root(&self) -> bool {
self.is_document()
}
}