use wasm_bindgen::JsCast;
use wasm_bindgen::UnwrapThrowExt;
use super::{spawn_for_each, create_text_node, InputType};
pub trait Attachable {
fn append_to(&self, parent: &web_sys::Node);
fn insert_at(&self, index: usize, parent: &web_sys::Node);
fn replace_at(&self, index: usize, parent: &web_sys::Node);
fn remove_from(&self, parent: &web_sys::Node);
}
pub trait Element: Sized {
fn websys_element(&self) -> &web_sys::Element;
fn websys_node(&self) -> &web_sys::Node;
fn store_future(&mut self);
fn listeners_mut(&mut self) -> &mut Vec<Box<crate::events::Listener>>;
}
impl<T: Element> Attachable for T {
fn append_to(&self, parent: &web_sys::Node) {
parent
.append_child(self.websys_node())
.expect_throw("parent.append_child(self.websys_node())");
}
fn insert_at(&self, index: usize, parent: &web_sys::Node) {
let node_at_index = parent.child_nodes().get(index as u32);
parent
.insert_before(self.websys_node(), node_at_index.as_ref())
.expect_throw("parent.insert_before(self.websys_node(), node_at_index.as_ref())");
}
fn replace_at(&self, index: usize, parent: &web_sys::Node) {
let node_at_index = parent
.child_nodes()
.get(index as u32)
.expect_throw("child_nodes().get");
parent
.replace_child(self.websys_node(), &node_at_index)
.expect_throw("parent.replace_child(self.websys_node(), &node_at_index)");
}
fn remove_from(&self, parent: &web_sys::Node) {
parent
.remove_child(self.websys_node())
.expect_throw("parent.remove_child(self.websys_node())");
}
}
#[cfg(feature = "message-like-elm")]
macro_rules! implement_events {
($($method_name:ident $WebSysEventArgType:ident $EventType:ident,)+) => {
$(
fn $method_name<A, F>(mut self, main: &crate::app::WeakMain<A>, hanlder: F) -> Self
where
A: crate::app::Application,
F: Fn(web_sys::$WebSysEventArgType) -> A::Message + 'static
{
let e = crate::events::$EventType::on(self.websys_node(), main, hanlder);
self.listeners_mut().push(e);
self
}
)+
}
}
#[cfg(not(feature = "message-like-elm"))]
macro_rules! implement_events {
($($method_name:ident $WebSysEventArgType:ident $EventType:ident,)+) => {
$(
fn $method_name<F>(mut self, hanlder: F) -> Self
where
F: Fn(web_sys::$WebSysEventArgType) + 'static
{
let e = crate::events::$EventType::on(self.websys_node(), hanlder);
self.listeners_mut().push(e);
self
}
)+
}
}
pub trait GlobalAttributes: Element {
fn id(self, value: &str) -> Self {
self.websys_element().set_id(value);
self
}
fn focus_signal<S>(self, signal: S) -> Self
where
S: signals::signal::Signal<Item = bool> + 'static,
{
let ws_element: web_sys::HtmlElement = self
.websys_element()
.clone()
.dyn_into()
.expect_throw("self.websys_element().dyn_into()");
spawn_for_each(signal, move |value| {
if value {
if let Err(e) = ws_element.focus() {
log::error!("{:?}", e);
}
}
});
self
}
fn class(self, space_separated_classes: &str) -> Self {
self.websys_element()
.set_attribute("class", space_separated_classes)
.expect_throw(
"self.websys_element().set_attribute(\"class\", space_separated_classes)",
);
self
}
fn class_signal<S>(self, class_name: &str, signal: S) -> Self
where
S: signals::signal::Signal<Item = bool> + 'static,
{
let class_name = class_name.to_string();
let ws_element = self.websys_element().clone();
spawn_for_each(signal, move |value| {
if value {
ws_element
.class_list()
.add_1(&class_name)
.expect_throw("ws_element.class_list().add_1(&class_name)");
} else {
ws_element
.class_list()
.remove_1(&class_name)
.expect_throw("ws_element.class_list().remove_1(&class_name)");
}
});
self
}
implement_events! {
on_blur FocusEvent Blur,
on_focus FocusEvent Focus,
on_click MouseEvent Click,
on_double_click MouseEvent DoubleClick,
on_change Event Change,
on_key_press KeyboardEvent KeyPress,
}
}
pub trait TextContent: Element {
fn text(self, text: &str) -> Self {
let ws_node = self.websys_node();
let text = create_text_node(text);
ws_node
.append_child(&text)
.expect_throw("ws_node.append_child(&text)");
self
}
fn text_signal<S, T>(self, signal: S) -> Self
where
T: ToString + 'static,
S: signals::signal::Signal<Item = T> + 'static,
{
let ws_node = self.websys_node();
let text = create_text_node("");
ws_node
.append_child(&text)
.expect_throw("ws_node.append_child(&text)");
spawn_for_each(signal, move |value| {
text.set_text_content(Some(&value.to_string()));
});
self
}
}
pub trait EmbeddedContent: Element {}
pub trait FlowContent: Element {
fn update_websys_node_signal<S, T, F>(self, signal: S, updater: F) -> Self
where
S: signals::signal::Signal<Item = T> + 'static,
T: Clone + 'static,
F: Fn(T, &web_sys::Element) + 'static,
{
let ws_element = self.websys_element().clone();
spawn_for_each(signal, move |value| {
updater(value, &ws_element);
});
self
}
}
impl<T> TextContent for T where T: FlowContent {}
pub trait FormContent: Element {}
pub trait FormLabelableContent: Element {}
pub trait FormListedContent: Element {}
pub trait FormResettableContent: Element {}
pub trait FormSubmittableContent: Element {}
pub trait HeadingContent: Element {}
pub trait InteractiveContent: Element {}
pub trait MetadataContent: Element {}
pub trait PalpableContent: Element {}
pub trait PhrasingContent: Element {}
pub trait SectioningContent: Element {}
pub trait TransparentContent: Element {}
pub trait TraitA: Element {
fn href(self, value: &str) -> Self {
self.websys_element()
.set_attribute("href", value)
.expect_throw("self.websys_element().set_attribute(\"href\", value)");
self
}
}
pub trait TraitCol: Element {}
pub trait TraitInput: Element {
#[deprecated(since = "0.0.0", note = "Use a label instead of a placeholder")]
fn placeholder(self, text: &str) -> Self {
self.websys_element()
.set_attribute("placeholder", text)
.expect_throw("self.websys_element().set_attribute(\"placeholder\", text)");
self
}
fn autofocus(self) -> Self {
self.websys_element()
.set_attribute("autofocus", "")
.expect_throw("self.websys_element().set_attribute(\"autofocus\", \"\")");
self
}
fn r#type(self, input_type: InputType) -> Self {
self.websys_element()
.set_attribute("type", input_type.as_str())
.expect_throw("self.websys_element().set_attribute(\"type\", input_type.as_str())");
self
}
fn value(self, value: &str) -> Self {
self.websys_element()
.unchecked_ref::<web_sys::HtmlInputElement>()
.set_value(value);
self
}
fn value_signal<S, T>(self, signal: S) -> Self
where
T: Clone + ToString + 'static,
S: signals::signal::Signal<Item = T> + 'static,
{
let ws_input: web_sys::HtmlInputElement = self.websys_element().clone().unchecked_into();
spawn_for_each(signal, move |value| {
ws_input.set_value(&value.to_string());
});
self
}
fn checked(self, value: bool) -> Self {
self.websys_element()
.unchecked_ref::<web_sys::HtmlInputElement>()
.set_checked(value);
self
}
fn checked_signal<S>(self, signal: S) -> Self
where
S: signals::signal::Signal<Item = bool> + 'static,
{
let ws_input: web_sys::HtmlInputElement = self.websys_element().clone().unchecked_into();
spawn_for_each(signal, move |value| {
ws_input.set_checked(value);
});
self
}
}
pub trait TraitLabel: Element {
fn r#for(self, element_id: &str) -> Self {
self.websys_element()
.set_attribute("for", element_id)
.expect_throw("self.websys_element().set_attribute(\"for\", element_id)");
self
}
fn form(self, element_id: &str) -> Self {
self.websys_element()
.set_attribute("form", element_id)
.expect_throw("self.websys_element().set_attribute(\"form\", element_id)");
self
}
}
pub trait TraitLi: Element {}
pub trait TraitFigure: Element {
fn caption_not_implement_yet(self) -> Self {
self
}
}
pub trait TraitOption: Element {}
pub trait TraitTr: Element {}
pub trait TraitTextArea: Element {
fn text(self) -> Self {
self
}
fn text_signal(self) -> Self {
self
}
}
pub trait FlowNonInteractiveContent: Element {}
pub trait PhrasingNonInteractiveContent: Element {}
pub trait Headings: Element {}
pub trait ChildOfA {}
impl<T> ChildOfA for T where T: FlowNonInteractiveContent {}
pub trait ChildOfAudioVideo {}
pub trait ChildOfDataList {}
impl<T> ChildOfDataList for T where T: PhrasingContent {}
pub trait ChildOfDetails {}
impl<T> ChildOfDetails for T where T: FlowContent {}
pub trait ChildOfDl {}
pub trait ChildOfFieldSet {}
impl<T> ChildOfFieldSet for T where T: FlowContent {}
pub trait ChildOfFigure {}
impl<T> ChildOfFigure for T where T: FlowContent {}
pub trait ChildOfPicture {}
pub trait ChildOfRtc {}
impl<T> ChildOfRtc for T where T: PhrasingContent {}
pub trait ChildOfSelect {}
pub trait ChildOfSummary {}
impl<T> ChildOfSummary for T where T: PhrasingContent {}
pub trait ChildOfTable {}
pub trait ChildOfTr {}