Skip to main content

wasm_dom/
lib.rs

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
91/// `setTimeout(func, delay_ms)` for a one-shot callback.
92pub 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}