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

Commit 639cdaf

Browse files
committed
fix(panel): Allow clickOutsideToClose to work with propagateContainerEvents
If both the `clickOutsideToClose` and `propagateContainerEvents` parameters are set to true within the panel configuration, then the panel will be closed when a click happens outside of the panel. Fixes #9388
1 parent e3619e6 commit 639cdaf

File tree

2 files changed

+71
-4
lines changed

2 files changed

+71
-4
lines changed

src/components/panel/panel.js

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ angular
1414
* PUBLIC DOCUMENTATION *
1515
*****************************************************************************/
1616

17+
1718
/**
1819
* @ngdoc service
1920
* @name $mdPanel
@@ -685,6 +686,7 @@ angular
685686
* MdPanelAnimation *
686687
*****************************************************************************/
687688

689+
688690
/**
689691
* @ngdoc type
690692
* @name MdPanelAnimation
@@ -1721,13 +1723,15 @@ MdPanelRef.prototype._configureEscapeToClose = function() {
17211723
*/
17221724
MdPanelRef.prototype._configureClickOutsideToClose = function() {
17231725
if (this.config['clickOutsideToClose']) {
1724-
var target = this.panelContainer;
1726+
var target = this.config['propagateContainerEvents'] ?
1727+
angular.element(document.body) :
1728+
this.panelContainer;
17251729
var sourceElem;
17261730

17271731
// Keep track of the element on which the mouse originally went down
17281732
// so that we can only close the backdrop when the 'click' started on it.
1729-
// A simple 'click' handler does not work,
1730-
// it sets the target object as the element the mouse went down on.
1733+
// A simple 'click' handler does not work, it sets the target object as the
1734+
// element the mouse went down on.
17311735
var mousedownHandler = function(ev) {
17321736
sourceElem = ev.target;
17331737
};
@@ -1737,14 +1741,36 @@ MdPanelRef.prototype._configureClickOutsideToClose = function() {
17371741
// panel we don't want to panel to close.
17381742
var self = this;
17391743
var mouseupHandler = function(ev) {
1740-
if (sourceElem === target[0] && ev.target === target[0]) {
1744+
if (self.config['propagateContainerEvents']) {
1745+
1746+
// We check if the sourceElem of the event is the panel element or one
1747+
// of it's children. If it is not, then close the panel.
1748+
var found = findSourceElem(
1749+
self.panelEl.find(sourceElem.tagName),
1750+
sourceElem
1751+
);
1752+
if (!found && self.panelEl[0] !== sourceElem) {
1753+
self.close();
1754+
}
1755+
1756+
} else if (sourceElem === target[0] && ev.target === target[0]) {
17411757
ev.stopPropagation();
17421758
ev.preventDefault();
17431759

17441760
self.close();
17451761
}
17461762
};
17471763

1764+
var findSourceElem = function(elems, sourceElem) {
1765+
var found = false;
1766+
angular.forEach(elems, function(elem) {
1767+
if (elem === sourceElem) {
1768+
found = true;
1769+
}
1770+
});
1771+
return found;
1772+
};
1773+
17481774
// Add listeners
17491775
target.on('mousedown', mousedownHandler);
17501776
target.on('mouseup', mouseupHandler);
@@ -1884,6 +1910,7 @@ MdPanelRef.prototype._animateClose = function() {
18841910
});
18851911
};
18861912

1913+
18871914
/**
18881915
* Registers a interceptor with the panel. The callback should return a promise,
18891916
* which will allow the action to continue when it gets resolved, or will
@@ -1914,6 +1941,7 @@ MdPanelRef.prototype.registerInterceptor = function(type, callback) {
19141941
return this;
19151942
};
19161943

1944+
19171945
/**
19181946
* Removes a registered interceptor.
19191947
* @param {string} type Type of interceptor to be removed.
@@ -2606,6 +2634,7 @@ MdPanelPosition.prototype._constrainToViewport = function(panelEl) {
26062634
}
26072635
};
26082636

2637+
26092638
/**
26102639
* Switches between 'start' and 'end'.
26112640
* @param {string} position Horizontal position of the panel
@@ -2795,6 +2824,7 @@ MdPanelAnimation.prototype.closeTo = function(closeTo) {
27952824
return this;
27962825
};
27972826

2827+
27982828
/**
27992829
* Specifies the duration of the animation in milliseconds.
28002830
* @param {number|{open: number, close: number}} duration
@@ -2820,6 +2850,7 @@ MdPanelAnimation.prototype.duration = function(duration) {
28202850
}
28212851
};
28222852

2853+
28232854
/**
28242855
* Returns the element and bounds for the animation target.
28252856
* @param {string|!Element|{top: number, left: number}} location
@@ -3037,6 +3068,7 @@ MdPanelAnimation.prototype._getBoundingClientRect = function(element) {
30373068
* Util Methods *
30383069
*****************************************************************************/
30393070

3071+
30403072
/**
30413073
* Returns the angular element associated with a css selector or element.
30423074
* @param el {string|!angular.JQLite|!Element}
@@ -3048,6 +3080,7 @@ function getElement(el) {
30483080
return angular.element(queryResult);
30493081
}
30503082

3083+
30513084
/**
30523085
* Gets the computed values for an element's translateX and translateY in px.
30533086
* @param {!angular.JQLite|!Element} el

src/components/panel/panel.spec.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,20 @@ describe('$mdPanel', function() {
542542
expect(PANEL_EL).not.toExist();
543543
});
544544

545+
it('should close when clickOutsideToClose set to true and ' +
546+
'propagateContainerEvents is also set to true', function() {
547+
var config = {
548+
propagateContainerEvents: true,
549+
clickOutsideToClose: true
550+
};
551+
552+
openPanel(config);
553+
554+
clickOutsideOfPanel();
555+
556+
expect(PANEL_EL).not.toExist();
557+
});
558+
545559
it('should not close when escapeToClose set to false', function() {
546560
openPanel();
547561

@@ -2843,6 +2857,26 @@ describe('$mdPanel', function() {
28432857
flushPanel();
28442858
}
28452859

2860+
function clickOutsideOfPanel() {
2861+
if (!panelRef) {
2862+
return;
2863+
}
2864+
2865+
var body = angular.element(document.body);
2866+
2867+
body.triggerHandler({
2868+
type: 'mousedown',
2869+
target: body[0]
2870+
});
2871+
2872+
body.triggerHandler({
2873+
type: 'mouseup',
2874+
target: body[0]
2875+
});
2876+
2877+
flushPanel();
2878+
}
2879+
28462880
function pressEscape() {
28472881
if (!panelRef) {
28482882
return;

0 commit comments

Comments
 (0)