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