@@ -142,6 +142,7 @@ where
142
142
{
143
143
document : web_sys:: Document ,
144
144
mount_point : web_sys:: Element ,
145
+ takeover_mount : bool ,
145
146
pub update : UpdateFn < Ms , Mdl , ElC , GMs > ,
146
147
pub sink : Option < SinkFn < Ms , Mdl , ElC , GMs > > ,
147
148
view : ViewFn < Mdl , ElC > ,
@@ -204,6 +205,7 @@ pub struct AppBuilder<Ms: 'static + Clone, Mdl: 'static, ElC: View<Ms>, GMs> {
204
205
sink : Option < SinkFn < Ms , Mdl , ElC , GMs > > ,
205
206
view : ViewFn < Mdl , ElC > ,
206
207
mount_point : Option < Element > ,
208
+ takeover_mount : bool ,
207
209
routes : Option < RoutesFn < Ms > > ,
208
210
window_events : Option < WindowEvents < Ms , Mdl > > ,
209
211
}
@@ -237,6 +239,18 @@ impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> AppBuilder<Ms, Mdl,
237
239
self
238
240
}
239
241
242
+ /// Allows for the [`App`] to takeover all the children of the mount point. The default
243
+ /// behavior is that the [`App`] ignores the children and leaves them in place. The new
244
+ /// behavior can be useful if SSR is implemented.
245
+ ///
246
+ /// As of right now, nodes found in the root will be destroyed and recreated once. This can
247
+ /// cause duplicated scripts, css, and other tags that should not otherwise be duplicated.
248
+ /// Unrecognized tags are also converted into spans, so take note.
249
+ pub fn takeover_mount ( mut self , should_takeover : bool ) -> Self {
250
+ self . takeover_mount = should_takeover;
251
+ self
252
+ }
253
+
240
254
/// Registers a function which maps URLs to messages.
241
255
pub fn routes ( mut self , routes : RoutesFn < Ms > ) -> Self {
242
256
self . routes = Some ( routes) ;
@@ -273,6 +287,7 @@ impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> AppBuilder<Ms, Mdl,
273
287
self . sink ,
274
288
self . view ,
275
289
self . mount_point . unwrap ( ) ,
290
+ self . takeover_mount ,
276
291
self . routes ,
277
292
self . window_events ,
278
293
) ;
@@ -314,6 +329,7 @@ impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GM
314
329
view,
315
330
sink : None ,
316
331
mount_point : None ,
332
+ takeover_mount : false ,
317
333
routes : None ,
318
334
window_events : None ,
319
335
}
@@ -325,6 +341,7 @@ impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GM
325
341
sink : Option < SinkFn < Ms , Mdl , ElC , GMs > > ,
326
342
view : ViewFn < Mdl , ElC > ,
327
343
mount_point : Element ,
344
+ takeover_mount : bool ,
328
345
routes : Option < RoutesFn < Ms > > ,
329
346
window_events : Option < WindowEvents < Ms , Mdl > > ,
330
347
) -> Self {
@@ -335,6 +352,7 @@ impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GM
335
352
cfg : Rc :: new ( AppCfg {
336
353
document,
337
354
mount_point,
355
+ takeover_mount,
338
356
update,
339
357
sink,
340
358
view,
@@ -368,46 +386,60 @@ impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GM
368
386
}
369
387
370
388
/// Bootstrap the dom with the vdom by taking over all children of the mount point and
371
- /// replacing them with the vdom.
389
+ /// replacing them with the vdom if requested. Will otherwise ignore the original children of
390
+ /// the mount point.
372
391
fn bootstrap_vdom ( & self ) -> El < Ms > {
373
- let mut new = {
374
- // Construct the vdom from the root element. Subsequently strip the workspace so that we
375
- // can recreate it later. There could be missing nodes here.
376
- // TODO: Optimize by utilizing a patching strategy instead of recreating the workspace
392
+ let mut new = El :: empty ( dom_types:: Tag :: Placeholder ) ;
393
+
394
+ // Map the DOM's elements onto the virtual DOM if requested to takeover.
395
+ if self . cfg . takeover_mount {
396
+ // Construct a vdom from the root element. Subsequently strip the workspace so that we
397
+ // can recreate it later - this is a kind of simple way to avoid missing nodes (but
398
+ // not entirely correct).
399
+ // TODO: 1) Optimize by utilizing a patching strategy instead of recreating the workspace
377
400
// TODO: nodes.
401
+ // TODO: 2) Watch out for elements that should not be recreated, such as script nodes,
402
+ // TODO: and other, similar things. For now, leave the warning in the builder's
403
+ // TODO: documentation.
378
404
let mut dom_nodes = websys_bridge:: el_from_ws_element ( & self . cfg . mount_point ) ;
379
405
dom_nodes. strip_ws_nodes ( ) ;
380
406
381
407
// Replace the root dom with a placeholder tag and move the children from the root element
382
408
// to the newly created root. Uses `Placeholder` to mimic update logic.
383
- let mut new = El :: empty ( dom_types:: Tag :: Placeholder ) ;
384
409
new. children = dom_nodes. children ;
385
- new
386
- } ;
410
+ }
387
411
388
412
// Setup listeners
389
413
self . setup_window_listeners ( ) ;
390
414
patch:: setup_input_listeners ( & mut new) ;
391
415
patch:: attach_listeners ( & mut new, & self . mailbox ( ) ) ;
392
416
393
- // Recreate the needed nodes.
394
- // TODO: Refer the TODO at the beginning of the function.
395
- let mut new_node = Node :: Element ( new) ;
396
- websys_bridge:: assign_ws_nodes ( & util:: document ( ) , & mut new_node) ;
397
- let mut new = new_node
398
- . el ( )
399
- . expect ( "`El` placed into `Node::Element` `new_node` is no longer an `El`." ) ;
400
-
401
- // Remove all old elements, and replace them with out newly created elements - we have
402
- // effectively taken over the original DOM and now have free reign over the mount_point.
403
- // Attach all top-level elements to the mount point: This is where our initial render
404
- // occurs.
405
- while let Some ( child) = self . cfg . mount_point . first_child ( ) {
406
- self . cfg
407
- . mount_point
408
- . remove_child ( & child)
409
- . expect ( "No problem removing node from parent." ) ;
410
- }
417
+ // Recreate the needed nodes. Only do this if requested to takeover the mount point.
418
+ let mut new = if self . cfg . takeover_mount {
419
+ // TODO: Refer the TODO at the beginning of the function.
420
+ let mut new_node = Node :: Element ( new) ;
421
+ websys_bridge:: assign_ws_nodes ( & util:: document ( ) , & mut new_node) ;
422
+ let new = new_node
423
+ . el ( )
424
+ . expect ( "`El` placed into `Node::Element` `new_node` is no longer an `El`." ) ;
425
+
426
+ // Remove all old elements. We'll swap them out with the newly created elements later.
427
+ // That maneuver will effectively allow us to remove everything in the mount and thus
428
+ // takeover the mount point.
429
+ while let Some ( child) = self . cfg . mount_point . first_child ( ) {
430
+ self . cfg
431
+ . mount_point
432
+ . remove_child ( & child)
433
+ . expect ( "No problem removing node from parent." ) ;
434
+ }
435
+
436
+ new
437
+ } else {
438
+ new
439
+ } ;
440
+
441
+ // Attach any children that may have been added. This is left outside in case we decide to
442
+ // add any default nodes in the future.
411
443
for child in & mut new. children {
412
444
match child {
413
445
Node :: Element ( child_el) => {
@@ -421,8 +453,10 @@ impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GM
421
453
}
422
454
}
423
455
456
+ // Finally return the bootstrapped version of the virtual DOM.
424
457
new
425
458
}
459
+
426
460
/// App initialization: Collect its fundamental components, setup, and perform
427
461
/// an initial render.
428
462
pub fn run ( self ) -> Self {
0 commit comments