Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 0d2e489

Browse files
Derek LouieErinCoughlan
authored andcommitted
feat(panel): animation hook and origin focus config
- Add onDomAdded, onOpenComplete, and onRemoving animation hooks. - Updates the detach / close code to focus on close.
1 parent 0168e86 commit 0d2e489

File tree

3 files changed

+444
-75
lines changed

3 files changed

+444
-75
lines changed

src/components/panel/panel.js

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ angular
131131
* behind the panel. Defaults to false.
132132
* - `disableParentScroll` - `{boolean=}`: Whether the user can scroll the
133133
* page behind the panel. Defaults to false.
134+
* - `onDomAdded` - `{function=}`: Callback function used to announce when
135+
* the panel is added to the DOM.
136+
* - `onOpenComplete` - `{function=}`: Callback function used to announce
137+
* when the open() action is finished.
138+
* - `onRemoving` - `{function=}`: Callback function used to announce the
139+
* close/hide() action is starting.
140+
* - `onDomRemoved` - `{function=}`: Callback function used to announce when the
141+
* panel is removed from the DOM.
142+
* - `origin` - `{(string|!angular.JQLite|!Element)=}`: The element to
143+
* focus on when the panel closes. This is commonly the element which triggered
144+
* the opening of the panel.
134145
*
135146
* TODO(ErinCoughlan): Add the following config options.
136147
* - `groupName` - `{string=}`: Name of panel groups. This group name is
@@ -212,15 +223,6 @@ angular
212223
* create.
213224
* - `isAttached` - `{boolean}`: Whether the panel is attached to the DOM.
214225
* Visibility to the user does not factor into isAttached.
215-
*
216-
* TODO(ErinCoughlan): Add the following properties.
217-
* - `onDomAdded` - `{function=}`: Callback function used to announce when
218-
* the panel is added to the DOM.
219-
* - `onOpenComplete` - `{function=}`: Callback function used to announce
220-
* when the open() action is finished.
221-
* - `onRemoving` - `{function=}`: Callback function used to announce the
222-
* close/hide() action is starting. This allows developers to run custom
223-
* animations in parallel the close animations.
224226
*/
225227

226228
/**
@@ -237,8 +239,7 @@ angular
237239
* @ngdoc method
238240
* @name MdPanelRef#close
239241
* @description
240-
* Hides and detaches the panel. This method destroys the reference to the panel.
241-
* In order to open the panel again, a new one must be created.
242+
* Hides and detaches the panel.
242243
*
243244
* @returns {!angular.$q.Promise} A promise that is resolved when the panel is
244245
* closed.
@@ -725,6 +726,7 @@ MdPanelService.prototype._wrapTemplate = function(origTemplate) {
725726
'</div>';
726727
};
727728

729+
728730
/*****************************************************************************
729731
* MdPanelRef *
730732
*****************************************************************************/
@@ -779,7 +781,6 @@ function MdPanelRef(config, $injector) {
779781
*/
780782
this.isAttached = false;
781783

782-
783784
// Private variables.
784785
/** @private {!Object} */
785786
this._config = config;
@@ -821,8 +822,9 @@ MdPanelRef.prototype.open = function() {
821822
var show = self._simpleBind(self.show, self);
822823

823824
self.attach()
824-
.then(show, reject)
825-
.then(done, reject);
825+
.then(show)
826+
.then(done)
827+
.catch(reject);
826828
});
827829
};
828830

@@ -835,13 +837,15 @@ MdPanelRef.prototype.open = function() {
835837
*/
836838
MdPanelRef.prototype.close = function() {
837839
var self = this;
840+
838841
return this._$q(function(resolve, reject) {
839842
var done = self._done(resolve, self);
840843
var detach = self._simpleBind(self.detach, self);
841844

842845
self.hide()
843-
.then(detach, reject)
844-
.then(done, reject);
846+
.then(detach)
847+
.then(done)
848+
.catch(reject);
845849
});
846850
};
847851

@@ -860,14 +864,21 @@ MdPanelRef.prototype.attach = function() {
860864
var self = this;
861865
return this._$q(function(resolve, reject) {
862866
var done = self._done(resolve, self);
863-
864-
self._$q.all([
865-
self._createBackdrop(),
866-
self._createPanel().then(function() {
867+
var onDomAdded = self._config['onDomAdded'] || angular.noop;
868+
var addListeners = function(response) {
867869
self.isAttached = true;
868870
self._addEventListeners();
869-
}, reject)
870-
]).then(done, reject);
871+
return response;
872+
};
873+
874+
self._$q.all([
875+
self._createBackdrop(),
876+
self._createPanel()
877+
.then(addListeners)
878+
.catch(reject)
879+
]).then(onDomAdded)
880+
.then(done)
881+
.catch(reject);
871882
});
872883
};
873884

@@ -884,8 +895,10 @@ MdPanelRef.prototype.detach = function() {
884895
}
885896

886897
var self = this;
898+
var onDomRemoved = self._config['onDomRemoved'] || angular.noop;
899+
887900
var detachFn = function() {
888-
self._removeEventListener();
901+
self._removeEventListeners();
889902

890903
// Remove the focus traps that we added earlier for keeping focus within
891904
// the panel.
@@ -913,11 +926,21 @@ MdPanelRef.prototype.detach = function() {
913926
self._$q.all([
914927
detachFn(),
915928
self._backdropRef ? self._backdropRef.detach() : true
916-
]).then(done, reject);
929+
]).then(onDomRemoved)
930+
.then(done)
931+
.catch(reject);
917932
});
918933
};
919934

920935

936+
/**
937+
* Destroys the panel. The Panel cannot be opened again after this.
938+
*/
939+
MdPanelRef.prototype.destroy = function() {
940+
this._config.locals = null;
941+
};
942+
943+
921944
/**
922945
* Shows the panel.
923946
*
@@ -943,11 +966,14 @@ MdPanelRef.prototype.show = function() {
943966

944967
return this._$q(function(resolve, reject) {
945968
var done = self._done(resolve, self);
969+
var onOpenComplete = self._config['onOpenComplete'] || angular.noop;
946970

947971
self._$q.all([
948972
self._backdropRef ? self._backdropRef.show() : self,
949973
animatePromise().then(function() { self._focusOnOpen(); }, reject)
950-
]).then(done, reject);
974+
]).then(onOpenComplete)
975+
.then(done)
976+
.catch(reject);
951977
});
952978
};
953979

@@ -970,13 +996,29 @@ MdPanelRef.prototype.hide = function() {
970996
}
971997

972998
var self = this;
999+
9731000
return this._$q(function(resolve, reject) {
9741001
var done = self._done(resolve, self);
1002+
var onRemoving = self._config['onRemoving'] || angular.noop;
1003+
1004+
var focusOnOrigin = function() {
1005+
var origin = self._config['origin'];
1006+
if (origin) {
1007+
getElement(origin).focus();
1008+
}
1009+
};
1010+
1011+
var hidePanel = function() {
1012+
self.addClass(MD_PANEL_HIDDEN);
1013+
};
9751014

9761015
self._$q.all([
9771016
self._backdropRef ? self._backdropRef.hide() : self,
978-
self._animateClose().then(function() { self.addClass(MD_PANEL_HIDDEN); },
979-
reject)
1017+
self._animateClose()
1018+
.then(onRemoving)
1019+
.then(hidePanel)
1020+
.then(focusOnOrigin)
1021+
.catch(reject)
9801022
]).then(done, reject);
9811023
});
9821024
};
@@ -1037,10 +1079,12 @@ MdPanelRef.prototype.toggleClass = function(toggleClass) {
10371079
*/
10381080
MdPanelRef.prototype._createPanel = function() {
10391081
var self = this;
1082+
10401083
return this._$q(function(resolve, reject) {
10411084
if (!self._config.locals) {
10421085
self._config.locals = {};
10431086
}
1087+
10441088
self._config.locals.mdPanelRef = self;
10451089
self._$mdCompiler.compile(self._config)
10461090
.then(function(compileData) {
@@ -1184,7 +1228,7 @@ MdPanelRef.prototype._addEventListeners = function() {
11841228
* Remove event listeners added in _addEventListeners.
11851229
* @private
11861230
*/
1187-
MdPanelRef.prototype._removeEventListener = function() {
1231+
MdPanelRef.prototype._removeEventListeners = function() {
11881232
this._removeListeners && this._removeListeners.forEach(function(removeFn) {
11891233
removeFn();
11901234
});
@@ -1289,6 +1333,12 @@ MdPanelRef.prototype._configureTrapFocus = function() {
12891333
this._topFocusTrap.addEventListener('focus', focusHandler);
12901334
this._bottomFocusTrap.addEventListener('focus', focusHandler);
12911335

1336+
// Queue remove listeners function
1337+
this._removeListeners.push(this._simpleBind(function() {
1338+
this._topFocusTrap.removeEventListener('focus', focusHandler);
1339+
this._bottomFocusTrap.removeEventListener('focus', focusHandler);
1340+
}, this));
1341+
12921342
// The top focus trap inserted immediately before the md-panel element (as
12931343
// a sibling). The bottom focus trap inserted immediately after the
12941344
// md-panel element (as a sibling).

0 commit comments

Comments
 (0)