yew_stdweb/html/component/
scope.rs1use super::{
4 lifecycle::{
5 ComponentLifecycleEvent, ComponentRunnable, ComponentState, CreateEvent, UpdateEvent,
6 },
7 Component,
8};
9use crate::callback::Callback;
10use crate::html::NodeRef;
11use crate::scheduler::{scheduler, Shared};
12use crate::utils::document;
13use crate::virtual_dom::{insert_node, VNode};
14use cfg_if::cfg_if;
15use std::any::{Any, TypeId};
16use std::cell::{Ref, RefCell};
17use std::fmt;
18use std::ops::Deref;
19use std::rc::Rc;
20cfg_if! {
21 if #[cfg(feature = "std_web")] {
22 use stdweb::web::{Element, Node};
23 } else if #[cfg(feature = "web_sys")] {
24 use web_sys::{Element, Node};
25 }
26}
27
28#[derive(Debug, Clone)]
30pub struct AnyScope {
31 pub(crate) type_id: TypeId,
32 pub(crate) parent: Option<Rc<AnyScope>>,
33 pub(crate) state: Rc<dyn Any>,
34}
35
36impl<COMP: Component> From<Scope<COMP>> for AnyScope {
37 fn from(scope: Scope<COMP>) -> Self {
38 AnyScope {
39 type_id: TypeId::of::<COMP>(),
40 parent: scope.parent,
41 state: Rc::new(scope.state),
42 }
43 }
44}
45
46impl AnyScope {
47 pub fn get_parent(&self) -> Option<&AnyScope> {
49 self.parent.as_deref()
50 }
51
52 pub fn get_type_id(&self) -> &TypeId {
54 &self.type_id
55 }
56
57 pub fn downcast<COMP: Component>(self) -> Scope<COMP> {
59 Scope {
60 parent: self.parent,
61 state: self
62 .state
63 .downcast_ref::<Shared<Option<ComponentState<COMP>>>>()
64 .expect("unexpected component type")
65 .clone(),
66 }
67 }
68}
69
70pub(crate) trait Scoped {
71 fn to_any(&self) -> AnyScope;
72 fn root_vnode(&self) -> Option<Ref<'_, VNode>>;
73 fn destroy(&mut self);
74}
75
76impl<COMP: Component> Scoped for Scope<COMP> {
77 fn to_any(&self) -> AnyScope {
78 self.clone().into()
79 }
80
81 fn root_vnode(&self) -> Option<Ref<'_, VNode>> {
82 let state_ref = self.state.borrow();
83
84 state_ref.as_ref()?;
86
87 Some(Ref::map(state_ref, |state_ref| {
88 &state_ref.as_ref().unwrap().root_node
89 }))
90 }
91
92 fn destroy(&mut self) {
94 self.process(ComponentLifecycleEvent::Destroy);
95 }
96}
97
98pub struct Scope<COMP: Component> {
100 parent: Option<Rc<AnyScope>>,
101 state: Shared<Option<ComponentState<COMP>>>,
102}
103
104impl<COMP: Component> fmt::Debug for Scope<COMP> {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 f.write_str("Scope<_>")
107 }
108}
109
110impl<COMP: Component> Clone for Scope<COMP> {
111 fn clone(&self) -> Self {
112 Scope {
113 parent: self.parent.clone(),
114 state: self.state.clone(),
115 }
116 }
117}
118
119impl<COMP: Component> Scope<COMP> {
120 pub fn get_parent(&self) -> Option<&AnyScope> {
122 self.parent.as_deref()
123 }
124
125 pub fn get_component(&self) -> Option<impl Deref<Target = COMP> + '_> {
127 self.state.try_borrow().ok().and_then(|state_ref| {
128 state_ref.as_ref()?;
129 Some(Ref::map(state_ref, |state| {
130 state.as_ref().unwrap().component.as_ref()
131 }))
132 })
133 }
134
135 pub(crate) fn new(parent: Option<AnyScope>) -> Self {
136 let parent = parent.map(Rc::new);
137 let state = Rc::new(RefCell::new(None));
138 Scope { parent, state }
139 }
140
141 pub(crate) fn mount_in_place(
143 self,
144 parent: Element,
145 next_sibling: NodeRef,
146 node_ref: NodeRef,
147 props: COMP::Properties,
148 ) -> Scope<COMP> {
149 let placeholder = {
150 let placeholder: Node = document().create_text_node("").into();
151 insert_node(&placeholder, &parent, next_sibling.get());
152 node_ref.set(Some(placeholder.clone()));
153 VNode::VRef(placeholder)
154 };
155
156 self.schedule(UpdateEvent::First.into());
157 self.process(ComponentLifecycleEvent::Create(CreateEvent {
158 parent,
159 next_sibling,
160 placeholder,
161 node_ref,
162 props,
163 scope: self.clone(),
164 }));
165
166 self
167 }
168
169 pub(crate) fn reuse(&self, props: COMP::Properties, node_ref: NodeRef, next_sibling: NodeRef) {
170 self.process(UpdateEvent::Properties(props, node_ref, next_sibling).into());
171 }
172
173 pub(crate) fn process(&self, event: ComponentLifecycleEvent<COMP>) {
174 let scheduler = scheduler();
175 scheduler.component.push(
176 event.as_runnable_type(),
177 Box::new(ComponentRunnable {
178 state: self.state.clone(),
179 event,
180 }),
181 );
182 scheduler.start();
183 }
184
185 fn schedule(&self, event: ComponentLifecycleEvent<COMP>) {
186 let scheduler = &scheduler().component;
187 scheduler.push(
188 event.as_runnable_type(),
189 Box::new(ComponentRunnable {
190 state: self.state.clone(),
191 event,
192 }),
193 );
194 }
195
196 pub fn send_message<T>(&self, msg: T)
201 where
202 T: Into<COMP::Message>,
203 {
204 self.process(UpdateEvent::Message(msg.into()).into());
205 }
206
207 pub fn send_message_batch(&self, messages: Vec<COMP::Message>) {
216 if messages.is_empty() {
219 return;
220 }
221
222 self.process(UpdateEvent::MessageBatch(messages).into());
223 }
224
225 pub fn callback<F, IN, M>(&self, function: F) -> Callback<IN>
232 where
233 M: Into<COMP::Message>,
234 F: Fn(IN) -> M + 'static,
235 {
236 let scope = self.clone();
237 let closure = move |input| {
238 let output = function(input);
239 scope.send_message(output);
240 };
241 closure.into()
242 }
243
244 pub fn callback_once<F, IN, M>(&self, function: F) -> Callback<IN>
251 where
252 M: Into<COMP::Message>,
253 F: FnOnce(IN) -> M + 'static,
254 {
255 let scope = self.clone();
256 let closure = move |input| {
257 let output = function(input);
258 scope.send_message(output);
259 };
260 Callback::once(closure)
261 }
262
263 pub fn batch_callback<F, IN, OUT>(&self, function: F) -> Callback<IN>
279 where
280 F: Fn(IN) -> OUT + 'static,
281 OUT: SendAsMessage<COMP>,
282 {
283 let scope = self.clone();
284 let closure = move |input| {
285 let messages = function(input);
286 messages.send(&scope);
287 };
288 closure.into()
289 }
290
291 pub fn batch_callback_once<F, IN, OUT>(&self, function: F) -> Callback<IN>
307 where
308 F: FnOnce(IN) -> OUT + 'static,
309 OUT: SendAsMessage<COMP>,
310 {
311 let scope = self.clone();
312 let closure = move |input| {
313 let messages = function(input);
314 messages.send(&scope);
315 };
316 Callback::once(closure)
317 }
318}
319
320pub trait SendAsMessage<COMP: Component> {
323 fn send(self, scope: &Scope<COMP>);
326}
327
328impl<COMP> SendAsMessage<COMP> for Option<COMP::Message>
329where
330 COMP: Component,
331{
332 fn send(self, scope: &Scope<COMP>) {
333 if let Some(msg) = self {
334 scope.send_message(msg);
335 }
336 }
337}
338
339impl<COMP> SendAsMessage<COMP> for Vec<COMP::Message>
340where
341 COMP: Component,
342{
343 fn send(self, scope: &Scope<COMP>) {
344 scope.send_message_batch(self);
345 }
346}