@@ -257,15 +257,20 @@ function InterimElementProvider() {
257
257
* A service used to control inserting and removing an element into the DOM.
258
258
*
259
259
*/
260
- var service , stack = [ ] ;
260
+
261
+ var service ;
262
+
263
+ var showPromises = [ ] ; // Promises for the interim's which are currently opening.
264
+ var hidePromises = [ ] ; // Promises for the interim's which are currently hiding.
265
+ var showingInterims = [ ] ; // Interim elements which are currently showing up.
261
266
262
267
// Publish instance $$interimElement service;
263
268
// ... used as $mdDialog, $mdToast, $mdMenu, and $mdSelect
264
269
265
270
return service = {
266
271
show : show ,
267
- hide : hide ,
268
- cancel : cancel ,
272
+ hide : waitForInterim ( hide ) ,
273
+ cancel : waitForInterim ( cancel ) ,
269
274
destroy : destroy ,
270
275
$injector_ : $injector
271
276
} ;
@@ -286,26 +291,35 @@ function InterimElementProvider() {
286
291
function show ( options ) {
287
292
options = options || { } ;
288
293
var interimElement = new InterimElement ( options || { } ) ;
294
+
289
295
// When an interim element is currently showing, we have to cancel it.
290
296
// Just hiding it, will resolve the InterimElement's promise, the promise should be
291
297
// rejected instead.
292
- var hideExisting = ! options . skipHide && stack . length ? service . cancel ( ) : $q . when ( true ) ;
293
-
294
- // This hide()s only the current interim element before showing the next, new one
295
- // NOTE: this is not reversible (e.g. interim elements are not stackable)
298
+ var hideAction = options . multiple ? $q . resolve ( ) : $q . all ( showPromises ) ;
299
+
300
+ if ( ! options . multiple ) {
301
+ // Wait for all opening interim's to finish their transition.
302
+ hideAction = hideAction . then ( function ( ) {
303
+ // Wait for all closing and showing interim's to be completely closed.
304
+ var promiseArray = hidePromises . concat ( showingInterims . map ( service . cancel ) ) ;
305
+ return $q . all ( promiseArray ) ;
306
+ } ) ;
307
+ }
296
308
297
- hideExisting . finally ( function ( ) {
309
+ var showAction = hideAction . then ( function ( ) {
298
310
299
- stack . push ( interimElement ) ;
300
- interimElement
311
+ return interimElement
301
312
. show ( )
302
- . catch ( function ( reason ) {
303
- //$log.error("InterimElement.show() error: " + reason );
304
- return reason ;
313
+ . catch ( function ( reason ) { return reason ; } )
314
+ . finally ( function ( ) {
315
+ showPromises . splice ( showPromises . indexOf ( showAction ) , 1 ) ;
316
+ showingInterims . push ( interimElement ) ;
305
317
} ) ;
306
318
307
319
} ) ;
308
320
321
+ showPromises . push ( showAction ) ;
322
+
309
323
// Return a promise that will be resolved when the interim
310
324
// element is hidden or cancelled...
311
325
@@ -325,27 +339,30 @@ function InterimElementProvider() {
325
339
*
326
340
*/
327
341
function hide ( reason , options ) {
328
- if ( ! stack . length ) return $q . when ( reason ) ;
329
342
options = options || { } ;
330
343
331
344
if ( options . closeAll ) {
332
- var promise = $q . all ( stack . reverse ( ) . map ( closeElement ) ) ;
333
- stack = [ ] ;
334
- return promise ;
345
+ // We have to make a shallow copy of the array, because otherwise the map will break.
346
+ return $q . all ( showingInterims . slice ( ) . reverse ( ) . map ( closeElement ) ) ;
335
347
} else if ( options . closeTo !== undefined ) {
336
- return $q . all ( stack . splice ( options . closeTo ) . map ( closeElement ) ) ;
337
- } else {
338
- var interim = stack . pop ( ) ;
339
- return closeElement ( interim ) ;
348
+ return $q . all ( showingInterims . slice ( options . closeTo ) . map ( closeElement ) ) ;
340
349
}
341
350
351
+ // Hide the latest showing interim element.
352
+ return closeElement ( showingInterims . pop ( ) ) ;
353
+
342
354
function closeElement ( interim ) {
343
- interim
355
+
356
+ var hideAction = interim
344
357
. remove ( reason , false , options || { } )
345
- . catch ( function ( reason ) {
346
- //$log.error("InterimElement.hide () error: " + reason );
347
- return reason ;
358
+ . catch ( function ( reason ) { return reason ; } )
359
+ . finally ( function ( ) {
360
+ hidePromises . splice ( hidePromises . indexOf ( hideAction ) , 1 ) ;
348
361
} ) ;
362
+
363
+ showingInterims . splice ( showingInterims . indexOf ( interim ) , 1 ) ;
364
+ hidePromises . push ( hideAction ) ;
365
+
349
366
return interim . deferred . promise ;
350
367
}
351
368
}
@@ -363,46 +380,76 @@ function InterimElementProvider() {
363
380
*
364
381
*/
365
382
function cancel ( reason , options ) {
366
- var interim = stack . pop ( ) ;
367
- if ( ! interim ) return $q . when ( reason ) ;
368
-
369
- interim
370
- . remove ( reason , true , options || { } )
371
- . catch ( function ( reason ) {
372
- //$log.error("InterimElement.cancel() error: " + reason );
373
- return reason ;
383
+ var interim = showingInterims . pop ( ) ;
384
+ if ( ! interim ) {
385
+ return $q . when ( reason ) ;
386
+ }
387
+
388
+ var cancelAction = interim
389
+ . remove ( reason , true , options || { } )
390
+ . catch ( function ( reason ) { return reason ; } )
391
+ . finally ( function ( ) {
392
+ hidePromises . splice ( hidePromises . indexOf ( cancelAction ) , 1 ) ;
374
393
} ) ;
375
394
395
+ hidePromises . push ( cancelAction ) ;
396
+
376
397
// Since Angular 1.6.7, promises will be logged to $exceptionHandler when the promise
377
398
// is not handling the rejection. We create a pseudo catch handler, which will prevent the
378
399
// promise from being logged to the $exceptionHandler.
379
400
return interim . deferred . promise . catch ( angular . noop ) ;
380
401
}
381
402
403
+ /**
404
+ * Creates a function to wait for at least one interim element to be available.
405
+ * @param callbackFn Function to be used as callback
406
+ * @returns {Function }
407
+ */
408
+ function waitForInterim ( callbackFn ) {
409
+ return function ( ) {
410
+ var fnArguments = arguments ;
411
+
412
+ if ( ! showingInterims . length ) {
413
+ // When there are still interim's opening, then wait for the first interim element to
414
+ // finish its open animation.
415
+ if ( showPromises . length ) {
416
+ return showPromises [ 0 ] . finally ( function ( ) {
417
+ return callbackFn . apply ( service , fnArguments ) ;
418
+ } ) ;
419
+ }
420
+
421
+ return $q . when ( "No interim elements currently showing up." ) ;
422
+ }
423
+
424
+ return callbackFn . apply ( service , fnArguments ) ;
425
+ } ;
426
+ }
427
+
382
428
/*
383
429
* Special method to quick-remove the interim element without animations
384
430
* Note: interim elements are in "interim containers"
385
431
*/
386
- function destroy ( target ) {
387
- var interim = ! target ? stack . shift ( ) : null ;
388
- var cntr = angular . element ( target ) . length ? angular . element ( target ) [ 0 ] . parentNode : null ;
389
-
390
- if ( cntr ) {
391
- // Try to find the interim element in the stack which corresponds to the supplied DOM element.
392
- var filtered = stack . filter ( function ( entry ) {
393
- var currNode = entry . options . element [ 0 ] ;
394
- return ( currNode === cntr ) ;
395
- } ) ;
432
+ function destroy ( targetEl ) {
433
+ var interim = ! targetEl ? showingInterims . shift ( ) : null ;
396
434
397
- // Note: this function might be called when the element already has been removed, in which
398
- // case we won't find any matches. That's ok.
399
- if ( filtered . length > 0 ) {
400
- interim = filtered [ 0 ] ;
401
- stack . splice ( stack . indexOf ( interim ) , 1 ) ;
402
- }
435
+ var parentEl = angular . element ( targetEl ) . length && angular . element ( targetEl ) [ 0 ] . parentNode ;
436
+
437
+ if ( parentEl ) {
438
+ // Try to find the interim in the stack which corresponds to the supplied DOM element.
439
+ var filtered = showingInterims . filter ( function ( entry ) {
440
+ return entry . options . element [ 0 ] === parentEl ;
441
+ } ) ;
442
+
443
+ // Note: This function might be called when the element already has been removed,
444
+ // in which case we won't find any matches.
445
+ if ( filtered . length ) {
446
+ interim = filtered [ 0 ] ;
447
+ showingInterims . splice ( showingInterims . indexOf ( interim ) , 1 ) ;
448
+ }
403
449
}
404
450
405
- return interim ? interim . remove ( SHOW_CANCELLED , false , { '$destroy' :true } ) : $q . when ( SHOW_CANCELLED ) ;
451
+ return interim ? interim . remove ( SHOW_CANCELLED , false , { '$destroy' : true } ) :
452
+ $q . when ( SHOW_CANCELLED ) ;
406
453
}
407
454
408
455
/*
0 commit comments