rust-dominator/src/dom_operations.rs

175 lines
4.8 KiB
Rust
Raw Normal View History

2018-02-25 06:58:20 -05:00
use std;
use stdweb::unstable::{TryFrom, TryInto};
2018-03-08 17:07:17 -05:00
use stdweb::{Value, Reference, JsSerialize};
2018-02-25 06:58:20 -05:00
use stdweb::web::{TextNode, INode, IHtmlElement, IElement};
#[inline]
pub(crate) fn create_element_ns<A: IElement>(name: &str, namespace: &str) -> A
2018-02-25 06:58:20 -05:00
where <A as TryFrom<Value>>::Error: std::fmt::Debug {
js!( return document.createElementNS(@{namespace}, @{name}); ).try_into().unwrap()
}
// TODO make this more efficient
#[inline]
pub(crate) fn move_from_to<A: INode>(parent: &A, old_index: u32, new_index: u32) {
js! { @(no_return)
var parent = @{parent.as_ref()};
// TODO verify that it exists ?
var child = parent.childNodes[@{old_index}];
parent.removeChild(child);
parent.insertBefore(child, parent.childNodes[@{new_index}]);
}
}
// TODO make this more efficient
#[inline]
pub(crate) fn insert_at<A: INode, B: INode>(parent: &A, index: u32, child: &B) {
js! { @(no_return)
var parent = @{parent.as_ref()};
parent.insertBefore(@{child.as_ref()}, parent.childNodes[@{index}]);
}
}
// TODO make this more efficient
#[inline]
pub(crate) fn update_at<A: INode, B: INode>(parent: &A, index: u32, child: &B) {
js! { @(no_return)
var parent = @{parent.as_ref()};
parent.replaceChild(@{child.as_ref()}, parent.childNodes[@{index}]);
}
}
// TODO make this more efficient
#[inline]
pub(crate) fn remove_at<A: INode>(parent: &A, index: u32) {
js! { @(no_return)
var parent = @{parent.as_ref()};
parent.removeChild(parent.childNodes[@{index}]);
}
}
2018-02-25 06:58:20 -05:00
// TODO this should be in stdweb
#[inline]
pub(crate) fn set_text(element: &TextNode, value: &str) {
2018-02-25 06:58:20 -05:00
js! { @(no_return)
// http://jsperf.com/textnode-performance
@{element}.data = @{value};
}
}
2018-06-25 21:02:48 -04:00
#[inline]
fn get_style<A: AsRef<Reference>>(element: &A, name: &str) -> String {
js!( return @{element.as_ref()}.style.getPropertyValue(@{name}); ).try_into().unwrap()
}
2018-06-25 21:02:48 -04:00
#[inline]
fn set_style_raw<A: AsRef<Reference>>(element: &A, name: &str, value: &str, important: bool) {
js! { @(no_return)
@{element.as_ref()}.style.setProperty(@{name}, @{value}, (@{important} ? "important" : ""));
}
}
// TODO this should be in stdweb
// TODO maybe use cfg(debug_assertions) ?
pub(crate) fn try_set_style<A: AsRef<Reference>>(element: &A, name: &str, value: &str, important: bool) -> bool {
2018-06-26 19:18:05 -04:00
assert!(value != "");
remove_style(element, name);
set_style_raw(element, name, value, important);
2018-06-25 21:02:48 -04:00
get_style(element, name) != ""
2018-06-23 13:08:34 -04:00
}
// TODO this should be in stdweb
// TODO handle browser prefixes
#[inline]
pub(crate) fn remove_style<A: AsRef<Reference>>(element: &A, name: &str) {
2018-06-23 13:08:34 -04:00
js! { @(no_return)
@{element.as_ref()}.style.removeProperty(@{name});
}
}
2018-02-25 06:58:20 -05:00
// TODO replace with element.focus() and element.blur()
// TODO make element.focus() and element.blur() inline
#[inline]
pub(crate) fn set_focused<A: IHtmlElement>(element: &A, focused: bool) {
2018-02-25 06:58:20 -05:00
js! { @(no_return)
var element = @{element.as_ref()};
if (@{focused}) {
element.focus();
} else {
element.blur();
}
}
}
#[inline]
pub(crate) fn add_class<A: IElement>(element: &A, name: &str) {
2018-02-25 06:58:20 -05:00
js! { @(no_return)
@{element.as_ref()}.classList.add(@{name});
2018-02-25 06:58:20 -05:00
}
}
#[inline]
pub(crate) fn remove_class<A: IElement>(element: &A, name: &str) {
2018-02-25 06:58:20 -05:00
js! { @(no_return)
@{element.as_ref()}.classList.remove(@{name});
2018-02-25 06:58:20 -05:00
}
}
// TODO check that the attribute *actually* was changed
2018-02-25 06:58:20 -05:00
#[inline]
pub(crate) fn set_attribute<A: IElement>(element: &A, name: &str, value: &str) {
2018-02-25 06:58:20 -05:00
js! { @(no_return)
@{element.as_ref()}.setAttribute(@{name}, @{value});
}
}
// TODO check that the attribute *actually* was changed
#[inline]
pub(crate) fn set_attribute_ns<A: IElement>(element: &A, namespace: &str, name: &str, value: &str) {
js! { @(no_return)
@{element.as_ref()}.setAttributeNS(@{namespace}, @{name}, @{value});
2018-02-25 06:58:20 -05:00
}
}
#[inline]
pub(crate) fn remove_attribute_ns<A: IElement>(element: &A, namespace: &str, name: &str) {
2018-02-25 06:58:20 -05:00
js! { @(no_return)
@{element.as_ref()}.removeAttributeNS(@{namespace}, @{name});
}
}
#[inline]
pub(crate) fn remove_attribute<A: IElement>(element: &A, name: &str) {
2018-02-25 06:58:20 -05:00
js! { @(no_return)
@{element.as_ref()}.removeAttribute(@{name});
}
}
// TODO check that the property *actually* was changed ?
2018-03-08 17:07:17 -05:00
// TODO better type checks ?
2018-02-25 06:58:20 -05:00
#[inline]
pub(crate) fn set_property<A: AsRef<Reference>, B: JsSerialize>(obj: &A, name: &str, value: B) {
2018-03-08 17:07:17 -05:00
js! { @(no_return)
@{obj.as_ref()}[@{name}] = @{value};
}
2018-02-25 06:58:20 -05:00
}
// TODO make this work on Nodes, not just Elements
// TODO is this the most efficient way to remove all children ?
#[inline]
pub(crate) fn remove_all_children<A: INode>(element: &A) {
2018-02-25 06:58:20 -05:00
js! { @(no_return)
@{element.as_ref()}.innerHTML = "";
}
}