duid_core/core/apps/
duid.rs1use std::rc::Rc;
2use std::cell::RefCell;
3use crate::{
4 core::{
5 duid_events::{Dispatch, Cmd},
6 util::{window, request_animation_frame_for_closure},
7 v_node::{ViewBuilder, VirtualNode},
8 apps::UserApp
9 },
10 dom::Dom,
11 effects::Effects
12};
13use wasm_bindgen::{closure::Closure};
14use wasm_bindgen::JsCast;
15use std::collections::HashMap;
16use indextree::Arena;
17
18
19
20pub struct Duid<MDL, MSG>
21where
22 MSG: std::fmt::Debug + Clone + 'static,
23 MDL: Clone + 'static,
24{
25 user_app: Rc<RefCell<UserApp<MDL, MSG>>>,
26 dom: Rc<RefCell<Dom<MSG>>>,
27 effects: Rc<RefCell<Effects>>
28}
29
30
31impl<MDL, MSG> Clone for Duid<MDL, MSG>
32where
33 MSG: std::fmt::Debug + Clone + 'static,
34 MDL: Clone + 'static,
35{
36 fn clone(&self) -> Self {
37 Duid {
38 user_app: Rc::clone(&self.user_app),
39 dom: Rc::clone(&self.dom),
40 effects: Rc::clone(&self.effects),
41 }
42 }
43}
44
45
46impl<MDL, MSG> Duid<MDL, MSG>
47where
48 MSG: std::fmt::Debug + Clone + 'static,
49 MDL: Clone + 'static,
50{
51 pub fn new(
52 mount_node: &str,
53 virtual_dom: UserApp<MDL, MSG>,
54 base_styles: HashMap<String, String>,
55 styles: HashMap<String, String>,
56 replace: bool,
57 use_shadow: bool
58 ) -> Self {
59
60 Duid {
61 user_app: Rc::new(RefCell::new(virtual_dom)),
62 dom: Rc::new(RefCell::new(Dom::new::<Self>(mount_node, replace, use_shadow, base_styles, styles))),
63 effects: Rc::new(RefCell::new(Effects::new()))
64 }
65 }
66
67 pub fn start(
68 mount_node: &str,
69 virtual_dom: UserApp<MDL, MSG>,
70 base_styles: HashMap<String, String>,
71 styles: HashMap<String, String>
72 ) -> Self
73 {
74 console_log::init_with_level(tracing::log::Level::Debug).unwrap();
75 std::panic::set_hook(Box::new(|info| {
76 tracing::error!("{:?}", info);
77 }));
78
79 let program = Self::new(mount_node, virtual_dom, base_styles, styles, true, false);
80 program.mount();
81 program
82 }
83
84 pub fn mount(&self) {
85 let view = self.user_app.borrow().render();
86 let mut arena = Arena::<VirtualNode<MSG>>::new();
87 let root_node_id = ViewBuilder::build(view, &mut arena);
88 self.dom.borrow_mut().mount(self, arena, root_node_id);
89 }
90
91 pub fn render(&self) {
92 let view = self.user_app.borrow().render();
93 let mut arena = Arena::<VirtualNode<MSG>>::new();
94 let root_node_id = ViewBuilder::build(view, &mut arena);
95 self.dom.borrow_mut().render(self, arena, root_node_id);
96 }
97
98 pub fn dispatch_inner(&mut self, msgs: Vec<MSG>) {
99 let mut cmd_msgs: Vec<_> = msgs.iter().map(|msg| self.user_app.borrow_mut().update(msg.to_owned())).collect();
100 let sub_msgs = self.user_app.borrow().subscription();
101 cmd_msgs.push(sub_msgs.into());
102 let cmd_merged = Cmd::merge_all(cmd_msgs);
103
104 if !cmd_merged.messages.is_empty() {
105 self.effects.borrow().effects(self, cmd_merged);
106 }
107 else {
108 self.render();
109 }
110
111 }
112}
113
114
115impl<MDL, MSG> Dispatch<MSG> for Duid<MDL, MSG>
116where
117 MSG: std::fmt::Debug + Clone + 'static,
118 MDL: Clone + 'static,
119{
120 #[cfg(feature = "with-request-animation-frame")]
121 fn dispatch_multiple(&self, msgs: Vec<MSG>) {
122 let mut program_clone = self.clone();
123 let closure_raf: Closure<dyn FnMut() + 'static> =
124 Closure::once(move || {
125 program_clone.dispatch_inner(msgs);
126 });
127 request_animation_frame_for_closure(&closure_raf);
128 closure_raf.forget();
129 }
130
131 #[cfg(not(feature = "with-request-animation-frame"))]
132 fn dispatch_multiple(&self, msgs: Vec<MSG>) {
133 self.dispatch_inner(msgs)
134 }
135
136 fn dispatch(&self, msg: MSG) {
137 self.dispatch_multiple(vec![msg])
138 }
139
140 fn dispatch_with_delay(&self, msg: MSG, timeout: i32) -> Option<i32> {
141 let program_clone = self.clone();
142 let window = window();
143 let closure_delay: Closure<dyn FnMut() + 'static> =
144 Closure::once(move || {
145 program_clone.dispatch(msg);
146 });
147
148 let timeout_id = window
149 .set_timeout_with_callback_and_timeout_and_arguments_0(
150 closure_delay.as_ref().unchecked_ref(),
151 timeout,
152 )
153 .expect("should register the setTimeout call");
154
155 closure_delay.forget();
156 Some(timeout_id)
157 }
158}