@@ -365,49 +365,73 @@ impl<Ms, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GMs> {
365
365
}
366
366
}
367
367
368
- /// App initialization: Collect its fundamental components, setup, and perform
369
- /// an initial render.
370
- pub fn run ( self ) -> Self {
371
- self . process_cmd_and_msg_queue (
372
- self . cfg
373
- . initial_orders
374
- . replace ( None )
375
- . expect ( "initial_orders should be set in AppBuilder::finish" )
376
- . effects ,
377
- ) ;
378
- // Our initial render. Can't initialize in new due to mailbox() requiring self.
379
- // "new" name is for consistency with `update` function.
380
- // this section parent is a placeholder, so we can iterate over children
381
- // in a way consistent with patching code.
382
- let mut new = El :: empty ( dom_types:: Tag :: Section ) ;
383
- new. children = ( self . cfg . view ) ( self . data . model . borrow ( ) . as_ref ( ) . unwrap ( ) ) . els ( ) ;
368
+ /// Bootstrap the dom with the vdom by taking over all children of the mount point and
369
+ /// replacing them with the vdom.
370
+ 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
375
+ // TODO: nodes.
376
+ let mut dom_nodes = websys_bridge:: el_from_ws_element ( & self . cfg . mount_point ) ;
377
+ dom_nodes. strip_ws_nodes ( ) ;
378
+
379
+ // Replace the root dom with a placeholder tag and move the children from the root element
380
+ // to the newly created root. Uses `Placeholder` to mimic update logic.
381
+ let mut new = El :: empty ( dom_types:: Tag :: Placeholder ) ;
382
+ new. children = dom_nodes. children ;
383
+ new
384
+ } ;
384
385
386
+ // Setup listeners
385
387
self . setup_window_listeners ( ) ;
386
388
patch:: setup_input_listeners ( & mut new) ;
387
389
patch:: attach_listeners ( & mut new, & self . mailbox ( ) ) ;
388
390
391
+ // Recreate the needed nodes.
392
+ // TODO: Refer the TODO at the beginning of the function.
389
393
let mut new_node = Node :: Element ( new) ;
390
-
391
394
websys_bridge:: assign_ws_nodes ( & util:: document ( ) , & mut new_node) ;
392
-
393
- if let Node :: Element ( mut new) = new_node {
394
- // Attach all top-level elements to the mount point: This is where our initial render occurs.
395
- for child in & mut new. children {
396
- match child {
397
- Node :: Element ( child_el) => {
398
- websys_bridge:: attach_el_and_children ( child_el, & self . cfg . mount_point ) ;
399
- patch:: attach_listeners ( child_el, & self . mailbox ( ) ) ;
400
- }
401
- Node :: Text ( top_child_text) => {
402
- websys_bridge:: attach_text_node ( top_child_text, & self . cfg . mount_point ) ;
403
- }
404
- Node :: Empty => ( ) ,
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
+ }
409
+ for child in & mut new. children {
410
+ match child {
411
+ Node :: Element ( child_el) => {
412
+ websys_bridge:: attach_el_and_children ( child_el, & self . cfg . mount_point ) ;
413
+ patch:: attach_listeners ( child_el, & self . mailbox ( ) ) ;
405
414
}
415
+ Node :: Text ( top_child_text) => {
416
+ websys_bridge:: attach_text_node ( top_child_text, & self . cfg . mount_point ) ;
417
+ }
418
+ Node :: Empty => ( ) ,
406
419
}
407
- self . data . main_el_vdom . replace ( Some ( new) ) ;
408
420
}
409
421
410
- // Update the state on page load, based
422
+ new
423
+ }
424
+ /// App initialization: Collect its fundamental components, setup, and perform
425
+ /// an initial render.
426
+ pub fn run ( self ) -> Self {
427
+ // Our initial render. Can't initialize in new due to mailbox() requiring self.
428
+ // "new" name is for consistency with `update` function.
429
+
430
+ // Bootstrap the vdom with the dom's state. No need to do a full render, sinc executing
431
+ // initial_orders should do this.
432
+ self . data . main_el_vdom . replace ( Some ( self . bootstrap_vdom ( ) ) ) ;
433
+
434
+ // Setup routes handling. Update the state on page load, based
411
435
// on the starting URL. Must be set up on the server as well.
412
436
if let Some ( routes) = * self . data . routes . borrow ( ) {
413
437
routing:: setup_popstate_listener (
@@ -419,6 +443,19 @@ impl<Ms, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GMs> {
419
443
) ;
420
444
routing:: setup_link_listener ( enclose ! ( ( self => s) move |msg| s. update( msg) ) , routes) ;
421
445
}
446
+
447
+ // Since everything's been set up, run the initial update. This will trigger the initial
448
+ // render as per normal for seed behavior. -- Executed here to ensure that all state has
449
+ // been initialized with a bootstrap version. The bootstrap will be replaced after first
450
+ // render.
451
+ self . process_cmd_and_msg_queue (
452
+ self . cfg
453
+ . initial_orders
454
+ . replace ( None )
455
+ . expect ( "initial_orders should be set in AppBuilder::finish" )
456
+ . effects ,
457
+ ) ;
458
+
422
459
self
423
460
}
424
461
0 commit comments