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