@@ -3,6 +3,10 @@ import DOMReconciler from "./DOMReconciler.js";
33import BrokerRegistrar from "../broker/BrokerRegistrar.js" ;
44import State from "../core/State.js" ;
55import { container } from "../core/Container.js" ;
6+ import {
7+ cleanupDisconnectedComponents ,
8+ getOjsChildren ,
9+ } from "../utils/helpers.js" ;
610
711/**
812 * Base Component Class
@@ -33,10 +37,10 @@ export default class Component {
3337 * List of events that the component emits
3438 */
3539 this . EVENTS = {
36- rendered : "rendered" , // component is visible on the dom
37- rerendered : "rerendered" , // component was rerendered
38- mounted : "mounted" , // the component is now registered
39- unmounted : "unmounted" , // removed from the markup engine memory
40+ rendered : "rendered" , // component ui is computed
41+ rerendered : "rerendered" , // component was ui was recomputed.
42+ mounted : "mounted" , // the component is now on the dom
43+ unmounted : "unmounted" , // removed from the repository
4044 } ;
4145
4246 /**
@@ -50,6 +54,11 @@ export default class Component {
5054 */
5155 this . mounted = false ;
5256
57+ /**
58+ * Has the component being unmounted
59+ */
60+ this . unmounted = false ;
61+
5362 /**
5463 * Has the component rendered
5564 */
@@ -60,11 +69,6 @@ export default class Component {
6069 */
6170 this . rerendered = false ;
6271
63- /**
64- * Is the component visible
65- */
66- this . visible = true ;
67-
6872 /**
6973 * The argument Map for rerendering on state changes
7074 */
@@ -85,9 +89,29 @@ export default class Component {
8589
8690 this . name = name ?? this . constructor . name ;
8791
88- this . emitter . once ( this . EVENTS . rendered , ( th ) => ( th . rendered = true ) ) ;
89- this . on ( this . EVENTS . rerendered , ( th ) => ( th . rerendered = true ) ) ;
90- this . on ( this . EVENTS . mounted , ( th ) => ( th . mounted = true ) ) ;
92+ this . emitter . once ( this . EVENTS . rendered , ( componentId ) => {
93+ console . log ( "Component rendered:" , componentId ) ;
94+ let repo = container . resolve ( "repository" ) ;
95+ let component = repo . findComponent ( componentId ) ;
96+ if ( component ) component . rendered = true ;
97+ console . log ( "Component rendered:" , component ) ;
98+ } ) ;
99+
100+ this . on ( this . EVENTS . rerendered , ( componentId ) => {
101+ console . log ( "Component rerendered:" , componentId ) ;
102+ let repo = container . resolve ( "repository" ) ;
103+ let component = repo . findComponent ( componentId ) ;
104+ if ( component ) component . rerendered = true ;
105+ console . log ( "Component rerendered:" , component ) ;
106+ } ) ;
107+
108+ this . on ( this . EVENTS . mounted , ( componentId ) => {
109+ console . log ( "Component mounted:" , componentId ) ;
110+ let repo = container . resolve ( "repository" ) ;
111+ let component = repo . findComponent ( componentId ) ;
112+ if ( component ) component . handleMounted ( ) ;
113+ console . log ( "Component mounted:" , component ) ;
114+ } ) ;
91115
92116 /**
93117 * Compare two Nodes
@@ -193,7 +217,7 @@ export default class Component {
193217 }
194218
195219 this . releaseMemory ( ) ;
196- this . mounted = false ;
220+ this . unmounted = true ;
197221
198222 return true ;
199223 }
@@ -203,8 +227,10 @@ export default class Component {
203227 * @param {string } event
204228 * @param {Array<*> } args
205229 */
206- emit ( event , args = [ ] ) {
207- this . emitter . emit ( event , this , event , ...args ) ;
230+ emit ( event , ...args ) {
231+ args . push ( event ) ;
232+
233+ this . emitter . emit ( event , ...args ) ;
208234 }
209235
210236 /**
@@ -325,7 +351,12 @@ export default class Component {
325351 final . parent = args [ i ] . parent ;
326352 }
327353
328- const keys = [ "resetParent" , "replaceParent" , "firstOfParent" ] ;
354+ const keys = [
355+ "resetParent" ,
356+ "replaceParent" ,
357+ "firstOfParent" ,
358+ "reconcileParent" ,
359+ ] ;
329360
330361 for ( let reserved of keys ) {
331362 if ( args [ i ] [ reserved ] ) {
@@ -360,8 +391,17 @@ export default class Component {
360391 wrap ( ...args ) {
361392 const h = container . resolve ( "h" ) ;
362393 const lastArg = args [ args . length - 1 ] ;
363- let { index, parent, resetParent, states, replaceParent, firstOfParent } =
364- this . getParentAndListen ( args ) ;
394+ let {
395+ index,
396+ parent,
397+ resetParent,
398+ states,
399+ replaceParent,
400+ firstOfParent,
401+ reconcileParent,
402+ } = this . getParentAndListen ( args ) ;
403+
404+ let reconciler = new this . Reconciler ( ) ;
365405
366406 // check if the render was called due to a state change
367407 if ( lastArg && lastArg [ "called-by-state-change" ] ) {
@@ -371,21 +411,15 @@ export default class Component {
371411
372412 let current =
373413 h . dom . querySelectorAll (
374- `ojs-${ this . kebab ( this . name ) } [uid="${ this . id } "][s- ${ stateId } =" ${
375- stateId
376- } "]`
414+ `ojs-${ this . kebab ( this . name ) } [uid="${
415+ this . id
416+ } "][s- ${ stateId } =" ${ stateId } "] `
377417 ) ?? [ ] ;
378418
379- let reconciler = new this . Reconciler ( ) ;
380-
381419 current . forEach ( ( e ) => {
382420 let arg = this . argsMap . get ( Number ( e . getAttribute ( "uid" ) ) ) ;
383421
384- let attr = {
385- componentId : this . id ,
386- event : this . EVENTS . rerendered ,
387- eventParams : [ { componentId : this . id } ] ,
388- } ;
422+ let attr = { } ;
389423
390424 let shouldReconcile = true ;
391425
@@ -405,8 +439,11 @@ export default class Component {
405439 reconciler . reconcile ( markup , e . childNodes [ 0 ] ) ;
406440 }
407441 }
442+
443+ this . emit ( this . EVENTS . rerendered , this . id ) ;
408444 } ) ;
409445
446+ queueMicrotask ( cleanupDisconnectedComponents ) ;
410447 return ;
411448 }
412449
@@ -437,7 +474,15 @@ export default class Component {
437474 class : "__ojs-c-class__" ,
438475 } ;
439476
440- if ( parent ) attr . parent = parent ;
477+ // we render in the parent node
478+ // if we don't need to reconcile the parent
479+ if ( parent ) {
480+ if ( reconcileParent ) {
481+ attr . parent = parent . cloneNode ( ) ;
482+ } else {
483+ attr . parent = parent ;
484+ }
485+ }
441486
442487 states . forEach ( ( id ) => {
443488 attr [ `s-${ id } ` ] = id ;
@@ -451,23 +496,32 @@ export default class Component {
451496 return children . length > 1 ? children : children [ 0 ] ;
452497 }
453498
454- if ( ! this . visible ) attr . style = "display: none;" ;
455-
456499 let cAttributes = { } ;
457500
458501 if ( markup instanceof HTMLElement ) {
459502 cAttributes = JSON . parse ( markup ?. getAttribute ( "c-attr" ) ?? "{}" ) ;
460503 markup . setAttribute ( "c-attr" , "" ) ;
461504 }
462505
463- attr = {
464- ...attr ,
465- componentId : this . id ,
466- event,
467- eventParams : [ { componentId : this . id } ] ,
468- } ;
506+ const rendered = h [ `ojs-${ this . kebab ( this . name ) } ` ] (
507+ attr ,
508+ markup ,
509+ cAttributes
510+ ) ;
511+
512+ if ( reconcileParent && parent ) {
513+ reconciler . reconcile ( rendered . parentElement , parent ) ;
514+ }
469515
470- return h [ `ojs-${ this . kebab ( this . name ) } ` ] ( attr , markup , cAttributes ) ;
516+ this . emit ( this . EVENTS . rendered , this . id ) ;
517+
518+ if ( parent && parent . isConnected ) {
519+ this . emit ( this . EVENTS . mounted , this . id ) ;
520+ }
521+
522+ queueMicrotask ( cleanupDisconnectedComponents ) ;
523+
524+ return rendered ;
471525 }
472526
473527 isHtml ( markup ) {
@@ -524,4 +578,28 @@ export default class Component {
524578 removeListener ( eventName , listener ) {
525579 return this . emitter . removeListener ( eventName , listener ) ;
526580 }
581+
582+ handleMounted ( ) {
583+ if ( this . mounted ) return ;
584+
585+ this . mounted = true ;
586+
587+ // get all components under this component and
588+ // fire their mounted event.
589+
590+ let markups = this . markup ( ) ;
591+
592+ let root = markups [ 0 ] ;
593+
594+ if ( ! root ) return ;
595+
596+ let children = getOjsChildren ( root ) ;
597+
598+ children . forEach ( ( child ) => {
599+ let component = container
600+ . resolve ( "repository" )
601+ . findComponent ( child . getAttribute ( "uid" ) ) ;
602+ if ( component ) component . emit ( this . EVENTS . mounted , component . id ) ;
603+ } ) ;
604+ }
527605}
0 commit comments