use crate::dom::Dom;
use crate::dom_string_map::{DomStringMap, DomStringMapMut};
use crate::error::{DomError, Result};
use crate::node::{NodeData, NodeType};
use crate::node_id::NodeId;
use crate::node_list::NodeList;
use crate::node_or_string::NodeOrString;
use crate::token_list::{DomTokenList, DomTokenListMut};
use crate::tree::AdjacentPosition;
#[derive(Clone, Copy)]
pub struct NodeRef<'a, Ext: 'static = ()> {
pub(crate) dom: &'a Dom<Ext>,
pub(crate) id: NodeId,
}
impl<'a, Ext: 'static> NodeRef<'a, Ext> {
pub fn id(&self) -> NodeId {
self.id
}
pub fn dom(&self) -> &'a Dom<Ext> {
self.dom
}
pub fn node_type(&self) -> NodeType {
self.dom
.get_node(self.id)
.map(|n| n.node_type())
.unwrap_or_else(|| panic!("NodeRef::node_type on a node that is not live: {}", self.id))
}
pub fn node_name(&self) -> &'a str {
let n = self.dom.get_node(self.id).unwrap_or_else(|| {
panic!("NodeRef::node_name on a node that is not live: {}", self.id)
});
match &n.data {
NodeData::Element { tag, .. } => tag,
NodeData::Text { .. } => "#text",
NodeData::Comment { .. } => "#comment",
NodeData::Fragment => "#document-fragment",
}
}
pub fn tag_name(&self) -> Option<&'a str> {
self.dom.get_node(self.id).and_then(|n| n.tag_name())
}
pub fn ext(&self) -> Option<&'a Ext> {
match &self.dom.get_node(self.id)?.data {
NodeData::Element { ext, .. } => Some(ext),
_ => None,
}
}
pub fn node_value(&self) -> Option<&'a str> {
match &self.dom.get_node(self.id)?.data {
NodeData::Text { data } | NodeData::Comment { data } => Some(data),
_ => None,
}
}
pub fn data(&self) -> Option<&'a str> {
self.node_value()
}
pub fn text_content(&self) -> String {
self.dom.text_content(self.id)
}
pub fn parent_node(&self) -> Option<NodeRef<'a, Ext>> {
let p = self.dom.get_node(self.id)?.parent?;
Some(NodeRef {
dom: self.dom,
id: p,
})
}
pub fn parent_element(&self) -> Option<NodeRef<'a, Ext>> {
let mut current = self.parent_node();
while let Some(p) = current {
if p.node_type() == NodeType::Element {
return Some(p);
}
current = p.parent_node();
}
None
}
pub fn first_child(&self) -> Option<NodeRef<'a, Ext>> {
let f = self.dom.get_node(self.id)?.first_child?;
Some(NodeRef {
dom: self.dom,
id: f,
})
}
pub fn last_child(&self) -> Option<NodeRef<'a, Ext>> {
let l = self.dom.get_node(self.id)?.last_child?;
Some(NodeRef {
dom: self.dom,
id: l,
})
}
pub fn previous_sibling(&self) -> Option<NodeRef<'a, Ext>> {
let p = self.dom.get_node(self.id)?.prev_sibling?;
Some(NodeRef {
dom: self.dom,
id: p,
})
}
pub fn next_sibling(&self) -> Option<NodeRef<'a, Ext>> {
let n = self.dom.get_node(self.id)?.next_sibling?;
Some(NodeRef {
dom: self.dom,
id: n,
})
}
pub fn has_child_nodes(&self) -> bool {
self.dom
.get_node(self.id)
.and_then(|n| n.first_child)
.is_some()
}
pub fn child_nodes(&self) -> ChildIter<'a, Ext> {
ChildIter {
dom: self.dom,
next: self.dom.get_node(self.id).and_then(|n| n.first_child),
}
}
pub fn first_element_child(&self) -> Option<NodeRef<'a, Ext>> {
let mut c = self.first_child();
while let Some(n) = c {
if n.node_type() == NodeType::Element {
return Some(n);
}
c = n.next_sibling();
}
None
}
pub fn last_element_child(&self) -> Option<NodeRef<'a, Ext>> {
let mut c = self.last_child();
while let Some(n) = c {
if n.node_type() == NodeType::Element {
return Some(n);
}
c = n.previous_sibling();
}
None
}
pub fn previous_element_sibling(&self) -> Option<NodeRef<'a, Ext>> {
let mut s = self.previous_sibling();
while let Some(n) = s {
if n.node_type() == NodeType::Element {
return Some(n);
}
s = n.previous_sibling();
}
None
}
pub fn next_element_sibling(&self) -> Option<NodeRef<'a, Ext>> {
let mut s = self.next_sibling();
while let Some(n) = s {
if n.node_type() == NodeType::Element {
return Some(n);
}
s = n.next_sibling();
}
None
}
pub fn children(&self) -> ElementChildIter<'a, Ext> {
ElementChildIter {
inner: self.child_nodes(),
}
}
pub fn child_element_count(&self) -> usize {
self.children().count()
}
pub fn id_attr(&self) -> Option<&'a str> {
self.get_attribute("id")
}
pub fn get_attribute(&self, key: &str) -> Option<&'a str> {
self.dom.get_attribute(self.id, key)
}
pub fn has_attribute(&self, key: &str) -> bool {
self.dom.has_attribute(self.id, key)
}
pub fn has_class(&self, class: &str) -> bool {
self.dom.has_class(self.id, class)
}
pub fn attributes(&self) -> impl Iterator<Item = (&'a str, &'a str)> {
self.dom.attributes(self.id)
}
pub fn class_name(&self) -> &'a str {
self.get_attribute("class").unwrap_or("")
}
pub fn class_list(&self) -> DomTokenList {
DomTokenList::from_tokens(self.dom.class_list(self.id).map(str::to_owned))
}
pub fn contains(&self, other: NodeId) -> bool {
self.dom.is_ancestor(self.id, other)
}
pub fn is_same_node(&self, other: NodeId) -> bool {
self.id == other
}
pub fn is_connected(&self) -> bool {
self.dom.is_ancestor(self.dom.root(), self.id)
}
pub fn get_root_node(&self) -> NodeRef<'a, Ext> {
let mut cur = self.id;
loop {
match self.dom.get_node(cur).and_then(|n| n.parent) {
Some(p) => cur = p,
None => {
return NodeRef {
dom: self.dom,
id: cur,
};
}
}
}
}
pub fn matches(&self, selector: &str) -> bool {
self.dom.matches(self.id, selector).unwrap_or(false)
}
pub fn closest(&self, selector: &str) -> Option<NodeRef<'a, Ext>> {
self.dom
.closest(self.id, selector)
.ok()
.flatten()
.map(|id| NodeRef { dom: self.dom, id })
}
pub fn query_selector(&self, selector: &str) -> Option<NodeRef<'a, Ext>> {
self.dom
.query_selector_in(self.id, selector)
.ok()
.flatten()
.filter(|&id| id != self.id)
.map(|id| NodeRef { dom: self.dom, id })
}
pub fn query_selector_all(&self, selector: &str) -> NodeList<'a, Ext> {
let ids = self
.dom
.query_selector_all_in(self.id, selector)
.unwrap_or_default()
.into_iter()
.filter(|&id| id != self.id);
NodeList::from_ids(self.dom, ids)
}
pub fn dataset(&self) -> DomStringMap<'a, Ext> {
DomStringMap::new(NodeRef {
dom: self.dom,
id: self.id,
})
}
pub fn tab_index(&self) -> Option<i32> {
self.get_attribute("tabindex")?.parse().ok()
}
pub fn hidden(&self) -> bool {
self.has_attribute("hidden")
}
pub fn content_editable(&self) -> &'a str {
self.get_attribute("contenteditable").unwrap_or("inherit")
}
pub fn inner_html(&self) -> String {
self.dom.inner_markup(self.id)
}
pub fn outer_html(&self) -> String {
self.dom.outer_markup(self.id)
}
}
mod node_mut;
pub use node_mut::NodeMut;
pub struct ChildIter<'a, Ext: 'static> {
dom: &'a Dom<Ext>,
next: Option<NodeId>,
}
impl<'a, Ext: 'static> Iterator for ChildIter<'a, Ext> {
type Item = NodeRef<'a, Ext>;
fn next(&mut self) -> Option<Self::Item> {
let current = self.next?;
self.next = self.dom.get_node(current).and_then(|n| n.next_sibling);
Some(NodeRef {
dom: self.dom,
id: current,
})
}
}
pub struct ElementChildIter<'a, Ext: 'static> {
inner: ChildIter<'a, Ext>,
}
impl<'a, Ext: 'static> Iterator for ElementChildIter<'a, Ext> {
type Item = NodeRef<'a, Ext>;
fn next(&mut self) -> Option<Self::Item> {
self.inner
.by_ref()
.find(|n| n.node_type() == NodeType::Element)
}
}
impl<Ext> Dom<Ext> {
pub fn node(&self, id: NodeId) -> NodeRef<'_, Ext> {
NodeRef { dom: self, id }
}
pub fn node_mut(&mut self, id: NodeId) -> NodeMut<'_, Ext> {
NodeMut { dom: self, id }
}
pub fn root_ref(&self) -> NodeRef<'_, Ext> {
self.node(self.root())
}
}
#[cfg(test)]
mod tests;