function InterimElementFactory($document, $q, $rootScope, $timeout, $rootElement, $animate,
                                 $mdUtil, $mdCompiler, $mdTheming, $injector, $exceptionHandler) {
    return function createInterimElementService() {
      var SHOW_CANCELLED = false;

      /*
       * @ngdoc service
       * @name $$interimElement.$service
       *
       * @description
       * A service used to control inserting and removing an element into the DOM.
       *
       */

      var service;

      var showPromises = []; // Promises for the interim's which are currently opening.
      var hidePromises = []; // Promises for the interim's which are currently hiding.
      var showingInterims = []; // Interim elements which are currently showing up.

      // Publish instance $$interimElement service;
      // ... used as $mdDialog, $mdToast, $mdMenu, and $mdSelect

      return service = {
        show: show,
        hide: waitForInterim(hide),
        cancel: waitForInterim(cancel),
        destroy : destroy,
        $injector_: $injector
      };

      /*
       * @ngdoc method
       * @name $$interimElement.$service#show
       * @kind function
       *
       * @description
       * Adds the `$interimElement` to the DOM and returns a special promise that will be resolved or rejected
       * with hide or cancel, respectively. To external cancel/hide, developers should use the
       *
       * @param {*} options is hashMap of settings
       * @returns a Promise
       *
       */
      function show(options) {
        options = options || {};
        var interimElement = new InterimElement(options || {});

        // When an interim element is currently showing, we have to cancel it.
        // Just hiding it, will resolve the InterimElement's promise, the promise should be
        // rejected instead.
        var hideAction = options.multiple ? $q.resolve() : $q.all(showPromises);

        if (!options.multiple) {
          // Wait for all opening interim's to finish their transition.
          hideAction = hideAction.then(function() {
            // Wait for all closing and showing interim's to be completely closed.
            var promiseArray = hidePromises.concat(showingInterims.map(service.cancel));
            return $q.all(promiseArray);
          });
        }

        var showAction = hideAction.then(function() {

          return interimElement
            .show()
            .catch(function(reason) { return reason; })
            .finally(function() {
              showPromises.splice(showPromises.indexOf(showAction), 1);
              showingInterims.push(interimElement);
            });

        });

        showPromises.push(showAction);

        // In AngularJS 1.6+, exceptions inside promises will cause a rejection. We need to handle
        // the rejection and only log it if it's an error.
        interimElement.deferred.promise.catch(function(fault) {
          if (fault instanceof Error) {
            $exceptionHandler(fault);
          }

          return fault;
        });

        // Return a promise that will be resolved when the interim
        // element is hidden or cancelled...
        return interimElement.deferred.promise;
      }

      /*
       * @ngdoc method
       * @name $$interimElement.$service#hide
       * @kind function
       *
       * @description
       * Removes the `$interimElement` from the DOM and resolves the promise returned from `show`
       *
       * @param {*} resolveParam Data to resolve the promise with
       * @returns a Promise that will be resolved after the element has been removed.
       *
       */
      function hide(reason, options) {
        options = options || {};

        if (options.closeAll) {
          // We have to make a shallow copy of the array, because otherwise the map will break.
          return $q.all(showingInterims.slice().reverse().map(closeElement));
        } else if (options.closeTo !== undefined) {
          return $q.all(showingInterims.slice(options.closeTo).map(closeElement));
        }

        // Hide the latest showing interim element.
        return closeElement(showingInterims[showingInterims.length - 1]);

        function closeElement(interim) {

          var hideAction = interim
            .remove(reason, false, options || { })
            .catch(function(reason) { return reason; })
            .finally(function() {
              hidePromises.splice(hidePromises.indexOf(hideAction), 1);
            });

          showingInterims.splice(showingInterims.indexOf(interim), 1);
          hidePromises.push(hideAction);

          return interim.deferred.promise;
        }
      }

      /*
       * @ngdoc method
       * @name $$interimElement.$service#cancel
       * @kind function
       *
       * @description
       * Removes the `$interimElement` from the DOM and rejects the promise returned from `show`
       *
       * @param {*} reason Data to reject the promise with
       * @returns Promise that will be resolved after the element has been removed.
       *
       */
      function cancel(reason, options) {
        var interim = showingInterims.pop();
        if (!interim) {
          return $q.when(reason);
        }

        var cancelAction = interim
          .remove(reason, true, options || {})
          .catch(function(reason) { return reason; })
          .finally(function() {
            hidePromises.splice(hidePromises.indexOf(cancelAction), 1);
          });

        hidePromises.push(cancelAction);

        // Since AngularJS 1.6.7, promises will be logged to $exceptionHandler when the promise
        // is not handling the rejection. We create a pseudo catch handler, which will prevent the
        // promise from being logged to the $exceptionHandler.
        return interim.deferred.promise.catch(angular.noop);
      }

      /**
       * Creates a function to wait for at least one interim element to be available.
       * @param callbackFn Function to be used as callback
       * @returns {Function}
       */
      function waitForInterim(callbackFn) {
        return function() {
          var fnArguments = arguments;

          if (!showingInterims.length) {
            // When there are still interim's opening, then wait for the first interim element to
            // finish its open animation.
            if (showPromises.length) {
              return showPromises[0].finally(function () {
                return callbackFn.apply(service, fnArguments);
              });
            }

            return $q.when("No interim elements currently showing up.");
          }

          return callbackFn.apply(service, fnArguments);
        };
      }

      /*
       * Special method to quick-remove the interim element without animations
       * Note: interim elements are in "interim containers"
       */
      function destroy(targetEl) {
        var interim = !targetEl ? showingInterims.shift() : null;

        var parentEl = angular.element(targetEl).length && angular.element(targetEl)[0].parentNode;

        if (parentEl) {
          // Try to find the interim in the stack which corresponds to the supplied DOM element.
          var filtered = showingInterims.filter(function(entry) {
            return entry.options.element[0] === parentEl;
          });

          // Note: This function might be called when the element already has been removed,
          // in which case we won't find any matches.
          if (filtered.length) {
            interim = filtered[0];
            showingInterims.splice(showingInterims.indexOf(interim), 1);
          }
        }

        return interim ? interim.remove(SHOW_CANCELLED, false, { '$destroy': true }) :
                         $q.when(SHOW_CANCELLED);
      }

      /*
       * Internal Interim Element Object
       * Used internally to manage the DOM element and related data
       */
      function InterimElement(options) {
        var self, element, showAction = $q.when(true);

        options = configureScopeAndTransitions(options);

        return self = {
          options : options,
          deferred: $q.defer(),
          show    : createAndTransitionIn,
          remove  : transitionOutAndRemove
        };

        /**
         * Compile, link, and show this interim element
         * Use optional autoHided and transition-in effects
         */
        function createAndTransitionIn() {
          return $q(function(resolve, reject) {

            // Trigger onCompiling callback before the compilation starts.
            // This is useful, when modifying options, which can be influenced by developers.
            options.onCompiling && options.onCompiling(options);

            compileElement(options)
              .then(function( compiledData ) {
                element = linkElement( compiledData, options );

                // Expose the cleanup function from the compiler.
                options.cleanupElement = compiledData.cleanup;

                showAction = showElement(element, options, compiledData.controller)
                  .then(resolve, rejectAll);
              }).catch(rejectAll);

            function rejectAll(fault) {
              // Force the '$md<xxx>.show()' promise to reject
              self.deferred.reject(fault);

              // Continue rejection propagation
              reject(fault);
            }
          });
        }

        /**
         * After the show process has finished/rejected:
         * - announce 'removing',
         * - perform the transition-out, and
         * - perform optional clean up scope.
         */
        function transitionOutAndRemove(response, isCancelled, opts) {

          // abort if the show() and compile failed
          if ( !element ) return $q.when(false);

          options = angular.extend(options || {}, opts || {});
          options.cancelAutoHide && options.cancelAutoHide();
          options.element.triggerHandler('$mdInterimElementRemove');

          if ( options.$destroy === true ) {

            return hideElement(options.element, options).then(function(){
              (isCancelled && rejectAll(response)) || resolveAll(response);
            });

          } else {
            $q.when(showAction).finally(function() {
              hideElement(options.element, options).then(function() {
                isCancelled ? rejectAll(response) : resolveAll(response);
              }, rejectAll);
            });

            return self.deferred.promise;
          }


          /**
           * The `show()` returns a promise that will be resolved when the interim
           * element is hidden or cancelled...
           */
          function resolveAll(response) {
            self.deferred.resolve(response);
          }

          /**
           * Force the '$md<xxx>.show()' promise to reject
           */
          function rejectAll(fault) {
            self.deferred.reject(fault);
          }
        }

        /**
         * Prepare optional isolated scope and prepare $animate with default enter and leave
         * transitions for the new element instance.
         */
        function configureScopeAndTransitions(options) {
          options = options || { };
          if ( options.template ) {
            options.template = $mdUtil.processTemplate(options.template);
          }

          return angular.extend({
            preserveScope: false,
            cancelAutoHide : angular.noop,
            scope: options.scope || $rootScope.$new(options.isolateScope),

            /**
             * Default usage to enable $animate to transition-in; can be easily overridden via 'options'
             */
            onShow: function transitionIn(scope, element, options) {
              return $animate.enter(element, options.parent);
            },

            /**
             * Default usage to enable $animate to transition-out; can be easily overridden via 'options'
             */
            onRemove: function transitionOut(scope, element) {
              // Element could be undefined if a new element is shown before
              // the old one finishes compiling.
              return element && $animate.leave(element) || $q.when();
            }
          }, options );

        }

        /**
         * Compile an element with a templateUrl, controller, and locals
         */
        function compileElement(options) {

          var compiled = !options.skipCompile ? $mdCompiler.compile(options) : null;

          return compiled || $q(function (resolve) {
              resolve({
                locals: {},
                link: function () {
                  return options.element;
                }
              });
            });
        }

        /**
         *  Link an element with compiled configuration
         */
        function linkElement(compileData, options){
          angular.extend(compileData.locals, options);

          var element = compileData.link(options.scope);

          // Search for parent at insertion time, if not specified
          options.element = element;
          options.parent = findParent(element, options);
          if (options.themable) $mdTheming(element);

          return element;
        }

        /**
         * Search for parent at insertion time, if not specified
         */
        function findParent(element, options) {
          var parent = options.parent;

          // Search for parent at insertion time, if not specified
          if (angular.isFunction(parent)) {
            parent = parent(options.scope, element, options);
          } else if (angular.isString(parent)) {
            parent = angular.element($document[0].querySelector(parent));
          } else {
            parent = angular.element(parent);
          }

          // If parent querySelector/getter function fails, or it's just null,
          // find a default.
          if (!(parent || {}).length) {
            var el;
            if ($rootElement[0] && $rootElement[0].querySelector) {
              el = $rootElement[0].querySelector(':not(svg) > body');
            }
            if (!el) el = $rootElement[0];
            if (el.nodeName == '#comment') {
              el = $document[0].body;
            }
            return angular.element(el);
          }

          return parent;
        }

        /**
         * If auto-hide is enabled, start timer and prepare cancel function
         */
        function startAutoHide() {
          var autoHideTimer, cancelAutoHide = angular.noop;

          if (options.hideDelay) {
            autoHideTimer = $timeout(service.hide, options.hideDelay) ;
            cancelAutoHide = function() {
              $timeout.cancel(autoHideTimer);
            };
          }

          // Cache for subsequent use
          options.cancelAutoHide = function() {
            cancelAutoHide();
            options.cancelAutoHide = undefined;
          };
        }

        /**
         * Show the element ( with transitions), notify complete and start
         * optional auto-Hide
         */
        function showElement(element, options, controller) {
          // Trigger onShowing callback before the `show()` starts
          var notifyShowing = options.onShowing || angular.noop;
          // Trigger onComplete callback when the `show()` finishes
          var notifyComplete = options.onComplete || angular.noop;

          // Necessary for consistency between AngularJS 1.5 and 1.6.
          try {
            notifyShowing(options.scope, element, options, controller);
          } catch (e) {
            return $q.reject(e);
          }

          return $q(function (resolve, reject) {
            try {
              // Start transitionIn
              $q.when(options.onShow(options.scope, element, options, controller))
                .then(function () {
                  notifyComplete(options.scope, element, options);
                  startAutoHide();

                  resolve(element);
                }, reject);

            } catch (e) {
              reject(e.message);
            }
          });
        }

        function hideElement(element, options) {
          var announceRemoving = options.onRemoving || angular.noop;

          return $q(function (resolve, reject) {
            try {
              // Start transitionIn
              var action = $q.when( options.onRemove(options.scope, element, options) || true );

              // Trigger callback *before* the remove operation starts
              announceRemoving(element, action);

              if (options.$destroy) {
                // For $destroy, onRemove should be synchronous
                resolve(element);

                if (!options.preserveScope && options.scope ) {
                  // scope destroy should still be be done after the current digest is done
                  action.then( function() { options.scope.$destroy(); });
                }
              } else {
                // Wait until transition-out is done
                action.then(function () {
                  if (!options.preserveScope && options.scope ) {
                    options.scope.$destroy();
                  }

                  resolve(element);
                }, reject);
              }
            } catch (e) {
              reject(e.message);
            }
          });
        }

      }
    };

  }
function InterimElementFactory($document, $q, $rootScope, $timeout, $rootElement, $animate,
                                 $mdUtil, $mdCompiler, $mdTheming, $injector, $exceptionHandler) {
    return function createInterimElementService() {
      var SHOW_CANCELLED = false;

      

      var service;

      var showPromises = []; 
      var hidePromises = []; 
      var showingInterims = []; 

      
      

      return service = {
        show: show,
        hide: waitForInterim(hide),
        cancel: waitForInterim(cancel),
        destroy : destroy,
        $injector_: $injector
      };

      
      function show(options) {
        options = options || {};
        var interimElement = new InterimElement(options || {});

        
        
        
        var hideAction = options.multiple ? $q.resolve() : $q.all(showPromises);

        if (!options.multiple) {
          
          hideAction = hideAction.then(function() {
            
            var promiseArray = hidePromises.concat(showingInterims.map(service.cancel));
            return $q.all(promiseArray);
          });
        }

        var showAction = hideAction.then(function() {

          return interimElement
            .show()
            .catch(function(reason) { return reason; })
            .finally(function() {
              showPromises.splice(showPromises.indexOf(showAction), 1);
              showingInterims.push(interimElement);
            });

        });

        showPromises.push(showAction);

        
        
        interimElement.deferred.promise.catch(function(fault) {
          if (fault instanceof Error) {
            $exceptionHandler(fault);
          }

          return fault;
        });

        
        
        return interimElement.deferred.promise;
      }

      
      function hide(reason, options) {
        options = options || {};

        if (options.closeAll) {
          
          return $q.all(showingInterims.slice().reverse().map(closeElement));
        } else if (options.closeTo !== undefined) {
          return $q.all(showingInterims.slice(options.closeTo).map(closeElement));
        }

        
        return closeElement(showingInterims[showingInterims.length - 1]);

        function closeElement(interim) {

          var hideAction = interim
            .remove(reason, false, options || { })
            .catch(function(reason) { return reason; })
            .finally(function() {
              hidePromises.splice(hidePromises.indexOf(hideAction), 1);
            });

          showingInterims.splice(showingInterims.indexOf(interim), 1);
          hidePromises.push(hideAction);

          return interim.deferred.promise;
        }
      }

      
      function cancel(reason, options) {
        var interim = showingInterims.pop();
        if (!interim) {
          return $q.when(reason);
        }

        var cancelAction = interim
          .remove(reason, true, options || {})
          .catch(function(reason) { return reason; })
          .finally(function() {
            hidePromises.splice(hidePromises.indexOf(cancelAction), 1);
          });

        hidePromises.push(cancelAction);

        
        
        
        return interim.deferred.promise.catch(angular.noop);
      }

      
      function waitForInterim(callbackFn) {
        return function() {
          var fnArguments = arguments;

          if (!showingInterims.length) {
            
            
            if (showPromises.length) {
              return showPromises[0].finally(function () {
                return callbackFn.apply(service, fnArguments);
              });
            }

            return $q.when("No interim elements currently showing up.");
          }

          return callbackFn.apply(service, fnArguments);
        };
      }

      
      function destroy(targetEl) {
        var interim = !targetEl ? showingInterims.shift() : null;

        var parentEl = angular.element(targetEl).length && angular.element(targetEl)[0].parentNode;

        if (parentEl) {
          
          var filtered = showingInterims.filter(function(entry) {
            return entry.options.element[0] === parentEl;
          });

          
          
          if (filtered.length) {
            interim = filtered[0];
            showingInterims.splice(showingInterims.indexOf(interim), 1);
          }
        }

        return interim ? interim.remove(SHOW_CANCELLED, false, { '$destroy': true }) :
                         $q.when(SHOW_CANCELLED);
      }

      
      function InterimElement(options) {
        var self, element, showAction = $q.when(true);

        options = configureScopeAndTransitions(options);

        return self = {
          options : options,
          deferred: $q.defer(),
          show    : createAndTransitionIn,
          remove  : transitionOutAndRemove
        };

        
        function createAndTransitionIn() {
          return $q(function(resolve, reject) {

            
            
            options.onCompiling && options.onCompiling(options);

            compileElement(options)
              .then(function( compiledData ) {
                element = linkElement( compiledData, options );

                
                options.cleanupElement = compiledData.cleanup;

                showAction = showElement(element, options, compiledData.controller)
                  .then(resolve, rejectAll);
              }).catch(rejectAll);

            function rejectAll(fault) {
              
              self.deferred.reject(fault);

              
              reject(fault);
            }
          });
        }

        
        function transitionOutAndRemove(response, isCancelled, opts) {

          
          if ( !element ) return $q.when(false);

          options = angular.extend(options || {}, opts || {});
          options.cancelAutoHide && options.cancelAutoHide();
          options.element.triggerHandler('$mdInterimElementRemove');

          if ( options.$destroy === true ) {

            return hideElement(options.element, options).then(function(){
              (isCancelled && rejectAll(response)) || resolveAll(response);
            });

          } else {
            $q.when(showAction).finally(function() {
              hideElement(options.element, options).then(function() {
                isCancelled ? rejectAll(response) : resolveAll(response);
              }, rejectAll);
            });

            return self.deferred.promise;
          }


          
          function resolveAll(response) {
            self.deferred.resolve(response);
          }

          
          function rejectAll(fault) {
            self.deferred.reject(fault);
          }
        }

        
        function configureScopeAndTransitions(options) {
          options = options || { };
          if ( options.template ) {
            options.template = $mdUtil.processTemplate(options.template);
          }

          return angular.extend({
            preserveScope: false,
            cancelAutoHide : angular.noop,
            scope: options.scope || $rootScope.$new(options.isolateScope),

            
            onShow: function transitionIn(scope, element, options) {
              return $animate.enter(element, options.parent);
            },

            
            onRemove: function transitionOut(scope, element) {
              
              
              return element && $animate.leave(element) || $q.when();
            }
          }, options );

        }

        
        function compileElement(options) {

          var compiled = !options.skipCompile ? $mdCompiler.compile(options) : null;

          return compiled || $q(function (resolve) {
              resolve({
                locals: {},
                link: function () {
                  return options.element;
                }
              });
            });
        }

        
        function linkElement(compileData, options){
          angular.extend(compileData.locals, options);

          var element = compileData.link(options.scope);

          
          options.element = element;
          options.parent = findParent(element, options);
          if (options.themable) $mdTheming(element);

          return element;
        }

        
        function findParent(element, options) {
          var parent = options.parent;

          
          if (angular.isFunction(parent)) {
            parent = parent(options.scope, element, options);
          } else if (angular.isString(parent)) {
            parent = angular.element($document[0].querySelector(parent));
          } else {
            parent = angular.element(parent);
          }

          
          
          if (!(parent || {}).length) {
            var el;
            if ($rootElement[0] && $rootElement[0].querySelector) {
              el = $rootElement[0].querySelector(':not(svg) > body');
            }
            if (!el) el = $rootElement[0];
            if (el.nodeName == '#comment') {
              el = $document[0].body;
            }
            return angular.element(el);
          }

          return parent;
        }

        
        function startAutoHide() {
          var autoHideTimer, cancelAutoHide = angular.noop;

          if (options.hideDelay) {
            autoHideTimer = $timeout(service.hide, options.hideDelay) ;
            cancelAutoHide = function() {
              $timeout.cancel(autoHideTimer);
            };
          }

          
          options.cancelAutoHide = function() {
            cancelAutoHide();
            options.cancelAutoHide = undefined;
          };
        }

        
        function showElement(element, options, controller) {
          
          var notifyShowing = options.onShowing || angular.noop;
          
          var notifyComplete = options.onComplete || angular.noop;

          
          try {
            notifyShowing(options.scope, element, options, controller);
          } catch (e) {
            return $q.reject(e);
          }

          return $q(function (resolve, reject) {
            try {
              
              $q.when(options.onShow(options.scope, element, options, controller))
                .then(function () {
                  notifyComplete(options.scope, element, options);
                  startAutoHide();

                  resolve(element);
                }, reject);

            } catch (e) {
              reject(e.message);
            }
          });
        }

        function hideElement(element, options) {
          var announceRemoving = options.onRemoving || angular.noop;

          return $q(function (resolve, reject) {
            try {
              
              var action = $q.when( options.onRemove(options.scope, element, options) || true );

              
              announceRemoving(element, action);

              if (options.$destroy) {
                
                resolve(element);

                if (!options.preserveScope && options.scope ) {
                  
                  action.then( function() { options.scope.$destroy(); });
                }
              } else {
                
                action.then(function () {
                  if (!options.preserveScope && options.scope ) {
                    options.scope.$destroy();
                  }

                  resolve(element);
                }, reject);
              }
            } catch (e) {
              reject(e.message);
            }
          });
        }

      }
    };

  }
function InterimElementFactory ( $document , $q , $rootScope , $timeout , $rootElement , $animate , $mdUtil , $mdCompiler , $mdTheming , $injector , $exceptionHandler ) { return function createInterimElementService ( ) { var SHOW_CANCELLED = false ; /*
       * @ngdoc service
       * @name $$interimElement.$service
       *
       * @description
       * A service used to control inserting and removing an element into the DOM.
       *
       */ var service ; var showPromises = [ ] ; // Promises for the interim's which are currently opening. var hidePromises = [ ] ; // Promises for the interim's which are currently hiding. var showingInterims = [ ] ; // Interim elements which are currently showing up. // Publish instance $$interimElement service; // ... used as $mdDialog, $mdToast, $mdMenu, and $mdSelect return service = { show : show , hide : waitForInterim ( hide ) , cancel : waitForInterim ( cancel ) , destroy : destroy , $injector_ : $injector } ; /*
       * @ngdoc method
       * @name $$interimElement.$service#show
       * @kind function
       *
       * @description
       * Adds the `$interimElement` to the DOM and returns a special promise that will be resolved or rejected
       * with hide or cancel, respectively. To external cancel/hide, developers should use the
       *
       * @param {*} options is hashMap of settings
       * @returns a Promise
       *
       */ function show ( options ) { options = options || { } ; var interimElement = new InterimElement ( options || { } ) ; // When an interim element is currently showing, we have to cancel it. // Just hiding it, will resolve the InterimElement's promise, the promise should be // rejected instead. var hideAction = options . multiple ? $q . resolve ( ) : $q . all ( showPromises ) ; if ( ! options . multiple ) { // Wait for all opening interim's to finish their transition. hideAction = hideAction . then ( function ( ) { // Wait for all closing and showing interim's to be completely closed. var promiseArray = hidePromises . concat ( showingInterims . map ( service . cancel ) ) ; return $q . all ( promiseArray ) ; } ) ; } var showAction = hideAction . then ( function ( ) { return interimElement . show ( ) . catch ( function ( reason ) { return reason ; } ) . finally ( function ( ) { showPromises . splice ( showPromises . indexOf ( showAction ) , 1 ) ; showingInterims . push ( interimElement ) ; } ) ; } ) ; showPromises . push ( showAction ) ; // In AngularJS 1.6+, exceptions inside promises will cause a rejection. We need to handle // the rejection and only log it if it's an error. interimElement . deferred . promise . catch ( function ( fault ) { if ( fault instanceof Error ) { $exceptionHandler ( fault ) ; } return fault ; } ) ; // Return a promise that will be resolved when the interim // element is hidden or cancelled... return interimElement . deferred . promise ; } /*
       * @ngdoc method
       * @name $$interimElement.$service#hide
       * @kind function
       *
       * @description
       * Removes the `$interimElement` from the DOM and resolves the promise returned from `show`
       *
       * @param {*} resolveParam Data to resolve the promise with
       * @returns a Promise that will be resolved after the element has been removed.
       *
       */ function hide ( reason , options ) { options = options || { } ; if ( options . closeAll ) { // We have to make a shallow copy of the array, because otherwise the map will break. return $q . all ( showingInterims . slice ( ) . reverse ( ) . map ( closeElement ) ) ; } else if ( options . closeTo !== undefined ) { return $q . all ( showingInterims . slice ( options . closeTo ) . map ( closeElement ) ) ; } // Hide the latest showing interim element. return closeElement ( showingInterims [ showingInterims . length - 1 ] ) ; function closeElement ( interim ) { var hideAction = interim . remove ( reason , false , options || { } ) . catch ( function ( reason ) { return reason ; } ) . finally ( function ( ) { hidePromises . splice ( hidePromises . indexOf ( hideAction ) , 1 ) ; } ) ; showingInterims . splice ( showingInterims . indexOf ( interim ) , 1 ) ; hidePromises . push ( hideAction ) ; return interim . deferred . promise ; } } /*
       * @ngdoc method
       * @name $$interimElement.$service#cancel
       * @kind function
       *
       * @description
       * Removes the `$interimElement` from the DOM and rejects the promise returned from `show`
       *
       * @param {*} reason Data to reject the promise with
       * @returns Promise that will be resolved after the element has been removed.
       *
       */ function cancel ( reason , options ) { var interim = showingInterims . pop ( ) ; if ( ! interim ) { return $q . when ( reason ) ; } var cancelAction = interim . remove ( reason , true , options || { } ) . catch ( function ( reason ) { return reason ; } ) . finally ( function ( ) { hidePromises . splice ( hidePromises . indexOf ( cancelAction ) , 1 ) ; } ) ; hidePromises . push ( cancelAction ) ; // Since AngularJS 1.6.7, promises will be logged to $exceptionHandler when the promise // is not handling the rejection. We create a pseudo catch handler, which will prevent the // promise from being logged to the $exceptionHandler. return interim . deferred . promise . catch ( angular . noop ) ; } /**
       * Creates a function to wait for at least one interim element to be available.
       * @param callbackFn Function to be used as callback
       * @returns {Function}
       */ function waitForInterim ( callbackFn ) { return function ( ) { var fnArguments = arguments ; if ( ! showingInterims . length ) { // When there are still interim's opening, then wait for the first interim element to // finish its open animation. if ( showPromises . length ) { return showPromises [ 0 ] . finally ( function ( ) { return callbackFn . apply ( service , fnArguments ) ; } ) ; } return $q . when ( "No interim elements currently showing up." ) ; } return callbackFn . apply ( service , fnArguments ) ; } ; } /*
       * Special method to quick-remove the interim element without animations
       * Note: interim elements are in "interim containers"
       */ function destroy ( targetEl ) { var interim = ! targetEl ? showingInterims . shift ( ) : null ; var parentEl = angular . element ( targetEl ) . length && angular . element ( targetEl ) [ 0 ] . parentNode ; if ( parentEl ) { // Try to find the interim in the stack which corresponds to the supplied DOM element. var filtered = showingInterims . filter ( function ( entry ) { return entry . options . element [ 0 ] === parentEl ; } ) ; // Note: This function might be called when the element already has been removed, // in which case we won't find any matches. if ( filtered . length ) { interim = filtered [ 0 ] ; showingInterims . splice ( showingInterims . indexOf ( interim ) , 1 ) ; } } return interim ? interim . remove ( SHOW_CANCELLED , false , { '$destroy' : true } ) : $q . when ( SHOW_CANCELLED ) ; } /*
       * Internal Interim Element Object
       * Used internally to manage the DOM element and related data
       */ function InterimElement ( options ) { var self , element , showAction = $q . when ( true ) ; options = configureScopeAndTransitions ( options ) ; return self = { options : options , deferred : $q . defer ( ) , show : createAndTransitionIn , remove : transitionOutAndRemove } ; /**
         * Compile, link, and show this interim element
         * Use optional autoHided and transition-in effects
         */ function createAndTransitionIn ( ) { return $q ( function ( resolve , reject ) { // Trigger onCompiling callback before the compilation starts. // This is useful, when modifying options, which can be influenced by developers. options . onCompiling && options . onCompiling ( options ) ; compileElement ( options ) . then ( function ( compiledData ) { element = linkElement ( compiledData , options ) ; // Expose the cleanup function from the compiler. options . cleanupElement = compiledData . cleanup ; showAction = showElement ( element , options , compiledData . controller ) . then ( resolve , rejectAll ) ; } ) . catch ( rejectAll ) ; function rejectAll ( fault ) { // Force the '$md<xxx>.show()' promise to reject self . deferred . reject ( fault ) ; // Continue rejection propagation reject ( fault ) ; } } ) ; } /**
         * After the show process has finished/rejected:
         * - announce 'removing',
         * - perform the transition-out, and
         * - perform optional clean up scope.
         */ function transitionOutAndRemove ( response , isCancelled , opts ) { // abort if the show() and compile failed if ( ! element ) return $q . when ( false ) ; options = angular . extend ( options || { } , opts || { } ) ; options . cancelAutoHide && options . cancelAutoHide ( ) ; options . element . triggerHandler ( '$mdInterimElementRemove' ) ; if ( options . $destroy === true ) { return hideElement ( options . element , options ) . then ( function ( ) { ( isCancelled && rejectAll ( response ) ) || resolveAll ( response ) ; } ) ; } else { $q . when ( showAction ) . finally ( function ( ) { hideElement ( options . element , options ) . then ( function ( ) { isCancelled ? rejectAll ( response ) : resolveAll ( response ) ; } , rejectAll ) ; } ) ; return self . deferred . promise ; } /**
           * The `show()` returns a promise that will be resolved when the interim
           * element is hidden or cancelled...
           */ function resolveAll ( response ) { self . deferred . resolve ( response ) ; } /**
           * Force the '$md<xxx>.show()' promise to reject
           */ function rejectAll ( fault ) { self . deferred . reject ( fault ) ; } } /**
         * Prepare optional isolated scope and prepare $animate with default enter and leave
         * transitions for the new element instance.
         */ function configureScopeAndTransitions ( options ) { options = options || { } ; if ( options . template ) { options . template = $mdUtil . processTemplate ( options . template ) ; } return angular . extend ( { preserveScope : false , cancelAutoHide : angular . noop , scope : options . scope || $rootScope . $new ( options . isolateScope ) , /**
             * Default usage to enable $animate to transition-in; can be easily overridden via 'options'
             */ onShow : function transitionIn ( scope , element , options ) { return $animate . enter ( element , options . parent ) ; } , /**
             * Default usage to enable $animate to transition-out; can be easily overridden via 'options'
             */ onRemove : function transitionOut ( scope , element ) { // Element could be undefined if a new element is shown before // the old one finishes compiling. return element && $animate . leave ( element ) || $q . when ( ) ; } } , options ) ; } /**
         * Compile an element with a templateUrl, controller, and locals
         */ function compileElement ( options ) { var compiled = ! options . skipCompile ? $mdCompiler . compile ( options ) : null ; return compiled || $q ( function ( resolve ) { resolve ( { locals : { } , link : function ( ) { return options . element ; } } ) ; } ) ; } /**
         *  Link an element with compiled configuration
         */ function linkElement ( compileData , options ) { angular . extend ( compileData . locals , options ) ; var element = compileData . link ( options . scope ) ; // Search for parent at insertion time, if not specified options . element = element ; options . parent = findParent ( element , options ) ; if ( options . themable ) $mdTheming ( element ) ; return element ; } /**
         * Search for parent at insertion time, if not specified
         */ function findParent ( element , options ) { var parent = options . parent ; // Search for parent at insertion time, if not specified if ( angular . isFunction ( parent ) ) { parent = parent ( options . scope , element , options ) ; } else if ( angular . isString ( parent ) ) { parent = angular . element ( $document [ 0 ] . querySelector ( parent ) ) ; } else { parent = angular . element ( parent ) ; } // If parent querySelector/getter function fails, or it's just null, // find a default. if ( ! ( parent || { } ) . length ) { var el ; if ( $rootElement [ 0 ] && $rootElement [ 0 ] . querySelector ) { el = $rootElement [ 0 ] . querySelector ( ':not(svg) > body' ) ; } if ( ! el ) el = $rootElement [ 0 ] ; if ( el . nodeName == '#comment' ) { el = $document [ 0 ] . body ; } return angular . element ( el ) ; } return parent ; } /**
         * If auto-hide is enabled, start timer and prepare cancel function
         */ function startAutoHide ( ) { var autoHideTimer , cancelAutoHide = angular . noop ; if ( options . hideDelay ) { autoHideTimer = $timeout ( service . hide , options . hideDelay ) ; cancelAutoHide = function ( ) { $timeout . cancel ( autoHideTimer ) ; } ; } // Cache for subsequent use options . cancelAutoHide = function ( ) { cancelAutoHide ( ) ; options . cancelAutoHide = undefined ; } ; } /**
         * Show the element ( with transitions), notify complete and start
         * optional auto-Hide
         */ function showElement ( element , options , controller ) { // Trigger onShowing callback before the `show()` starts var notifyShowing = options . onShowing || angular . noop ; // Trigger onComplete callback when the `show()` finishes var notifyComplete = options . onComplete || angular . noop ; // Necessary for consistency between AngularJS 1.5 and 1.6. try { notifyShowing ( options . scope , element , options , controller ) ; } catch ( e ) { return $q . reject ( e ) ; } return $q ( function ( resolve , reject ) { try { // Start transitionIn $q . when ( options . onShow ( options . scope , element , options , controller ) ) . then ( function ( ) { notifyComplete ( options . scope , element , options ) ; startAutoHide ( ) ; resolve ( element ) ; } , reject ) ; } catch ( e ) { reject ( e . message ) ; } } ) ; } function hideElement ( element , options ) { var announceRemoving = options . onRemoving || angular . noop ; return $q ( function ( resolve , reject ) { try { // Start transitionIn var action = $q . when ( options . onRemove ( options . scope , element , options ) || true ) ; // Trigger callback *before* the remove operation starts announceRemoving ( element , action ) ; if ( options . $destroy ) { // For $destroy, onRemove should be synchronous resolve ( element ) ; if ( ! options . preserveScope && options . scope ) { // scope destroy should still be be done after the current digest is done action . then ( function ( ) { options . scope . $destroy ( ) ; } ) ; } } else { // Wait until transition-out is done action . then ( function ( ) { if ( ! options . preserveScope && options . scope ) { options . scope . $destroy ( ) ; } resolve ( element ) ; } , reject ) ; } } catch ( e ) { reject ( e . message ) ; } } ) ; } } } ; }
/* @ngInject
/ *