livid/
widget.rs

1use crate::document::Document;
2use crate::enums::*;
3use crate::traits::IsElementIterable;
4use std::ops::{Deref, DerefMut};
5use wasm_bindgen::prelude::*;
6use wasm_bindgen::JsCast;
7use wasm_bindgen::UnwrapThrowExt;
8use std::cell::RefCell;
9
10thread_local! {
11    pub(crate) static PARENTS: RefCell<Vec<Widget>> = RefCell::from(vec![crate::widget::Widget::from_elem(Document::get().body().unwrap_throw().into())]);
12}
13
14#[derive(Debug, Clone)]
15/// An Html Element wrapper
16pub struct Widget {
17    elem: web_sys::Element,
18}
19
20impl Widget {
21    /// Create a new Widget
22    pub fn new(typ: WidgetType) -> Self {
23        let doc = Document::get();
24        let elem = doc.create_element(&typ.to_str()).unwrap_throw();
25        PARENTS.with(|p| {
26            if let Some(last) = p.borrow().last() {
27                last.append_child(&elem).unwrap_throw();
28            }
29        });
30        Self { elem }
31    }
32    /// Delete a widget
33    pub fn delete(w: Widget) {
34        w.elem.set_outer_html("");
35        drop(w.elem);
36    }
37    /// Create a new widget from an existing Element
38    pub fn from_elem(elem: web_sys::Element) -> Self {
39        Self { elem }
40    }
41    /// Create a new widget from an existing Element
42    pub fn elem(&self) -> web_sys::Element {
43        self.elem.clone()
44    }
45    /// Create a widget struct from an id
46    pub fn from_id(id: &str) -> Option<Self> {
47        Document::get()
48            .get_element_by_id(id)
49            .map(|elem| Self { elem })
50    }
51    /// Add a callback
52    pub fn add_callback<F: 'static + FnMut(&Self)>(&self, event: Event, mut cb: F) {
53        let e = self.clone();
54        let cb1 = Closure::wrap(Box::new(move || {
55            cb(&e);
56        }) as Box<dyn FnMut()>);
57        self.elem
58            .add_event_listener_with_callback(&event.to_str(), cb1.as_ref().unchecked_ref())
59            .unwrap_throw();
60        cb1.forget();
61    }
62    /// Set a specific style
63    pub fn set_style(&self, style: Style, val: &str) {
64        let style_elem: web_sys::HtmlStyleElement = JsValue::from(self.elem.clone()).into();
65        let css = style_elem.style();
66        css.set_property(style.to_str(), val).unwrap_throw();
67    }
68    /// Get a specific style
69    pub fn style(&self, s: Style) -> String {
70        let style_elem: web_sys::HtmlStyleElement = JsValue::from(self.elem.clone()).into();
71        let css = style_elem.style();
72        css.get_property_value(s.to_str()).unwrap_throw()
73    }
74    /// Append a widget
75    pub fn append(&self, other: &Widget) {
76        self.elem.append_child(&other.elem).unwrap_throw();
77    }
78    /// Remove a widget
79    pub fn remove(&self, other: &Widget) {
80        self.elem.remove_child(&other.elem).unwrap_throw();
81    }
82    pub fn as_elem<T: JsCast>(&self) -> Option<&T> {
83        self.elem.dyn_ref()
84    }
85    pub fn begin(&self) {
86        PARENTS.with(|p| p.borrow_mut().push(self.clone()));
87    }
88    pub fn end(&self) {
89        PARENTS.with(|p| p.borrow_mut().pop());
90    }
91    pub fn clear(&self) {
92        self.set_inner_html("");
93    }
94    pub fn set_align_content(&self, align: AlignContent) {
95        self.set_style(Style::AlignContent, align.to_str());
96    }
97    pub fn set_justify_content(&self, align: AlignContent) {
98        self.set_style(Style::JustifyContent, align.to_str());
99    }
100    pub fn children(&self) -> Vec<Widget> {
101        let mut v: Vec<Widget> = vec![];
102        let c = self.elem.children();
103        for e in c.iter() {
104            v.push(e.to_owned());
105        }
106        v
107    }
108    pub fn parent(&self) -> Option<Widget> {
109        if let Some(elem) = self.parent_element() {
110            Some(Widget::from_elem(elem))
111        } else {
112            None
113        }
114    }
115    pub fn do_callback(&self, event: Event) {
116        let elem: &web_sys::EventTarget = self.dyn_ref().unwrap_throw();
117        elem.dispatch_event(&web_sys::Event::new(&event.to_str()).unwrap_throw())
118            .unwrap_throw();
119    }
120}
121
122impl Deref for Widget {
123    type Target = web_sys::Element;
124
125    fn deref(&self) -> &Self::Target {
126        &self.elem
127    }
128}
129
130impl DerefMut for Widget {
131    fn deref_mut(&mut self) -> &mut Self::Target {
132        &mut self.elem
133    }
134}