1use std::iter;
2
3pub use js_sys::{self, Reflect};
4use wasm_bindgen::prelude::Closure;
5pub use wasm_bindgen::{self, JsCast, JsValue, UnwrapThrowExt};
6pub use web_sys::{Document, Location, Window};
7use web_sys::{Element, HtmlElement, NodeList};
8
9pub use crate::error::{Error, Result};
10use crate::existing::access::CastToElement;
11
12pub mod animation;
13pub mod correct;
14pub mod error;
15pub mod event;
16pub mod existing;
17
18pub fn window() -> Result<Window> {
19 web_sys::window().ok_or(Error::WindowNotFound)
20}
21
22pub fn document() -> Result<Document> {
23 window()?.document().ok_or(Error::DocumentNotFound)
24}
25
26pub fn document_element() -> Result<Element> {
27 document()?.document_element().ok_or(Error::DocumentElementNotFound)
28}
29
30pub fn body() -> Result<HtmlElement> {
31 document()?.body().ok_or(Error::BodyNotFound)
32}
33
34pub fn location() -> Result<Location> {
35 document()?.location().ok_or(Error::LocationNotFound)
36}
37
38pub fn get_element_by_id<T: JsCast>(id: &str) -> Result<T> {
39 let element = document()?
40 .get_element_by_id(id)
41 .ok_or_else(|| Error::ElementNotFound(id.into()))?;
42 element.dyn_into::<T>().map_err(|_| Error::IsNotAnElement)
43}
44
45pub fn select_element_from(root: &Element, selectors: &str) -> Result<Element> {
46 root.query_selector(selectors)
47 .map_err(|_| Error::InvalidSelectors(selectors.into()))?
48 .ok_or_else(|| Error::ElementNotFound(selectors.into()))
49}
50
51pub fn select_element(selectors: &str) -> Result<Element> {
52 document()?
53 .query_selector(selectors)
54 .map_err(|_| Error::InvalidSelectors(selectors.into()))?
55 .ok_or_else(|| Error::ElementNotFound(selectors.into()))
56}
57
58pub fn select_all_elements_from(root: &Element, selectors: &str) -> Result<impl Iterator<Item = Element>> {
59 root.query_selector_all(selectors)
60 .map(elements)
61 .map_err(|_| Error::InvalidSelectors(selectors.into()))
62}
63
64pub fn select_all_elements(selectors: &str) -> Result<impl Iterator<Item = Element>> {
65 document()?
66 .query_selector_all(selectors)
67 .map(elements)
68 .map_err(|_| Error::InvalidSelectors(selectors.into()))
69}
70
71pub fn select_element_cast<T: JsCast>(selectors: &str) -> Result<T> {
72 select_element(selectors)?
73 .dyn_into::<T>()
74 .map_err(Error::ElementNotCast)
75}
76
77pub fn elements(list: NodeList) -> impl Iterator<Item = Element> {
78 let mut index = 0;
79 iter::from_fn(move || {
80 if index < list.length() {
81 let node = list.get(index);
82 index += 1;
83 Some(node)
84 } else {
85 None
86 }
87 })
88 .filter_map(|node| node.and_then(CastToElement::maybe_into_element))
89}
90
91pub fn set_timeout(func: impl FnOnce() + 'static, delay_ms: i32) -> Result<i32> {
93 let callback = Closure::once_into_js(func).unchecked_into();
94 window()?
95 .set_timeout_with_callback_and_timeout_and_arguments_0(&callback, delay_ms)
96 .map_err(|_| Error::FailedToSetTimeout)
97}