1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use crate::prelude::*;
pub fn create_element<F, Msg>(
f: F,
tag: &str,
id_name: Option<&str>,
class_names: Vec<&str>,
attrs: Vec<(String, String)>,
events: Vec<(String, Msg)>,
binding: Option<String>,
) -> web_sys::Element
where
F: Fn(Option<Msg>) + Clone + 'static,
Msg: Clone + 'static,
{
use wasm_bindgen::JsCast;
let elem = document().create_element(tag).unwrap();
if let Some(id_name) = id_name {
elem.set_id(id_name);
}
for class_name in class_names {
elem.class_list().add_1(class_name).unwrap();
}
if !attrs.is_empty() {
elem.set_attribute(
"style",
&attrs
.iter()
.map(|(k, v)| format!("{}: {};", k, v))
.collect::<Vec<_>>()
.join(""),
)
.unwrap();
}
let mut events = events
.into_iter()
.map(|(event_name, event)| (event_name, Some(event)))
.collect::<Vec<(_, _)>>();
if let Some(binding) = &binding {
if tag == "input" {
let input: &web_sys::HtmlInputElement = elem.dyn_ref().unwrap();
input.set_value(binding);
events.push(("blur".to_string(), None));
}
}
for (event_name, event) in events {
let mut event_name = event_name;
if event_name == "click" {
event_name = "mousedown".to_string();
}
let f = f.clone();
let closure = Closure::wrap(Box::new(move || {
f(event.clone());
}) as Box<dyn FnMut()>);
elem.add_event_listener_with_callback(&event_name, closure.as_ref().unchecked_ref())
.unwrap();
closure.forget();
}
elem
}
pub fn document() -> web_sys::Document {
web_sys::window()
.expect("no global `window` exists")
.document()
.expect("should have a document on window")
}
#[derive(Clone)]
pub enum HtmlNode {
Text(web_sys::Text),
Element(web_sys::Element),
}
impl HtmlNode {
pub fn into_element(self) -> web_sys::Element {
match self {
HtmlNode::Text(text) => panic!("Expected element, got text: {:?}", text),
HtmlNode::Element(elem) => elem,
}
}
pub fn append_to(self, parent: &web_sys::Element) {
match self {
HtmlNode::Text(text) => parent.append_child(&text).unwrap(),
HtmlNode::Element(elem) => parent.append_child(&elem).unwrap(),
};
}
}