web_sys_query/query/
mod.rs

1//! The main `Query` interface.
2
3mod attributes;
4mod events;
5mod helpers;
6mod manipulation;
7mod traversing;
8
9use crate::error::Error;
10use derive_more::{AsRef, Deref, DerefMut, From, Into};
11use std::{
12    collections::VecDeque,
13    convert::{TryFrom, TryInto},
14    fmt,
15    iter::FromIterator,
16};
17use wasm_bindgen::JsCast;
18use web_sys::{HtmlCollection, HtmlElement, NodeList};
19
20pub use events::Event;
21pub use helpers::{FormData, FormValue};
22
23/// Document with jQuery-like methods.
24#[derive(AsRef, Clone, Debug, Deref, DerefMut, From, Into)]
25pub struct Document(web_sys::Document);
26
27impl Document {
28    pub fn new() -> Result<Self, Error> {
29        let inner = web_sys::window()
30            .ok_or(Error::DomElementNotFound("window"))?
31            .document()
32            .ok_or(Error::DomElementNotFound("document"))?;
33
34        Ok(Self(inner))
35    }
36
37    pub fn descendants(&self) -> Collection {
38        Element::try_from(self)
39            .as_ref()
40            .map(Element::descendants)
41            .unwrap_or_default()
42    }
43}
44
45/// Element with jQuery-like methods.
46#[derive(AsRef, Clone, Deref, DerefMut, From, Into)]
47pub struct Element(web_sys::Element);
48
49impl Element {
50    pub fn descendants(&self) -> Collection {
51        let mut result = vec![];
52        let mut nodes = vec![self.clone()];
53        while let Some(node) = nodes.pop() {
54            result.push(node.clone());
55            for child in Collection::from(node.0.children()).into_iter().rev() {
56                nodes.push(child);
57            }
58        }
59        result.into()
60    }
61
62    pub fn dyn_ref<T: JsCast>(&self) -> Result<&T, Error> {
63        self.0.dyn_ref::<T>().ok_or(Error::DynRefFailed)
64    }
65}
66
67impl fmt::Display for Element {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        write!(f, "{}", self.local_name())?;
70        let id = self.id();
71        if !id.is_empty() {
72            write!(f, "[id=\"{}\"]", id)?;
73        }
74        Ok(())
75    }
76}
77
78impl fmt::Debug for Element {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        fmt::Display::fmt(self, f)?;
81        write!(f, "(children={}", self.child_element_count())?;
82        let parent = self.parent_node().map(|elem| elem.node_type()).unwrap_or(0);
83        write!(f, ", parent={})", parent)?;
84        Ok(())
85    }
86}
87
88impl<'a> TryInto<&'a web_sys::HtmlElement> for &'a Element {
89    type Error = Error;
90
91    fn try_into(self) -> Result<&'a web_sys::HtmlElement, Self::Error> {
92        self.0.dyn_ref::<HtmlElement>().ok_or(Error::NotHtmlElement)
93    }
94}
95
96impl TryFrom<&Document> for Element {
97    type Error = Error;
98
99    fn try_from(document: &Document) -> Result<Element, Self::Error> {
100        document
101            .0
102            .document_element()
103            .map(Into::into)
104            .ok_or(Error::NoDocumentElement)
105    }
106}
107
108impl TryFrom<Document> for Element {
109    type Error = Error;
110
111    fn try_from(document: Document) -> Result<Element, Self::Error> {
112        Element::try_from(&document)
113    }
114}
115
116impl TryFrom<web_sys::Event> for Element {
117    type Error = Error;
118
119    fn try_from(event: web_sys::Event) -> Result<Element, Self::Error> {
120        if let Some(target) = event.target() {
121            Ok(Element::from(
122                target
123                    .dyn_into::<web_sys::Element>()
124                    .map_err(|_| Error::NoTargetElement)?,
125            ))
126        } else {
127            Err(Error::NoTargetElement)
128        }
129    }
130}
131
132/// HTML `Collection` that can be used as an iterator
133#[derive(AsRef, Clone, Debug, Default, Deref, DerefMut, From, Into)]
134pub struct Collection(pub VecDeque<Element>);
135
136impl Collection {
137    pub fn new() -> Self {
138        Default::default()
139    }
140
141    /// Move all elements of another collection into this collection.
142    pub fn append_collection(&mut self, mut other: Self) {
143        self.0.append(&mut other.0);
144    }
145
146    pub fn descendants(&self) -> Collection {
147        self.0.iter().map(|elem| elem.descendants()).collect()
148    }
149}
150
151impl IntoIterator for Collection {
152    type Item = Element;
153    type IntoIter = std::collections::vec_deque::IntoIter<Self::Item>;
154
155    fn into_iter(self) -> Self::IntoIter {
156        self.0.into_iter()
157    }
158}
159
160impl From<HtmlCollection> for Collection {
161    fn from(collection: HtmlCollection) -> Self {
162        let mut inner = VecDeque::new();
163
164        for i in 0..collection.length() {
165            if let Some(item) = collection.item(i) {
166                inner.push_back(item.into());
167            }
168        }
169
170        Self(inner)
171    }
172}
173
174impl From<NodeList> for Collection {
175    fn from(list: NodeList) -> Self {
176        let mut inner = VecDeque::new();
177
178        for i in 0..list.length() {
179            if let Some(item) = list.item(i) {
180                // Only add `Element` nodes, ignore the others.
181                if let Ok(element) = item.dyn_into::<web_sys::Element>() {
182                    inner.push_back(element.into());
183                }
184            }
185        }
186
187        Self(inner)
188    }
189}
190
191impl From<Element> for Collection {
192    fn from(element: Element) -> Self {
193        Self(vec![element].into())
194    }
195}
196
197impl FromIterator<Collection> for Collection {
198    fn from_iter<I: IntoIterator<Item = Collection>>(iter: I) -> Self {
199        iter.into_iter().map(|coll| coll.0).flatten().collect()
200    }
201}
202
203impl FromIterator<VecDeque<Element>> for Collection {
204    fn from_iter<I: IntoIterator<Item = VecDeque<Element>>>(iter: I) -> Self {
205        iter.into_iter().flatten().collect()
206    }
207}
208
209impl FromIterator<Element> for Collection {
210    fn from_iter<I: IntoIterator<Item = Element>>(iter: I) -> Self {
211        VecDeque::from_iter(iter).into()
212    }
213}
214
215impl From<Vec<Element>> for Collection {
216    fn from(collection: Vec<Element>) -> Self {
217        Self(collection.into())
218    }
219}
220
221impl From<Option<web_sys::Element>> for Collection {
222    fn from(element: Option<web_sys::Element>) -> Self {
223        let inner = match element {
224            Some(element) => vec![element.into()],
225            None => vec![],
226        };
227
228        Self(inner.into())
229    }
230}