22 * @coreapi  
33 * @module  view 
44 */  /** for typedoc */ 
5- import  { equals ,  applyPairs ,  removeFrom ,  TypedMap }  from  "../common/common" ; 
6- import  { curry ,  prop }  from  "../common/hof" ; 
7- import  { isString ,  isArray }  from  "../common/predicates" ; 
8- import  { trace }  from  "../common/trace" ; 
9- import  { PathNode }  from  "../path/pathNode" ; 
10- 
11- import  { ActiveUIView ,  ViewContext ,  ViewConfig }  from  "./interface" ; 
12- import  { _ViewDeclaration }  from  "../state/interface" ; 
5+ import  {  equals ,  applyPairs ,  removeFrom ,  TypedMap ,  inArray  }  from  "../common/common" ; 
6+ import  {  curry ,  prop  }  from  "../common/hof" ; 
7+ import  {  isString ,  isArray  }  from  "../common/predicates" ; 
8+ import  {  trace  }  from  "../common/trace" ; 
9+ import  {  PathNode  }  from  "../path/pathNode" ; 
10+ import  {  ActiveUIView ,  ViewContext ,  ViewConfig  }  from  "./interface" ; 
11+ import  {  _ViewDeclaration  }  from  "../state/interface" ; 
1312
1413export  type  ViewConfigFactory  =  ( path : PathNode [ ] ,  decl : _ViewDeclaration )  =>  ViewConfig | ViewConfig [ ] ; 
1514
@@ -18,6 +17,17 @@ export interface ViewServicePluginAPI {
1817  _viewConfigFactory ( viewType : string ,  factory : ViewConfigFactory ) ; 
1918  _registeredUIViews ( ) : ActiveUIView [ ] ; 
2019  _activeViewConfigs ( ) : ViewConfig [ ] ; 
20+   _onSync ( listener : ViewSyncListener ) : Function ; 
21+ } 
22+ 
23+ // A uiView and its matching viewConfig 
24+ export  interface  ViewTuple  { 
25+   uiView : ActiveUIView ; 
26+   viewConfig : ViewConfig ; 
27+ } 
28+ 
29+ export  interface  ViewSyncListener  { 
30+   ( viewTuples : ViewTuple [ ] ) : void ; 
2131} 
2232
2333/** 
@@ -41,6 +51,7 @@ export class ViewService {
4151  private  _viewConfigs : ViewConfig [ ]  =  [ ] ; 
4252  private  _rootContext : ViewContext ; 
4353  private  _viewConfigFactories : {  [ key : string ] : ViewConfigFactory  }  =  { } ; 
54+   private  _listeners : ViewSyncListener [ ]  =  [ ] ; 
4455
4556  constructor ( )  {  } 
4657
@@ -49,6 +60,10 @@ export class ViewService {
4960    _viewConfigFactory : this . _viewConfigFactory . bind ( this ) , 
5061    _registeredUIViews : ( )  =>  this . _uiViews , 
5162    _activeViewConfigs : ( )  =>  this . _viewConfigs , 
63+     _onSync : ( listener : ViewSyncListener )  =>  { 
64+       this . _listeners . push ( listener ) ; 
65+       return  ( )  =>  removeFrom ( this . _listeners ,  listener ) ; 
66+     } , 
5267  } ; 
5368
5469  private  _rootViewContext ( context ?: ViewContext ) : ViewContext  { 
@@ -65,7 +80,7 @@ export class ViewService {
6580    let  cfgs  =  cfgFactory ( path ,  decl ) ; 
6681    return  isArray ( cfgs )  ? cfgs  : [ cfgs ] ; 
6782  } 
68-    
83+ 
6984  /** 
7085   * Deactivates a ViewConfig. 
7186   * 
@@ -186,30 +201,37 @@ export class ViewService {
186201    // Given a depth function, returns a compare function which can return either ascending or descending order 
187202    const  depthCompare  =  curry ( ( depthFn ,  posNeg ,  left ,  right )  =>  posNeg  *  ( depthFn ( left )  -  depthFn ( right ) ) ) ; 
188203
189-     const  matchingConfigPair  =  ( uiView : ActiveUIView )  =>  { 
204+     const  matchingConfigPair  =  ( uiView : ActiveUIView ) :  ViewTuple  =>  { 
190205      let  matchingConfigs  =  this . _viewConfigs . filter ( ViewService . matches ( uiViewsByFqn ,  uiView ) ) ; 
191206      if  ( matchingConfigs . length  >  1 )  { 
192207        // This is OK.  Child states can target a ui-view that the parent state also targets (the child wins) 
193208        // Sort by depth and return the match from the deepest child 
194209        // console.log(`Multiple matching view configs for ${uiView.fqn}`, matchingConfigs); 
195210        matchingConfigs . sort ( depthCompare ( viewConfigDepth ,  - 1 ) ) ;  // descending 
196211      } 
197-       return  [ uiView ,  matchingConfigs [ 0 ] ] ; 
212+       return  {   uiView,  viewConfig :  matchingConfigs [ 0 ]   } ; 
198213    } ; 
199214
200-     const  configureUIView  =  ( [ uiView ,   viewConfig ] )  =>  { 
215+     const  configureUIView  =  ( tuple :  ViewTuple )  =>  { 
201216      // If a parent ui-view is reconfigured, it could destroy child ui-views. 
202217      // Before configuring a child ui-view, make sure it's still in the active uiViews array. 
203-       if  ( this . _uiViews . indexOf ( uiView )  !==  - 1 ) 
204-         uiView . configUpdated ( viewConfig ) ; 
218+       if  ( this . _uiViews . indexOf ( tuple . uiView )  !==  - 1 ) 
219+         tuple . uiView . configUpdated ( tuple . viewConfig ) ; 
205220    } ; 
206221
207222    // Sort views by FQN and state depth. Process uiviews nearest the root first. 
208-     const  pairs  =  this . _uiViews . sort ( depthCompare ( uiViewDepth ,  1 ) ) . map ( matchingConfigPair ) ; 
223+     const  uiViewTuples  =  this . _uiViews . sort ( depthCompare ( uiViewDepth ,  1 ) ) . map ( matchingConfigPair ) ; 
224+     const  matchedViewConfigs  =  uiViewTuples . map ( tuple  =>  tuple . viewConfig ) ; 
225+     const  unmatchedConfigTuples  =  this . _viewConfigs 
226+       . filter ( config  =>  inArray ( matchedViewConfigs ,  config ) ) 
227+       . map ( viewConfig  =>  ( {  uiView : undefined ,  viewConfig } ) ) ; 
209228
210-     trace . traceViewSync ( pairs ) ; 
229+     const   allTuples :  ViewTuple [ ]   =   uiViewTuples . concat ( unmatchedConfigTuples ) ; 
211230
212-     pairs . forEach ( configureUIView ) ; 
231+     uiViewTuples . forEach ( configureUIView ) ; 
232+ 
233+     this . _listeners . forEach ( cb  =>  cb ( allTuples ) ) ; 
234+     trace . traceViewSync ( allTuples ) ; 
213235  } ; 
214236
215237  /** 
@@ -310,4 +332,4 @@ export class ViewService {
310332
311333    return  { uiViewName,  uiViewContextAnchor} ; 
312334  } 
313- } 
335+ } 
0 commit comments