use crate::prelude::*;
use futures_lite::future::race;
use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue;
use web_sys::Document;
use web_sys::Event;
use web_sys::HtmlAnchorElement;
use web_sys::HtmlButtonElement;
use web_sys::HtmlCanvasElement;
use web_sys::HtmlDivElement;
use web_sys::HtmlElement;
use web_sys::HtmlHeadElement;
use web_sys::HtmlInputElement;
use web_sys::HtmlLinkElement;
use web_sys::HtmlParagraphElement;
use web_sys::HtmlScriptElement;
use web_sys::KeyboardEvent;
use web_sys::MouseEvent;
use web_sys::Node;
use web_sys::Window;
fn window() -> Window { web_sys::window().unwrap() }
pub fn document() -> Document { window().document().unwrap() }
pub fn head() -> HtmlHeadElement { document().head().unwrap() }
pub fn body() -> HtmlElement { document().body().unwrap() }
pub fn append_child(node: &Node) { body().append_child(node).unwrap(); }
pub fn clear_body() {
let body_el = body();
while let Some(child) = body_el.first_child() {
body_el.remove_child(&child).unwrap();
}
}
pub fn query_selector<T>(selector: &str) -> Option<T>
where
T: JsCast,
{
document()
.query_selector(selector)
.unwrap()
.map(|el| el.dyn_into::<T>().unwrap())
}
pub fn create_element(local_name: &str) -> HtmlElement {
document()
.create_element(local_name)
.unwrap()
.dyn_into()
.unwrap()
}
pub fn create_anchor() -> HtmlAnchorElement {
document().create_element("a").unwrap().dyn_into().unwrap()
}
pub fn create_canvas() -> HtmlCanvasElement {
document()
.create_element("canvas")
.unwrap()
.dyn_into()
.unwrap()
}
pub fn create_div() -> HtmlDivElement {
document()
.create_element("div")
.unwrap()
.dyn_into()
.unwrap()
}
pub fn create_input() -> HtmlInputElement {
document()
.create_element("input")
.unwrap()
.dyn_into()
.unwrap()
}
pub fn create_button() -> HtmlButtonElement {
document()
.create_element("button")
.unwrap()
.dyn_into()
.unwrap()
}
pub async fn await_interaction() {
let mut on_click = HtmlEventListener::<MouseEvent>::new("mousedown");
let mut on_scroll = HtmlEventListener::<Event>::new("scroll");
let mut on_key = HtmlEventListener::<KeyboardEvent>::new("keydown");
let click = async {
on_click.next().await;
};
let scroll = async {
on_scroll.next().await;
};
let key = async {
on_key.next().await;
};
let _ = race(click, race(scroll, key)).await;
}
pub fn create_paragraph() -> HtmlParagraphElement {
document().create_element("p").unwrap().dyn_into().unwrap()
}
pub fn add_script_src_to_head(src: &str) -> Result<HtmlScriptElement, JsValue> {
let el = document()
.create_element("script")?
.dyn_into::<HtmlScriptElement>()?;
el.set_src(src);
el.set_type("text/javascript");
head().append_child(&el)?;
Ok(el)
}
pub fn add_script_content_to_body(
code: &str,
) -> Result<HtmlScriptElement, JsValue> {
let el = document()
.create_element("script")?
.dyn_into::<HtmlScriptElement>()?;
el.set_type("text/javascript");
el.set_inner_html(code);
body().append_child(&el)?;
Ok(el)
}
pub fn add_style_src_to_head(src: &str) -> Result<HtmlLinkElement, JsValue> {
let el = document()
.create_element("link")?
.dyn_into::<HtmlLinkElement>()?;
el.set_href(src);
el.set_rel("stylesheet");
el.set_type("text/css");
head().append_child(&el)?;
Ok(el)
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use web_sys::HtmlDivElement;
use web_sys::HtmlLinkElement;
use web_sys::HtmlScriptElement;
#[ignore = "requires dom"]
#[test]
fn runs_in_wasm() {
let _ = document_ext::document();
let _ = document_ext::head();
let _ = document_ext::body();
}
#[ignore = "requires dom"]
#[test]
fn creates_and_appends_div() {
document_ext::clear_body();
let div = document_ext::create_div();
div.set_id("greeting");
div.set_inner_html("hello");
document_ext::append_child(&div);
let found = document_ext::query_selector::<HtmlDivElement>("#greeting")
.unwrap();
found.inner_html().xpect_eq("hello");
}
#[ignore = "requires dom"]
#[crate::test]
async fn adds_script_and_style() {
document_ext::clear_body();
let _script =
document_ext::add_script_content_to_body("window.__beet_flag = 1;")
.unwrap();
let _style = document_ext::add_style_src_to_head(
"data:text/css,body{outline:0}",
)
.unwrap();
let script_el =
document_ext::query_selector::<HtmlScriptElement>("body script");
let style_el = document_ext::query_selector::<HtmlLinkElement>(
"head link[rel='stylesheet']",
);
script_el.is_some().xpect_true();
style_el.is_some().xpect_true();
}
}