1use std::rc::Rc;
2use serde::{self, Serialize, Deserialize, de::DeserializeOwned};
3use wasm_bindgen::JsValue;
4
5
6pub mod event {
11 use super::*;
12
13 pub fn get_oninput_value(event: &JsValue) -> String {
14 let event: web_sys::Event = From::from(event.clone());
15 let target: web_sys::EventTarget = event
16 .target()
17 .expect("target failed");
18 let target: JsValue = From::from(target);
19 let target: web_sys::HtmlInputElement = From::from(target);
20 let value = target.value();
21 value
22 }
23 pub fn prevent_default(event: &JsValue) {
24 let event: web_sys::Event = From::from(event.clone());
25 event.prevent_default();
26 }
27}
28
29pub mod tag {
30 pub fn is_svg(tag: &str) -> bool {
31 match tag.to_lowercase().as_str() {
32 "animate" => true,
33 "animatemotion" => true,
34 "animatetransform" => true,
35 "circle" => true,
36 "clippath" => true,
37 "defs" => true,
38 "desc" => true,
39 "discard" => true,
40 "ellipse" => true,
41 "feblend" => true,
42 "fecolormatrix" => true,
43 "fecomponenttransfer" => true,
44 "fecomposite" => true,
45 "feconvolvematrix" => true,
46 "fediffuselighting" => true,
47 "fedisplacementmap" => true,
48 "fedistantlight" => true,
49 "fedropshadow" => true,
50 "feflood" => true,
51 "fefunca" => true,
52 "fefuncb" => true,
53 "fefuncg" => true,
54 "fefuncr" => true,
55 "fegaussianblur" => true,
56 "feimage" => true,
57 "femerge" => true,
58 "femergenode" => true,
59 "femorphology" => true,
60 "feoffset" => true,
61 "fepointlight" => true,
62 "fespecularlighting" => true,
63 "fespotlight" => true,
64 "fetile" => true,
65 "feturbulence" => true,
66 "filter" => true,
67 "foreignobject" => true,
68 "g" => true,
69 "line" => true,
70 "lineargradient" => true,
71 "marker" => true,
72 "mask" => true,
73 "metadata" => true,
74 "mpath" => true,
75 "path" => true,
76 "pattern" => true,
77 "polygon" => true,
78 "polyline" => true,
79 "radialgradient" => true,
80 "rect" => true,
81 "set" => true,
82 "stop" => true,
83 "svg" => true,
84 "switch" => true,
85 "symbol" => true,
86 "text" => true,
87 "textpath" => true,
88 "title" => true,
89 "tspan" => true,
90 "unknown" => true,
91 "use" => true,
92 "view" => true,
93 _ => false,
94 }
95 }
96}
97
98pub mod core {
99 pub fn get_window() -> web_sys::Window {
100 let window: web_sys::Window = web_sys::window()
101 .expect("window not available");
102 window
103 }
104 pub fn get_document() -> web_sys::Document {
105 let window: web_sys::Window = web_sys::window()
106 .expect("window not available");
107 let document = window
108 .document()
109 .expect("document not available");
110 document
111 }
112 pub fn get_body_as_node() -> web_sys::Node {
113 let window: web_sys::Window = web_sys::window()
114 .expect("window not available");
115 let document = window
116 .document()
117 .expect("document not available");
118 let body: web_sys::Node = std::convert::From::from(
119 document.body().expect("document.body not available")
120 );
121 body
122 }
123 pub fn get_body() -> web_sys::Element {
124 let window: web_sys::Window = web_sys::window()
125 .expect("window not available");
126 let document = window
127 .document()
128 .expect("document not available");
129 let body: web_sys::Element = std::convert::From::from(
130 document.body().expect("document.body not available")
131 );
132 body
133 }
134 pub fn new_element(tag: &str) -> web_sys::Element {
135 let document = get_document();
136 let result = document.create_element(tag)
137 .expect("failed to create element");
138 result
139 }
140 pub fn new_svg_element(tag: &str) -> web_sys::Element {
141 let document = get_document();
142 let result = document.create_element_ns(
143 Some("http://www.w3.org/2000/svg"),
144 tag,
145 )
146 .expect("failed to create element");
147 result
148 }
149 pub fn new_text(value: &str) -> web_sys::Text {
150 let document = get_document();
151 let result = document.create_text_node(value);
152 result
153 }
154}
155
156pub trait Callback {
161 fn as_js_function(&self) -> &js_sys::Function;
162}
163
164
165pub trait DomRef {
170 fn dom_ref(&self) -> &JsValue;
171 fn dom_ref_as_node(&self) -> &web_sys::Node;
172
173 fn add_event_listener(&self, event_name: &str, cb: &Callback) {
174 self.dom_ref_as_node().add_event_listener_with_callback(event_name, cb.as_js_function())
175 .expect("addEventListener failed");
176 }
177 fn remove_event_listener(&self, event_name: &str, cb: &Callback) {
178 self.dom_ref_as_node().remove_event_listener_with_callback(event_name, cb.as_js_function())
179 .expect("removeEventListener failed");
180 }
181 fn append_child(&self, child: &DomRef) {
182 self.dom_ref_as_node()
183 .append_child(&child.dom_ref_as_node())
184 .expect("appendChild failed");
185 }
186 fn remove_child(&self, child: &DomRef) {
187 self.dom_ref_as_node()
188 .remove_child(&child.dom_ref_as_node())
189 .expect("removeChild failed");
190 }
191 fn try_remove_child(&self, child: &DomRef) -> Result<(), JsValue> {
192 match self.dom_ref_as_node().remove_child(&child.dom_ref_as_node()) {
193 Err(x) => Err(x),
194 Ok(_) => Ok(())
195 }
196 }
197 fn replace_child(&self, new_child: &DomRef, old_child: &DomRef) {
198 self.dom_ref_as_node()
199 .replace_child(&new_child.dom_ref_as_node(), &old_child.dom_ref_as_node())
200 .expect("replacedNode failed");
201 }
202}
203
204pub trait DomNode: DomRef {
205 fn dom_ref_as_element(&self) -> &web_sys::Element;
206
207 fn set_attribute(&self, key: &str, value: &str) {
208 self.dom_ref_as_element().set_attribute(key, value)
209 .expect("setAttribute failed");
210 }
211 fn remove_attribute(&self, key: &str) {
212 self.dom_ref_as_element().remove_attribute(key)
213 .expect("removeAttribute failed");
214 }
215}
216
217
218thread_local! {
224 pub static GLOBAL_WINDOW: Window = {
225 let window = Window {
226 instance: core::get_window(),
227 local_storage: Storage::new(),
228 document: Document::new(),
229 location: Location::new(),
230 history: History::new(),
231 };
232 window
233 };
234}
235
236
237pub fn window() -> Window {
238 let win = GLOBAL_WINDOW.with(|win| win.clone());
239 win
240}
241
242
243#[derive(Clone, Debug)]
244pub struct Window {
245 pub instance: web_sys::Window,
246 pub local_storage: Storage,
247 pub document: Document,
248 pub location: Location,
249 pub history: History,
250}
251
252impl Window {
253 pub fn device_pixel_ratio(&self) -> f64 {
254 self.instance.device_pixel_ratio()
255 }
256 pub fn request_animation_frame(&self, cb: &Callback) {
257 self.instance.request_animation_frame(cb.as_js_function());
258 }
259 pub fn set_timeout(&self, cb: &Callback, timeout: i32) {
260 self.instance.set_timeout_with_callback_and_timeout_and_arguments_0(
261 cb.as_js_function(),
262 timeout
263 );
264 }
265}
266
267
268#[derive(Clone, Debug)]
272pub struct Location {
273 pub instance: web_sys::Location
274}
275
276impl Location {
277 pub fn new() -> Self {
278 Location {
279 instance: core::get_window()
280 .location()
281 }
282 }
283 pub fn pathname(&self) -> String {
284 self.instance
285 .pathname()
286 .expect("pathname failed")
287 }
288}
289
290
291
292#[derive(Clone, Debug)]
297pub struct History {
298 pub instance: web_sys::History
299}
300
301impl History {
302 pub fn new() -> Self {
303 History {
304 instance: core::get_window()
305 .history()
306 .expect("window.history getter failed"),
307 }
308 }
309 pub fn push_state(&self, url_path: &str) {
310 self.instance.push_state_with_url(
311 &JsValue::null(),
312 "",
313 Some(url_path)
314 )
315 .expect("pushState failed");
316 }
317}
318
319
320#[derive(Clone, Debug)]
325pub struct Storage {
326 pub instance: web_sys::Storage
327}
328
329impl Storage {
330 pub fn new() -> Self {
331 let instance = core::get_window()
332 .local_storage()
333 .expect("localStorage failed")
334 .expect("localStorage missing");
335 Storage {
336 instance: instance,
337 }
338 }
339 pub fn get<Value>(&self, key: &str) -> Option<Value>
340 where
341 Value: DeserializeOwned
342 {
343 let value = self.instance
344 .get_item(key)
345 .expect("getItem method failed");
346 match value {
347 None => None,
348 Some(value) => match serde_json::from_str(value.clone().as_str()) {
349 Err(msg) => None,
350 Ok(value) => Some(value)
351 }
352 }
353 }
354 pub fn set<Value: Serialize>(&self, key: &str, value: &Value) {
355 match serde_json::to_string(value) {
356 Err(msg) => (),
357 Ok(value) => self.instance
358 .set_item(key, value.as_str())
359 .expect("setItem method failed")
360 }
361 }
362 pub fn remove(&self, key: &str) {
363 self.instance
364 .remove_item(key)
365 .expect("removeItem method failed")
366 }
367}
368
369#[derive(Clone, Debug)]
374pub struct Document {
375 pub body: Body
376}
377
378impl Document {
379 pub fn new() -> Self {
380 Document {
381 body: Body::new()
382 }
383 }
384 pub fn create_element(&self, tag: &str) -> Tag {
385 let element = {
386 if tag::is_svg(tag) {
387 core::new_svg_element(tag)
388 } else {
389 core::new_element(tag)
390 }
391 };
392 let dom_ref: JsValue = From::from(element.clone());
393 Tag {
394 tag: String::from(tag),
395 dom_ref_as_node: From::from(dom_ref.clone()),
396 dom_ref: dom_ref,
397 dom_ref_as_element: element,
398 }
399 }
400 pub fn create_text_node(&self, initial_value: &str) -> Text {
401 let dom_ref_as_text: web_sys::Text = core::new_text(initial_value);
402 let dom_ref: JsValue = From::from(dom_ref_as_text.clone());
403 let dom_ref_as_node: web_sys::Node = From::from(dom_ref.clone());
404 Text {
405 dom_ref_as_text: dom_ref_as_text,
406 dom_ref: dom_ref,
407 dom_ref_as_node: dom_ref_as_node,
408 }
409 }
410}
411
412#[derive(Clone, Debug)]
417pub struct Head {
418
419}
420
421
422
423#[derive(Clone, Debug)]
428pub struct Body {
429 pub i_dom_ref: JsValue,
430 pub i_dom_ref_as_node: web_sys::Node,
431 pub i_dom_ref_as_element: web_sys::Element,
432}
433
434impl Body {
435 pub fn new() -> Self {
436 let i_dom_ref_as_element = core::get_body();
437 let i_dom_ref: JsValue = From::from(i_dom_ref_as_element.clone());
438 let i_dom_ref_as_node: web_sys::Node = From::from(i_dom_ref.clone());
439 Body {i_dom_ref, i_dom_ref_as_element, i_dom_ref_as_node}
440 }
441}
442
443impl DomRef for Body {
444 fn dom_ref_as_node(&self) -> &web_sys::Node {
445 &self.i_dom_ref_as_node
446 }
447 fn dom_ref(&self) -> &JsValue {
448 &self.i_dom_ref
449 }
450}
451
452impl DomNode for Body {
453 fn dom_ref_as_element(&self) -> &web_sys::Element {
454 &self.i_dom_ref_as_element
455 }
456}
457
458
459
460#[derive(Clone, Debug)]
465pub struct Tag {
467 pub tag: String,
468 pub dom_ref: JsValue,
469 pub dom_ref_as_node: web_sys::Node,
470 pub dom_ref_as_element: web_sys::Element,
471}
472
473impl Tag {
474 pub fn new(tag: &str) -> Self {
475 let element = {
476 if tag::is_svg(tag) {
477 core::new_svg_element(tag)
478 } else {
479 core::new_element(tag)
480 }
481 };
482 let dom_ref: JsValue = From::from(element.clone());
483 Tag {
484 tag: String::from(tag),
485 dom_ref_as_node: From::from(dom_ref.clone()),
486 dom_ref: dom_ref,
487 dom_ref_as_element: element,
488 }
489 }
490}
491
492impl DomRef for Tag {
493 fn dom_ref_as_node(&self) -> &web_sys::Node {
494 &self.dom_ref_as_node
495 }
496 fn dom_ref(&self) -> &JsValue {
497 &self.dom_ref
498 }
499}
500
501impl DomNode for Tag {
502 fn dom_ref_as_element(&self) -> &web_sys::Element {
503 &self.dom_ref_as_element
504 }
505}
506
507
508
509#[derive(Clone, Debug)]
514pub struct Text {
515 pub dom_ref: JsValue,
516 pub dom_ref_as_text: web_sys::Text,
517 pub dom_ref_as_node: web_sys::Node,
518}
519
520impl Text {
521 pub fn new(initial_value: &str) -> Self {
522 let dom_ref_as_text: web_sys::Text = core::new_text(initial_value);
523 let dom_ref: JsValue = From::from(dom_ref_as_text.clone());
524 let dom_ref_as_node: web_sys::Node = From::from(dom_ref.clone());
525 Text {
526 dom_ref_as_text: dom_ref_as_text,
527 dom_ref: dom_ref,
528 dom_ref_as_node: dom_ref_as_node,
529 }
530 }
531 pub fn set_text_content(&self, value: &str) {
532 self.dom_ref_as_node.set_text_content(Some(value));
533 }
534}
535
536impl DomRef for Text {
537 fn dom_ref_as_node(&self) -> &web_sys::Node {
538 &self.dom_ref_as_node
539 }
540 fn dom_ref(&self) -> &JsValue {
541 &self.dom_ref
542 }
543}
544