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 fn create_element_ns<A: IElement>(name: &str, namespace: &str) -> A
|
|
|
|
where <A as TryFrom<Value>>::Error: std::fmt::Debug {
|
|
|
|
js!( return document.createElementNS(@{namespace}, @{name}); ).try_into().unwrap()
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
// TODO make this more efficient
|
|
|
|
#[inline]
|
|
|
|
pub 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
|
2018-03-01 08:39:58 -05:00
|
|
|
#[inline]
|
|
|
|
pub 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}]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
// TODO make this more efficient
|
2018-03-01 08:39:58 -05:00
|
|
|
#[inline]
|
|
|
|
pub 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}]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
// TODO make this more efficient
|
2018-03-01 08:39:58 -05:00
|
|
|
#[inline]
|
|
|
|
pub 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 fn set_text(element: &TextNode, value: &str) {
|
|
|
|
js! { @(no_return)
|
|
|
|
// http://jsperf.com/textnode-performance
|
|
|
|
@{element}.data = @{value};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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" : ""));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
// TODO this should be in stdweb
|
|
|
|
// TODO handle browser prefixes
|
2018-06-23 13:08:34 -04:00
|
|
|
#[cfg(debug_assertions)]
|
2018-04-25 19:01:52 -04:00
|
|
|
pub fn set_style<A: AsRef<Reference>>(element: &A, name: &str, value: &str, important: bool) {
|
2018-06-26 19:18:05 -04:00
|
|
|
assert!(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-26 19:18:05 -04:00
|
|
|
remove_style(element, name);
|
|
|
|
set_style_raw(element, name, value, important);
|
2018-06-25 21:02:48 -04:00
|
|
|
|
2018-06-26 19:18:05 -04:00
|
|
|
if get_style(element, name) == "" {
|
|
|
|
panic!("style is incorrect:\n name: {}\n value: {}", name, value);
|
2018-06-25 21:02:48 -04:00
|
|
|
}
|
2018-06-23 13:08:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
|
|
#[inline]
|
|
|
|
pub fn set_style<A: AsRef<Reference>>(element: &A, name: &str, value: &str, important: bool) {
|
2018-06-25 21:02:48 -04:00
|
|
|
set_style_raw(element, name, value, important);
|
2018-06-23 13:08:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO this should be in stdweb
|
|
|
|
// TODO handle browser prefixes
|
|
|
|
#[inline]
|
|
|
|
pub fn remove_style<A: AsRef<Reference>>(element: &A, name: &str) {
|
|
|
|
js! { @(no_return)
|
|
|
|
@{element.as_ref()}.style.removeProperty(@{name});
|
2018-04-25 19:01:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 fn set_focused<A: IHtmlElement>(element: &A, focused: bool) {
|
|
|
|
js! { @(no_return)
|
|
|
|
var element = @{element.as_ref()};
|
|
|
|
|
|
|
|
if (@{focused}) {
|
|
|
|
element.focus();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
element.blur();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2018-04-25 19:01:52 -04:00
|
|
|
pub fn add_class<A: IElement>(element: &A, name: &str) {
|
2018-02-25 06:58:20 -05:00
|
|
|
js! { @(no_return)
|
2018-04-25 19:01:52 -04:00
|
|
|
@{element.as_ref()}.classList.add(@{name});
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2018-04-25 19:01:52 -04:00
|
|
|
pub fn remove_class<A: IElement>(element: &A, name: &str) {
|
2018-02-25 06:58:20 -05:00
|
|
|
js! { @(no_return)
|
2018-04-25 19:01:52 -04:00
|
|
|
@{element.as_ref()}.classList.remove(@{name});
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
|
|
|
|
// TODO check that the attribute *actually* was changed
|
2018-02-25 06:58:20 -05:00
|
|
|
#[inline]
|
2018-04-25 19:01:52 -04:00
|
|
|
pub 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]
|
2018-04-25 19:01:52 -04:00
|
|
|
pub 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]
|
2018-04-25 19:01:52 -04:00
|
|
|
pub 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]
|
2018-04-25 19:01:52 -04:00
|
|
|
pub 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]
|
2018-04-25 19:01:52 -04:00
|
|
|
pub 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 fn remove_all_children<A: INode>(element: &A) {
|
|
|
|
js! { @(no_return)
|
|
|
|
@{element.as_ref()}.innerHTML = "";
|
|
|
|
}
|
|
|
|
}
|