web_sys_query/query/
mod.rs1mod 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#[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#[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#[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 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 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}