@@ -257,15 +257,20 @@ function InterimElementProvider() {
257257 * A service used to control inserting and removing an element into the DOM.
258258 *
259259 */
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.
261266
262267 // Publish instance $$interimElement service;
263268 // ... used as $mdDialog, $mdToast, $mdMenu, and $mdSelect
264269
265270 return service = {
266271 show : show ,
267- hide : hide ,
268- cancel : cancel ,
272+ hide : waitForInterim ( hide ) ,
273+ cancel : waitForInterim ( cancel ) ,
269274 destroy : destroy ,
270275 $injector_ : $injector
271276 } ;
@@ -286,26 +291,35 @@ function InterimElementProvider() {
286291 function show ( options ) {
287292 options = options || { } ;
288293 var interimElement = new InterimElement ( options || { } ) ;
294+
289295 // When an interim element is currently showing, we have to cancel it.
290296 // Just hiding it, will resolve the InterimElement's promise, the promise should be
291297 // 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+ }
296308
297- hideExisting . finally ( function ( ) {
309+ var showAction = hideAction . then ( function ( ) {
298310
299- stack . push ( interimElement ) ;
300- interimElement
311+ return interimElement
301312 . 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 ) ;
305317 } ) ;
306318
307319 } ) ;
308320
321+ showPromises . push ( showAction ) ;
322+
309323 // Return a promise that will be resolved when the interim
310324 // element is hidden or cancelled...
311325
@@ -325,27 +339,30 @@ function InterimElementProvider() {
325339 *
326340 */
327341 function hide ( reason , options ) {
328- if ( ! stack . length ) return $q . when ( reason ) ;
329342 options = options || { } ;
330343
331344 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 ) ) ;
335347 } 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 ) ) ;
340349 }
341350
351+ // Hide the latest showing interim element.
352+ return closeElement ( showingInterims . pop ( ) ) ;
353+
342354 function closeElement ( interim ) {
343- interim
355+
356+ var hideAction = interim
344357 . 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 ) ;
348361 } ) ;
362+
363+ showingInterims . splice ( showingInterims . indexOf ( interim ) , 1 ) ;
364+ hidePromises . push ( hideAction ) ;
365+
349366 return interim . deferred . promise ;
350367 }
351368 }
@@ -363,46 +380,76 @@ function InterimElementProvider() {
363380 *
364381 */
365382 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 ) ;
374393 } ) ;
375394
395+ hidePromises . push ( cancelAction ) ;
396+
376397 // Since Angular 1.6.7, promises will be logged to $exceptionHandler when the promise
377398 // is not handling the rejection. We create a pseudo catch handler, which will prevent the
378399 // promise from being logged to the $exceptionHandler.
379400 return interim . deferred . promise . catch ( angular . noop ) ;
380401 }
381402
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+
382428 /*
383429 * Special method to quick-remove the interim element without animations
384430 * Note: interim elements are in "interim containers"
385431 */
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 ;
396434
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+ }
403449 }
404450
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 ) ;
406453 }
407454
408455 /*
0 commit comments