@@ -6,30 +6,29 @@ import { RootLayout, RootLayoutOptions, ShadeCoverOptions, TransitionAnimation }
6
6
import { Animation } from '../../animation' ;
7
7
import { AnimationDefinition } from '../../animation' ;
8
8
import { isNumber } from '../../../utils/types' ;
9
+ import { _findRootLayoutById , _pushIntoRootLayoutStack , _removeFromRootLayoutStack , _geRootLayoutFromStack } from './root-layout-stack' ;
9
10
10
11
@CSSType ( 'RootLayout' )
11
12
export class RootLayoutBase extends GridLayout {
12
- private shadeCover : View ;
13
- private staticChildCount : number ;
14
- private popupViews : { view : View ; options : RootLayoutOptions } [ ] = [ ] ;
13
+ private _shadeCover : View ;
14
+ private _popupViews : { view : View ; options : RootLayoutOptions } [ ] = [ ] ;
15
15
16
- constructor ( ) {
17
- super ( ) ;
18
- global . rootLayout = this ;
16
+ public initNativeView ( ) : void {
17
+ super . initNativeView ( ) ;
18
+
19
+ _pushIntoRootLayoutStack ( this ) ;
19
20
}
20
21
21
- public onLoaded ( ) {
22
- // get actual content count of rootLayout (elements between the <RootLayout> tags in the template).
23
- // All popups will be inserted dynamically at a higher index
24
- this . staticChildCount = this . getChildrenCount ( ) ;
22
+ public disposeNativeView ( ) : void {
23
+ super . disposeNativeView ( ) ;
25
24
26
- super . onLoaded ( ) ;
25
+ _removeFromRootLayoutStack ( this ) ;
27
26
}
28
27
29
28
public _onLivesync ( context ?: ModuleContext ) : boolean {
30
29
let handled = false ;
31
30
32
- if ( this . popupViews . length > 0 ) {
31
+ if ( this . _popupViews . length > 0 ) {
33
32
this . closeAll ( ) ;
34
33
handled = true ;
35
34
}
@@ -55,29 +54,32 @@ export class RootLayoutBase extends GridLayout {
55
54
}
56
55
57
56
if ( this . hasChild ( view ) ) {
58
- return reject ( new Error ( `${ view } has already been added` ) ) ;
57
+ return reject ( new Error ( `View ${ view } has already been added to the root layout ` ) ) ;
59
58
}
60
59
61
60
const toOpen = [ ] ;
62
61
const enterAnimationDefinition = options . animation ? options . animation . enterFrom : null ;
63
62
64
- // keep track of the views locally to be able to use their options later
65
- this . popupViews . push ( { view : view , options : options } ) ;
63
+ // Keep track of the views locally to be able to use their options later
64
+ this . _popupViews . push ( { view : view , options : options } ) ;
65
+
66
+ // Always begin with view invisible when adding dynamically
67
+ view . opacity = 0 ;
68
+ // Add view to view tree before adding shade cover
69
+ // Before being added to view tree, shade cover calculates the index to be inserted based on existing popup views
70
+ this . insertChild ( view , this . getChildrenCount ( ) ) ;
66
71
67
72
if ( options . shadeCover ) {
68
73
// perf optimization note: we only need 1 layer of shade cover
69
74
// we just update properties if needed by additional overlaid views
70
- if ( this . shadeCover ) {
75
+ if ( this . _shadeCover ) {
71
76
// overwrite current shadeCover options if topmost popupview has additional shadeCover configurations
72
- toOpen . push ( this . updateShadeCover ( this . shadeCover , options . shadeCover ) ) ;
77
+ toOpen . push ( this . updateShadeCover ( this . _shadeCover , options . shadeCover ) ) ;
73
78
} else {
74
79
toOpen . push ( this . openShadeCover ( options . shadeCover ) ) ;
75
80
}
76
81
}
77
82
78
- view . opacity = 0 ; // always begin with view invisible when adding dynamically
79
- this . insertChild ( view , this . getChildrenCount ( ) + 1 ) ;
80
-
81
83
toOpen . push (
82
84
new Promise < void > ( ( res , rej ) => {
83
85
setTimeout ( ( ) => {
@@ -125,12 +127,12 @@ export class RootLayoutBase extends GridLayout {
125
127
}
126
128
127
129
if ( ! this . hasChild ( view ) ) {
128
- return reject ( new Error ( `Unable to close popup. ${ view } not found` ) ) ;
130
+ return reject ( new Error ( `Unable to close popup. View ${ view } not found` ) ) ;
129
131
}
130
132
131
133
const toClose = [ ] ;
132
134
const popupIndex = this . getPopupIndex ( view ) ;
133
- const poppedView = this . popupViews [ popupIndex ] ;
135
+ const poppedView = this . _popupViews [ popupIndex ] ;
134
136
const cleanupAndFinish = ( ) => {
135
137
view . notify ( { eventName : 'closed' , object : view } ) ;
136
138
this . removeChild ( view ) ;
@@ -141,7 +143,7 @@ export class RootLayoutBase extends GridLayout {
141
143
142
144
// Remove view from tracked popupviews
143
145
if ( popupIndex > - 1 ) {
144
- this . popupViews . splice ( popupIndex , 1 ) ;
146
+ this . _popupViews . splice ( popupIndex , 1 ) ;
145
147
}
146
148
147
149
toClose . push (
@@ -158,13 +160,13 @@ export class RootLayoutBase extends GridLayout {
158
160
} ) ,
159
161
) ;
160
162
161
- if ( this . shadeCover ) {
163
+ if ( this . _shadeCover ) {
162
164
// Update shade cover with the topmost popupView options (if not specifically told to ignore)
163
- if ( this . popupViews . length ) {
165
+ if ( this . _popupViews . length ) {
164
166
if ( ! poppedView ?. options ?. shadeCover ?. ignoreShadeRestore ) {
165
- const shadeCoverOptions = this . popupViews [ this . popupViews . length - 1 ] . options ?. shadeCover ;
167
+ const shadeCoverOptions = this . _popupViews [ this . _popupViews . length - 1 ] . options ?. shadeCover ;
166
168
if ( shadeCoverOptions ) {
167
- toClose . push ( this . updateShadeCover ( this . shadeCover , shadeCoverOptions ) ) ;
169
+ toClose . push ( this . updateShadeCover ( this . _shadeCover , shadeCoverOptions ) ) ;
168
170
}
169
171
}
170
172
} else {
@@ -186,7 +188,7 @@ export class RootLayoutBase extends GridLayout {
186
188
187
189
closeAll ( ) : Promise < void [ ] > {
188
190
const toClose = [ ] ;
189
- const views = this . popupViews . map ( ( popupView ) => popupView . view ) ;
191
+ const views = this . _popupViews . map ( ( popupView ) => popupView . view ) ;
190
192
191
193
// Close all views at the same time and wait for all of them
192
194
for ( const view of views ) {
@@ -196,12 +198,25 @@ export class RootLayoutBase extends GridLayout {
196
198
}
197
199
198
200
getShadeCover ( ) : View {
199
- return this . shadeCover ;
201
+ return this . _shadeCover ;
200
202
}
201
203
202
204
openShadeCover ( options : ShadeCoverOptions = { } ) : Promise < void > {
203
205
return new Promise ( ( resolve ) => {
204
- if ( this . shadeCover ) {
206
+ const childrenCount = this . getChildrenCount ( ) ;
207
+
208
+ let indexToAdd : number ;
209
+
210
+ if ( this . _popupViews . length ) {
211
+ const { view } = this . _popupViews [ 0 ] ;
212
+ const index = this . getChildIndex ( view ) ;
213
+
214
+ indexToAdd = index > - 1 ? index : childrenCount ;
215
+ } else {
216
+ indexToAdd = childrenCount ;
217
+ }
218
+
219
+ if ( this . _shadeCover ) {
205
220
if ( Trace . isEnabled ( ) ) {
206
221
Trace . write ( `RootLayout shadeCover already open.` , Trace . categories . Layout , Trace . messageType . warn ) ;
207
222
}
@@ -216,25 +231,25 @@ export class RootLayoutBase extends GridLayout {
216
231
} ) ;
217
232
} ) ;
218
233
219
- this . shadeCover = shadeCover ;
220
- // Insert shade cover at index right above the first layout
221
- this . insertChild ( this . shadeCover , this . staticChildCount + 1 ) ;
234
+ this . _shadeCover = shadeCover ;
235
+ // Insert shade cover at index right below the first popup view
236
+ this . insertChild ( this . _shadeCover , indexToAdd ) ;
222
237
}
223
238
} ) ;
224
239
}
225
240
226
241
closeShadeCover ( shadeCoverOptions : ShadeCoverOptions = { } ) : Promise < void > {
227
242
return new Promise ( ( resolve ) => {
228
243
// if shade cover is displayed and the last popup is closed, also close the shade cover
229
- if ( this . shadeCover ) {
230
- return this . _closeShadeCover ( this . shadeCover , shadeCoverOptions ) . then ( ( ) => {
231
- if ( this . shadeCover ) {
232
- this . shadeCover . off ( 'loaded' ) ;
233
- if ( this . shadeCover . parent ) {
234
- this . removeChild ( this . shadeCover ) ;
244
+ if ( this . _shadeCover ) {
245
+ return this . _closeShadeCover ( this . _shadeCover , shadeCoverOptions ) . then ( ( ) => {
246
+ if ( this . _shadeCover ) {
247
+ this . _shadeCover . off ( 'loaded' ) ;
248
+ if ( this . _shadeCover . parent ) {
249
+ this . removeChild ( this . _shadeCover ) ;
235
250
}
236
251
}
237
- this . shadeCover = null ;
252
+ this . _shadeCover = null ;
238
253
// cleanup any platform specific details related to shade cover
239
254
this . _cleanupPlatformShadeCover ( ) ;
240
255
resolve ( ) ;
@@ -245,30 +260,40 @@ export class RootLayoutBase extends GridLayout {
245
260
}
246
261
247
262
topmost ( ) : View {
248
- return this . popupViews . length ? this . popupViews [ this . popupViews . length - 1 ] . view : null ;
263
+ return this . _popupViews . length ? this . _popupViews [ this . _popupViews . length - 1 ] . view : null ;
249
264
}
250
265
251
- // bring any view instance open on the rootlayout to front of all the children visually
266
+ /**
267
+ * This method causes the requested view to overlap its siblings by bring it to front.
268
+ *
269
+ * @param view
270
+ * @param animated
271
+ * @returns
272
+ */
252
273
bringToFront ( view : View , animated : boolean = false ) : Promise < void > {
253
274
return new Promise ( ( resolve , reject ) => {
254
275
if ( ! ( view instanceof View ) ) {
255
276
return reject ( new Error ( `Invalid bringToFront view: ${ view } ` ) ) ;
256
277
}
257
278
258
279
if ( ! this . hasChild ( view ) ) {
259
- return reject ( new Error ( `${ view } not found or already at topmost ` ) ) ;
280
+ return reject ( new Error ( `View ${ view } is not a child of the root layout ` ) ) ;
260
281
}
261
282
262
283
const popupIndex = this . getPopupIndex ( view ) ;
263
- // popupview should be present and not already the topmost view
264
- if ( popupIndex < 0 || popupIndex == this . popupViews . length - 1 ) {
265
- return reject ( new Error ( `${ view } not found or already at topmost` ) ) ;
284
+
285
+ if ( popupIndex < 0 ) {
286
+ return reject ( new Error ( `View ${ view } is not a child of the root layout` ) ) ;
287
+ }
288
+
289
+ if ( popupIndex == this . _popupViews . length - 1 ) {
290
+ return reject ( new Error ( `View ${ view } is already the topmost view in the rootlayout` ) ) ;
266
291
}
267
292
268
293
// keep the popupViews array in sync with the stacking of the views
269
- const currentView = this . popupViews [ popupIndex ] ;
270
- this . popupViews . splice ( popupIndex , 1 ) ;
271
- this . popupViews . push ( currentView ) ;
294
+<
F438
/span> const currentView = this . _popupViews [ popupIndex ] ;
295
+ this . _popupViews . splice ( popupIndex , 1 ) ;
296
+ this . _popupViews . push ( currentView ) ;
272
297
273
298
const exitAnimation = this . getViewExitState ( view ) ;
274
299
if ( animated && exitAnimation ) {
@@ -302,22 +327,22 @@ export class RootLayoutBase extends GridLayout {
302
327
// update shadeCover to reflect topmost's shadeCover options
303
328
const shadeCoverOptions = currentView ?. options ?. shadeCover ;
304
329
if ( shadeCoverOptions ) {
305
- this . updateShadeCover ( this . shadeCover , shadeCoverOptions ) ;
330
+ this . updateShadeCover ( this . _shadeCover , shadeCoverOptions ) ;
306
331
}
307
332
resolve ( ) ;
308
333
} ) ;
309
334
}
310
335
311
336
private getPopupIndex ( view : View ) : number {
312
- return this . popupViews . findIndex ( ( popupView ) => popupView . view === view ) ;
337
+ return this . _popupViews . findIndex ( ( popupView ) => popupView . view === view ) ;
313
338
}
314
339
315
340
private getViewInitialState ( view : View ) : TransitionAnimation {
316
341
const popupIndex = this . getPopupIndex ( view ) ;
317
342
if ( popupIndex === - 1 ) {
318
343
return ;
319
344
}
320
- const initialState = this . popupViews [ popupIndex ] ?. options ?. animation ?. enterFrom ;
345
+ const initialState = this . _popupViews [ popupIndex ] ?. options ?. animation ?. enterFrom ;
321
346
if ( ! initialState ) {
322
347
return ;
323
348
}
@@ -329,7 +354,7 @@ export class RootLayoutBase extends GridLayout {
329
354
if ( popupIndex === - 1 ) {
330
355
return ;
331
356
}
332
- const exitAnimation = this . popupViews [ popupIndex ] ?. options ?. animation ?. exitTo ;
357
+ const exitAnimation = this . _popupViews [ popupIndex ] ?. options ?. animation ?. exitTo ;
333
358
if ( ! exitAnimation ) {
334
359
return ;
335
360
}
@@ -428,7 +453,11 @@ export class RootLayoutBase extends GridLayout {
428
453
}
429
454
430
455
export function getRootLayout ( ) : RootLayout {
431
- return < RootLayout > global . rootLayout ;
456
+ return _geRootLayoutFromStack ( 0 ) ;
457
+ }
458
+
459
+ export function getRootLayoutById ( id : string ) : RootLayout {
460
+ return _findRootLayoutById ( id ) ;
432
461
}
433
462
434
463
export const defaultTransitionAnimation : TransitionAnimation = {
0 commit comments