2019-06-20 19:57:47 -04:00
|
|
|
use wasm_bindgen::prelude::*;
|
2019-07-23 00:51:40 -04:00
|
|
|
use wasm_bindgen::{JsCast, intern};
|
|
|
|
use js_sys::Function;
|
2019-07-23 01:25:27 -04:00
|
|
|
use web_sys::{HtmlElement, Element, Node, Window, History, Document, Text, Comment, DomTokenList, CssStyleSheet, CssStyleDeclaration, HtmlStyleElement, CssStyleRule, EventTarget};
|
2019-06-20 19:57:47 -04:00
|
|
|
|
|
|
|
|
|
|
|
#[wasm_bindgen(inline_js = "
|
|
|
|
export function set_property(obj, name, value) { obj[name] = value; }
|
2019-06-21 14:58:39 -04:00
|
|
|
|
|
|
|
export function add_event(elem, name, f) {
|
|
|
|
elem.addEventListener(name, f, {
|
2020-08-27 11:22:14 -04:00
|
|
|
capture: true,
|
2019-06-21 14:58:39 -04:00
|
|
|
once: false,
|
|
|
|
passive: true
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function add_event_once(elem, name, f) {
|
|
|
|
elem.addEventListener(name, f, {
|
2020-08-27 11:22:14 -04:00
|
|
|
capture: true,
|
2019-06-21 14:58:39 -04:00
|
|
|
once: true,
|
|
|
|
passive: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function add_event_preventable(elem, name, f) {
|
|
|
|
elem.addEventListener(name, f, {
|
2020-08-27 11:22:14 -04:00
|
|
|
capture: true,
|
2019-06-21 14:58:39 -04:00
|
|
|
once: false,
|
|
|
|
passive: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function remove_event(elem, name, f) {
|
2020-08-27 11:22:14 -04:00
|
|
|
elem.removeEventListener(name, f, true);
|
2019-06-21 14:58:39 -04:00
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
")]
|
|
|
|
extern "C" {
|
2019-07-23 00:51:40 -04:00
|
|
|
// TODO move this into wasm-bindgen or gloo or something
|
|
|
|
// TODO maybe use Object for obj ?
|
|
|
|
pub(crate) fn set_property(obj: &JsValue, name: &str, value: &JsValue);
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
// TODO replace with gloo-events
|
|
|
|
pub(crate) fn add_event(elem: &EventTarget, name: &str, f: &Function);
|
|
|
|
pub(crate) fn add_event_once(elem: &EventTarget, name: &str, f: &Function);
|
|
|
|
pub(crate) fn add_event_preventable(elem: &EventTarget, name: &str, f: &Function);
|
|
|
|
pub(crate) fn remove_event(elem: &EventTarget, name: &str, f: &Function);
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
thread_local! {
|
|
|
|
static WINDOW: Window = web_sys::window().unwrap_throw();
|
|
|
|
static DOCUMENT: Document = WINDOW.with(|w| w.document().unwrap_throw());
|
|
|
|
static HISTORY: History = WINDOW.with(|w| w.history().unwrap_throw());
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn window_event_target() -> EventTarget {
|
|
|
|
// TODO avoid the clone somehow ?
|
|
|
|
WINDOW.with(|w| w.clone().into())
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn body() -> HtmlElement {
|
|
|
|
DOCUMENT.with(|d| d.body().unwrap_throw())
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn ready_state() -> String {
|
|
|
|
DOCUMENT.with(|d| d.ready_state())
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn current_url() -> String {
|
|
|
|
WINDOW.with(|w| w.location().href().unwrap_throw())
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn go_to_url(url: &str) {
|
|
|
|
HISTORY.with(|h| {
|
|
|
|
h.push_state_with_url(&JsValue::NULL, "", Some(url)).unwrap_throw();
|
|
|
|
});
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn create_stylesheet() -> CssStyleSheet {
|
|
|
|
DOCUMENT.with(|document| {
|
|
|
|
// TODO use createElementNS ?
|
|
|
|
// TODO use dyn_into ?
|
|
|
|
let e: HtmlStyleElement = document.create_element("style").unwrap_throw().unchecked_into();
|
|
|
|
e.set_type("text/css");
|
|
|
|
append_child(&document.head().unwrap_throw(), &e);
|
|
|
|
// TODO use dyn_into ?
|
|
|
|
e.sheet().unwrap_throw().unchecked_into()
|
|
|
|
})
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-08-04 21:39:40 -04:00
|
|
|
pub(crate) fn make_style_rule(sheet: &CssStyleSheet, selector: &str) -> Result<CssStyleRule, JsValue> {
|
2019-07-23 00:51:40 -04:00
|
|
|
let rules = sheet.css_rules().unwrap_throw();
|
|
|
|
let length = rules.length();
|
|
|
|
// TODO don't return u32 ?
|
2019-08-04 21:39:40 -04:00
|
|
|
sheet.insert_rule_with_index(&format!("{}{{}}", selector), length)?;
|
2019-07-23 00:51:40 -04:00
|
|
|
// TODO use dyn_into ?
|
2019-08-04 21:39:40 -04:00
|
|
|
Ok(rules.get(length).unwrap_throw().unchecked_into())
|
2019-07-23 00:51:40 -04:00
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn get_element_by_id(id: &str) -> Element {
|
|
|
|
DOCUMENT.with(|d| d.get_element_by_id(id).unwrap_throw())
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn create_element(name: &str) -> Element {
|
|
|
|
DOCUMENT.with(|d| d.create_element(name).unwrap_throw())
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn create_element_ns(namespace: &str, name: &str) -> Element {
|
|
|
|
DOCUMENT.with(|d| d.create_element_ns(Some(namespace), name).unwrap_throw())
|
|
|
|
}
|
2019-06-20 19:57:47 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn create_text_node(value: &str) -> Text {
|
|
|
|
DOCUMENT.with(|d| d.create_text_node(value))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn set_text(elem: &Text, value: &str) {
|
|
|
|
// http://jsperf.com/textnode-performance
|
|
|
|
elem.set_data(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn create_comment(value: &str) -> Comment {
|
|
|
|
DOCUMENT.with(|d| d.create_comment(value))
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO check that the attribute *actually* was changed
|
|
|
|
pub(crate) fn set_attribute(elem: &Element, key: &str, value: &str) {
|
|
|
|
elem.set_attribute(key, value).unwrap_throw();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn set_attribute_ns(elem: &Element, namespace: &str, key: &str, value: &str) {
|
|
|
|
elem.set_attribute_ns(Some(namespace), key, value).unwrap_throw();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn remove_attribute(elem: &Element, key: &str) {
|
|
|
|
elem.remove_attribute(key).unwrap_throw();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn remove_attribute_ns(elem: &Element, namespace: &str, key: &str) {
|
|
|
|
elem.remove_attribute_ns(Some(namespace), key).unwrap_throw();
|
|
|
|
}
|
|
|
|
|
2019-07-23 01:25:27 -04:00
|
|
|
pub(crate) fn add_class(classes: &DomTokenList, value: &str) {
|
|
|
|
classes.add_1(value).unwrap_throw();
|
2019-07-23 00:51:40 -04:00
|
|
|
}
|
|
|
|
|
2019-07-23 01:25:27 -04:00
|
|
|
pub(crate) fn remove_class(classes: &DomTokenList, value: &str) {
|
|
|
|
classes.remove_1(value).unwrap_throw();
|
2019-07-23 00:51:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_style(style: &CssStyleDeclaration, name: &str) -> String {
|
|
|
|
style.get_property_value(name).unwrap_throw()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn remove_style(style: &CssStyleDeclaration, name: &str) {
|
|
|
|
// TODO don't return String ?
|
|
|
|
style.remove_property(name).unwrap_throw();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn set_style(style: &CssStyleDeclaration, name: &str, value: &str, important: bool) {
|
|
|
|
let priority = if important { intern("important") } else { intern("") };
|
|
|
|
style.set_property_with_priority(name, value, priority).unwrap_throw();
|
|
|
|
}
|
2019-06-21 14:58:39 -04:00
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn insert_child_before(parent: &Node, child: &Node, other: &Node) {
|
|
|
|
// TODO don't return Node ?
|
|
|
|
parent.insert_before(child, Some(other)).unwrap_throw();
|
2019-06-20 19:57:47 -04:00
|
|
|
}
|
|
|
|
|
2019-07-23 00:51:40 -04:00
|
|
|
pub(crate) fn replace_child(parent: &Node, child: &Node, other: &Node) {
|
|
|
|
// TODO don't return Node ?
|
|
|
|
parent.replace_child(child, other).unwrap_throw();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn append_child(parent: &Node, child: &Node) {
|
|
|
|
// TODO don't return Node ?
|
|
|
|
parent.append_child(child).unwrap_throw();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn remove_child(parent: &Node, child: &Node) {
|
|
|
|
// TODO don't return Node ?
|
|
|
|
parent.remove_child(child).unwrap_throw();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn focus(elem: &HtmlElement) {
|
|
|
|
elem.focus().unwrap_throw();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn blur(elem: &HtmlElement) {
|
|
|
|
elem.blur().unwrap_throw();
|
|
|
|
}
|