@@ -353,6 +353,47 @@ angular
353353 * @param {!MdPanelPosition } position
354354 */
355355
356+ /**
357+ * @ngdoc method
358+ * @name MdPanelRef#registerInterceptor
359+ * @description
360+ *
361+ * Registers an interceptor with the panel. The callback should return a promise,
362+ * which will allow the action to continue when it gets resolved, or will
363+ * prevent an action if it is rejected. The interceptors are called sequentially
364+ * and it reverse order. `type` must be one of the following
365+ * values available on `$mdPanel.interceptorTypes`:
366+ * * `CLOSE` - Gets called before the panel begins closing.
367+ *
368+ * @param {string } type Type of interceptor.
369+ * @param {!angular.$q.Promise<any> } callback Callback to be registered.
370+ * @returns {!MdPanelRef }
371+ */
372+
373+ /**
374+ * @ngdoc method
375+ * @name MdPanelRef#removeInterceptor
376+ * @description
377+ *
378+ * Removes a registered interceptor.
379+ *
380+ * @param {string } type Type of interceptor to be removed.
381+ * @param {function(): !angular.$q.Promise<any> } callback Interceptor to be removed.
382+ * @returns {!MdPanelRef }
383+ */
384+
385+ /**
386+ * @ngdoc method
387+ * @name MdPanelRef#removeAllInterceptors
388+ * @description
389+ *
390+ * Removes all interceptors. If a type is supplied, only the
391+ * interceptors of that type will be cleared.
392+ *
393+ * @param {string= } type Type of interceptors to be removed.
394+ * @returns {!MdPanelRef }
395+ */
396+
356397
357398/*****************************************************************************
358399 * MdPanelPosition *
@@ -743,6 +784,12 @@ function MdPanelService($rootElement, $rootScope, $injector, $window) {
743784 * @type {enum }
744785 */
745786 this . yPosition = MdPanelPosition . yPosition ;
787+
788+ /**
789+ * Possible values for the interceptors that can be registered on a panel.
790+ * @type {enum }
791+ */
792+ this . interceptorTypes = MdPanelRef . interceptorTypes ;
746793}
747794
748795
@@ -912,9 +959,20 @@ function MdPanelRef(config, $injector) {
912959
913960 /** @private {Function?} */
914961 this . _restoreScroll = null ;
962+
963+ /**
964+ * Keeps track of all the panel interceptors.
965+ * @private {!Object}
966+ */
967+ this . _interceptors = Object . create ( null ) ;
915968}
916969
917970
971+ MdPanelRef . interceptorTypes = {
972+ CLOSE : 'onClose'
973+ } ;
974+
975+
918976/**
919977 * Opens an already created and configured panel. If the panel is already
920978 * visible, does nothing.
@@ -944,13 +1002,15 @@ MdPanelRef.prototype.close = function() {
9441002 var self = this ;
9451003
9461004 return this . _$q ( function ( resolve , reject ) {
947- var done = self . _done ( resolve , self ) ;
948- var detach = self . _simpleBind ( self . detach , self ) ;
949-
950- self . hide ( )
951- . then ( detach )
952- . then ( done )
953- . catch ( reject ) ;
1005+ self . _callInterceptors ( MdPanelRef . interceptorTypes . CLOSE ) . then ( function ( ) {
1006+ var done = self . _done ( resolve , self ) ;
1007+ var detach = self . _simpleBind ( self . detach , self ) ;
1008+
1009+ self . hide ( )
1010+ . then ( detach )
1011+ . then ( done )
1012+ . catch ( reject ) ;
1013+ } , reject ) ;
9541014 } ) ;
9551015} ;
9561016
@@ -1042,6 +1102,7 @@ MdPanelRef.prototype.detach = function() {
10421102MdPanelRef . prototype . destroy = function ( ) {
10431103 this . config . scope . $destroy ( ) ;
10441104 this . config . locals = null ;
1105+ this . _interceptors = null ;
10451106} ;
10461107
10471108
@@ -1641,6 +1702,106 @@ MdPanelRef.prototype._animateClose = function() {
16411702 } ) ;
16421703} ;
16431704
1705+ /**
1706+ * Registers a interceptor with the panel. The callback should return a promise,
1707+ * which will allow the action to continue when it gets resolved, or will
1708+ * prevent an action if it is rejected.
1709+ * @param {string } type Type of interceptor.
1710+ * @param {!angular.$q.Promise<!any> } callback Callback to be registered.
1711+ * @returns {!MdPanelRef }
1712+ */
1713+ MdPanelRef . prototype . registerInterceptor = function ( type , callback ) {
1714+ var error = null ;
1715+
1716+ if ( ! angular . isString ( type ) ) {
1717+ error = 'Interceptor type must be a string, instead got ' + typeof type ;
1718+ } else if ( ! angular . isFunction ( callback ) ) {
1719+ error = 'Interceptor callback must be a function, instead got ' + typeof callback ;
1720+ }
1721+
1722+ if ( error ) {
1723+ throw new Error ( 'MdPanel: ' + error ) ;
1724+ }
1725+
1726+ var interceptors = this . _interceptors [ type ] = this . _interceptors [ type ] || [ ] ;
1727+
1728+ if ( interceptors . indexOf ( callback ) === - 1 ) {
1729+ interceptors . push ( callback ) ;
1730+ }
1731+
1732+ return this ;
1733+ } ;
1734+
1735+ /**
1736+ * Removes a registered interceptor.
1737+ * @param {string } type Type of interceptor to be removed.
1738+ * @param {Function } callback Interceptor to be removed.
1739+ * @returns {!MdPanelRef }
1740+ */
1741+ MdPanelRef . prototype . removeInterceptor = function ( type , callback ) {
1742+ var index = this . _interceptors [ type ] ?
1743+ this . _interceptors [ type ] . indexOf ( callback ) : - 1 ;
1744+
1745+ if ( index > - 1 ) {
1746+ this . _interceptors [ type ] . splice ( index , 1 ) ;
1747+ }
1748+
1749+ return this ;
1750+ } ;
1751+
1752+
1753+ /**
1754+ * Removes all interceptors.
1755+ * @param {string= } type Type of interceptors to be removed.
1756+ * If ommited, all interceptors types will be removed.
1757+ * @returns {!MdPanelRef }
1758+ */
1759+ MdPanelRef . prototype . removeAllInterceptors = function ( type ) {
1760+ if ( type ) {
1761+ this . _interceptors [ type ] = [ ] ;
1762+ } else {
1763+ this . _interceptors = Object . create ( null ) ;
1764+ }
1765+
1766+ return this ;
1767+ } ;
1768+
1769+
1770+ /**
1771+ * Invokes all the interceptors of a certain type sequantially in
1772+ * reverse order. Works in a similar way to `$q.all`, except it
1773+ * respects the order of the functions.
1774+ * @param {string } type Type of interceptors to be invoked.
1775+ * @returns {!angular.$q.Promise<!MdPanelRef> }
1776+ * @private
1777+ */
1778+ MdPanelRef . prototype . _callInterceptors = function ( type ) {
1779+ var self = this ;
1780+ var $q = self . _$q ;
1781+ var interceptors = self . _interceptors && self . _interceptors [ type ] || [ ] ;
1782+
1783+ return interceptors . reduceRight ( function ( promise , interceptor ) {
1784+ var isPromiseLike = interceptor && angular . isFunction ( interceptor . then ) ;
1785+ var response = isPromiseLike ? interceptor : null ;
1786+
1787+ /**
1788+ * For interceptors to reject/cancel subsequent portions of the chain, simply
1789+ * return a `$q.reject(<value>)`
1790+ */
1791+ return promise . then ( function ( ) {
1792+ if ( ! response ) {
1793+ try {
1794+ response = interceptor ( self ) ;
1795+ } catch ( e ) {
1796+ response = $q . reject ( e ) ;
1797+ }
1798+ }
1799+
1800+ return response ;
1801+ } ) ;
1802+ } , $q . resolve ( self ) ) ;
1803+ } ;
1804+
16441805
16451806/**
16461807 * Faster, more basic than angular.bind
0 commit comments