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)]
15pub struct Widget {
17 elem: web_sys::Element,
18}
19
20impl Widget {
21 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 pub fn delete(w: Widget) {
34 w.elem.set_outer_html("");
35 drop(w.elem);
36 }
37 pub fn from_elem(elem: web_sys::Element) -> Self {
39 Self { elem }
40 }
41 pub fn elem(&self) -> web_sys::Element {
43 self.elem.clone()
44 }
45 pub fn from_id(id: &str) -> Option<Self> {
47 Document::get()
48 .get_element_by_id(id)
49 .map(|elem| Self { elem })
50 }
51 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 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 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 pub fn append(&self, other: &Widget) {
76 self.elem.append_child(&other.elem).unwrap_throw();
77 }
78 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}