2
2
* @coreapi
3
3
* @module view
4
4
*/ /** 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" ;
13
12
14
13
export type ViewConfigFactory = ( path : PathNode [ ] , decl : _ViewDeclaration ) => ViewConfig | ViewConfig [ ] ;
15
14
@@ -18,6 +17,17 @@ export interface ViewServicePluginAPI {
18
17
_viewConfigFactory ( viewType : string , factory : ViewConfigFactory ) ;
19
18
_registeredUIViews ( ) : ActiveUIView [ ] ;
20
19
_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 ;
21
31
}
22
32
23
33
/**
@@ -41,6 +51,7 @@ export class ViewService {
41
51
private _viewConfigs : ViewConfig [ ] = [ ] ;
42
52
private _rootContext : ViewContext ;
43
53
private _viewConfigFactories : { [ key : string ] : ViewConfigFactory } = { } ;
54
+ private _listeners : ViewSyncListener [ ] = [ ] ;
44
55
45
56
constructor ( ) { }
46
57
@@ -49,6 +60,10 @@ export class ViewService {
49
60
_viewConfigFactory : this . _viewConfigFactory . bind ( this ) ,
50
61
_registeredUIViews : ( ) => this . _uiViews ,
51
62
_activeViewConfigs : ( ) => this . _viewConfigs ,
63
+ _onSync : ( listener : ViewSyncListener ) => {
64
+ this . _listeners . push ( listener ) ;
65
+ return ( ) => removeFrom ( this . _listeners , listener ) ;
66
+ } ,
52
67
} ;
53
68
54
69
private _rootViewContext ( context ?: ViewContext ) : ViewContext {
@@ -65,7 +80,7 @@ export class ViewService {
65
80
let cfgs = cfgFactory ( path , decl ) ;
66
81
return isArray ( cfgs ) ? cfgs : [ cfgs ] ;
67
82
}
68
-
83
+
69
84
/**
70
85
* Deactivates a ViewConfig.
71
86
*
@@ -186,30 +201,37 @@ export class ViewService {
186
201
// Given a depth function, returns a compare function which can return either ascending or descending order
187
202
const depthCompare = curry ( ( depthFn , posNeg , left , right ) => posNeg * ( depthFn ( left ) - depthFn ( right ) ) ) ;
188
203
189
- const matchingConfigPair = ( uiView : ActiveUIView ) => {
204
+ const matchingConfigPair = ( uiView : ActiveUIView ) : ViewTuple => {
190
205
let matchingConfigs = this . _viewConfigs . filter ( ViewService . matches ( uiViewsByFqn , uiView ) ) ;
191
206
if ( matchingConfigs . length > 1 ) {
192
207
// This is OK. Child states can target a ui-view that the parent state also targets (the child wins)
193
208
// Sort by depth and return the match from the deepest child
194
209
// console.log(`Multiple matching view configs for ${uiView.fqn}`, matchingConfigs);
195
210
matchingConfigs . sort ( depthCompare ( viewConfigDepth , - 1 ) ) ; // descending
196
211
}
197
- return [ uiView , matchingConfigs [ 0 ] ] ;
212
+ return { uiView, viewConfig : matchingConfigs [ 0 ] } ;
198
213
} ;
199
214
200
- const configureUIView = ( [ uiView , viewConfig ] ) => {
215
+ const configureUIView = ( tuple : ViewTuple ) => {
201
216
// If a parent ui-view is reconfigured, it could destroy child ui-views.
202
217
// 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 ) ;
205
220
} ;
206
221
207
222
// 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 } ) ) ;
209
228
210
- trace . traceViewSync ( pairs ) ;
229
+ const allTuples : ViewTuple [ ] = uiViewTuples . concat ( unmatchedConfigTuples ) ;
211
230
212
- pairs . forEach ( configureUIView ) ;
231
+ uiViewTuples . forEach ( configureUIView ) ;
232
+
233
+ this . _listeners . forEach ( cb => cb ( allTuples ) ) ;
234
+ trace . traceViewSync ( allTuples ) ;
213
235
} ;
214
236
215
237
/**
@@ -310,4 +332,4 @@ export class ViewService {
310
332
311
333
return { uiViewName, uiViewContextAnchor} ;
312
334
}
313
- }
335
+ }
0 commit comments