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

Commit 9f4f19e

Browse files
committed
update(panel): refactor positioning to allow multiple.
1 parent b1c1bde commit 9f4f19e

File tree

3 files changed

+108
-69
lines changed

3 files changed

+108
-69
lines changed

src/components/panel/demoBasicUsage/script.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ BasicDemoCtrl.prototype.showDialog = function() {
4848
BasicDemoCtrl.prototype.showMenu = function(ev) {
4949
var position = this._mdPanel.newPanelPosition()
5050
.relativeTo('.demo-menu-open-button')
51-
.withPanelXPosition(this._mdPanel.xPosition.ALIGN_START)
52-
.withPanelYPosition(this._mdPanel.yPosition.BELOW);
51+
.addPanelPosition(this._mdPanel.xPosition.ALIGN_START, this._mdPanel.yPosition.BELOW);
5352

5453
var config = {
5554
attachTo: '.demo-md-panel',

src/components/panel/panel.js

Lines changed: 73 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -338,14 +338,12 @@ angular
338338
* Overlapping the panel with an element:
339339
* `new MdPanelPosition()
340340
* .relativeTo(someElement)
341-
* .withPanelXPosition($mdPanel.xPosition.ALIGN_START)
342-
* .withPanelYPosition($mdPanel.yPosition.ALIGN_TOPS);`
341+
* .addPanelPosition($mdPanel.xPosition.ALIGN_START, $mdPanel.yPosition.ALIGN_TOPS);`
343342
*
344343
* Aligning the panel with the bottom of an element:
345344
* `new MdPanelPosition()
346345
* .relativeTo(someElement)
347-
* .withPanelXPosition($mdPanel.xPosition.CENTER)
348-
* .withPanelYPosition($mdPanel.yPosition.BELOW);`
346+
* .addPanelPosition($mdPanel.xPosition.CENTER, $mdPanel.yPosition.BELOW);
349347
*/
350348

351349
/**
@@ -438,10 +436,15 @@ angular
438436

439437
/**
440438
* @ngdoc method
441-
* @name MdPanelPosition#withPanelXPosition
439+
* @name MdPanelPosition#addPanelPosition
442440
* @param {string} xPosition
441+
* @param {string} yPosition
443442
* @description
444-
* Sets the x position for the panel relative to another element.
443+
* Sets the x and y position for the panel relative to another element. Can be
444+
* called multiple times to specify an ordered list of panel positions. The
445+
* first position which allows the panel to be completely on-screen will be
446+
* chosen; the last position will be chose whether it is on-screen or not.
447+
*
445448
* xPosition must be one of the following values available on
446449
* $mdPanel.xPosition:
447450
*
@@ -459,14 +462,7 @@ angular
459462
* C: CENTER
460463
* D: ALIGN_END (for LTR displays)
461464
* E: OFFSET_END (for LTR displays)
462-
*/
463-
464-
/**
465-
* @ngdoc method
466-
* @name MdPanelPosition#withPanelYPosition
467-
* @param {string} yPosition
468-
* @description
469-
* Sets the y position for the panel relative to another element.
465+
*
470466
* yPosition must be one of the following values available on
471467
* $mdPanel.yPosition:
472468
*
@@ -485,6 +481,7 @@ angular
485481
* H: CENTER
486482
* I: ALIGN_BOTTOMS
487483
* J: ABOVE
484+
* @returns {MdPanelPosition}
488485
*/
489486

490487
/**
@@ -1090,7 +1087,7 @@ MdPanelRef.prototype._addStyles = function() {
10901087
return this._$q(function(resolve) {
10911088
self._panelContainer.css('z-index', self._config['zIndex']);
10921089
self._panelEl.css('z-index', self._config['zIndex'] + 1);
1093-
1090+
10941091
if (self._config['fullscreen']) {
10951092
self._panelEl.addClass('_md-panel-fullscreen');
10961093
resolve(self);
@@ -1436,11 +1433,8 @@ function MdPanelPosition() {
14361433
/** @private {!Array<string>} */
14371434
this._translateY = [];
14381435

1439-
/** @private {string} */
1440-
this._xPosition = '';
1441-
1442-
/** @private {string} */
1443-
this._yPosition = '';
1436+
/** @private {!Array<{x:string, y:string}>} */
1437+
this._positions = [];
14441438
}
14451439

14461440

@@ -1583,60 +1577,77 @@ MdPanelPosition.prototype.relativeTo = function(element) {
15831577

15841578

15851579
/**
1586-
* Sets the x position for the panel relative to another element.
1587-
* xPosition must be one of the MdPanelPosition.xPosition values.
1588-
*
1589-
* @param {string} xPosition
1580+
* Sets the x and y positions for the panel relative to another element.
1581+
* @param {string} xPosition must be one of the MdPanelPosition.xPosition values.
1582+
* @param {string} yPosition must be one of the MdPanelPosition.yPosition values.
15901583
* @returns {MdPanelPosition}
15911584
*/
1592-
MdPanelPosition.prototype.withPanelXPosition = function(xPosition) {
1585+
MdPanelPosition.prototype.addPanelPosition = function(xPosition, yPosition) {
15931586
if (!this._relativeToRect) {
1594-
throw new Error('withPanelXPosition can only be used with relative' +
1587+
throw new Error('addPanelPosition can only be used with relative ' +
15951588
'positioning. Set relativeTo first.');
15961589
}
15971590

1598-
var positionKeys = Object.keys(MdPanelPosition.xPosition);
1591+
this._validateXPosition(xPosition);
1592+
this._validateYPosition(yPosition);
1593+
1594+
this._positions.push({
1595+
x: xPosition,
1596+
y: yPosition,
1597+
});
1598+
return this;
1599+
};
1600+
1601+
1602+
/**
1603+
* Ensure that yPosition is a valid position name. Throw an exception if not.
1604+
* @param {string} yPosition
1605+
*/
1606+
MdPanelPosition.prototype._validateYPosition = function(yPosition) {
1607+
// empty is ok
1608+
if (yPosition == null) {
1609+
return;
1610+
}
1611+
1612+
var positionKeys = Object.keys(MdPanelPosition.yPosition);
15991613
var positionValues = [];
16001614
for (var key, i = 0; key = positionKeys[i]; i++) {
1601-
var position = MdPanelPosition.xPosition[key];
1615+
var position = MdPanelPosition.yPosition[key];
16021616
positionValues.push(position);
1603-
if (position === xPosition) {
1604-
this._xPosition = xPosition;
1605-
return this;
1617+
1618+
if (position === yPosition) {
1619+
return;
16061620
}
16071621
}
16081622

1609-
throw new Error('withPanelXPosition only accepts the following values:\n' +
1610-
positionValues.join(' | '));
1623+
throw new Error('Panel y position only accepts the following values:\n' +
1624+
positionValues.join(' | '));
16111625
};
16121626

16131627

16141628
/**
1615-
* Sets the y position for the panel relative to another element.
1616-
* yPosition must be one of the MdPanelPosition.yPosition values.
1617-
*
1618-
* @param {string} yPosition
1619-
* @returns {MdPanelPosition}
1629+
* Ensure that xPosition is a valid position name. Throw an exception if not.
1630+
* @param {string} xPosition
16201631
*/
1621-
MdPanelPosition.prototype.withPanelYPosition = function(yPosition) {
1622-
if (!this._relativeToRect) {
1623-
throw new Error('withPanelYPosition can only be used with relative ' +
1624-
'positioning. Set relativeTo first.');
1632+
MdPanelPosition.prototype._validateXPosition = function(xPosition) {
1633+
// empty is ok
1634+
if (xPosition == null) {
1635+
return;
16251636
}
16261637

1627-
var positionKeys = Object.keys(MdPanelPosition.yPosition);
1638+
var positionKeys = Object.keys(MdPanelPosition.xPosition);
16281639
var positionValues = [];
16291640
for (var key, i = 0; key = positionKeys[i]; i++) {
1630-
var position = MdPanelPosition.yPosition[key];
1641+
var position = MdPanelPosition.xPosition[key];
16311642
positionValues.push(position);
1632-
if (position === yPosition) {
1633-
this._yPosition = yPosition;
1634-
return this;
1643+
if (position === xPosition) {
1644+
return;
16351645
}
16361646
}
16371647

1638-
throw new Error('withPanelYPosition only accepts the following values:\n' +
1648+
throw new Error('Panel x Position only accepts the following values:\n' +
16391649
positionValues.join(' | '));
1650+
16401651
};
16411652

16421653

@@ -1722,6 +1733,16 @@ MdPanelPosition.prototype.getTransform = function() {
17221733
};
17231734

17241735

1736+
/**
1737+
* Gets the first x/y position that can fit on-screen.
1738+
* @returns {string}
1739+
*/
1740+
MdPanelPosition.prototype.getActualPosition = function() {
1741+
// TODO(gmoothart): intelligently pick the first on-screen position.
1742+
return this._positions[0] || {};
1743+
};
1744+
1745+
17251746
/**
17261747
* Reduces a list of translate values to a string that can be used within
17271748
* transform.
@@ -1765,7 +1786,9 @@ MdPanelPosition.prototype._calculatePanelPosition = function(panelEl) {
17651786
var targetRight = targetBounds.right;
17661787
var targetWidth = targetBounds.width;
17671788

1768-
switch (this._xPosition) {
1789+
var pos = this.getActualPosition();
1790+
1791+
switch (pos.x) {
17691792
case MdPanelPosition.xPosition.OFFSET_START:
17701793
// TODO(ErinCoughlan): Change OFFSET_START for rtl vs ltr.
17711794
this._left = targetLeft - panelWidth + 'px';
@@ -1792,7 +1815,7 @@ MdPanelPosition.prototype._calculatePanelPosition = function(panelEl) {
17921815
var targetBottom = targetBounds.bottom;
17931816
var targetHeight = targetBounds.height;
17941817

1795-
switch (this._yPosition) {
1818+
switch (pos.y) {
17961819
case MdPanelPosition.yPosition.ABOVE:
17971820
this._top = targetTop - panelHeight + 'px';
17981821
break;

src/components/panel/panel.spec.js

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,8 +1118,7 @@ describe('$mdPanel', function() {
11181118
it('with respect to an element', function() {
11191119
var position = mdPanelPosition
11201120
.relativeTo(myButton[0])
1121-
.withPanelXPosition(xPosition.ALIGN_START)
1122-
.withPanelYPosition(yPosition.ALIGN_TOPS);
1121+
.addPanelPosition(xPosition.ALIGN_START, yPosition.ALIGN_TOPS);
11231122

11241123
config['position'] = position;
11251124

@@ -1133,8 +1132,7 @@ describe('$mdPanel', function() {
11331132
it('with respect to a query selector', function() {
11341133
var position = mdPanelPosition
11351134
.relativeTo('button')
1136-
.withPanelXPosition(xPosition.ALIGN_START)
1137-
.withPanelYPosition(yPosition.ALIGN_TOPS);
1135+
.addPanelPosition(xPosition.ALIGN_START, yPosition.ALIGN_TOPS);
11381136

11391137
config['position'] = position;
11401138

@@ -1148,8 +1146,7 @@ describe('$mdPanel', function() {
11481146
it('with respect to a JQLite object', function() {
11491147
var position = mdPanelPosition
11501148
.relativeTo(myButton)
1151-
.withPanelXPosition(xPosition.ALIGN_START)
1152-
.withPanelYPosition(yPosition.ALIGN_TOPS);
1149+
.addPanelPosition(xPosition.ALIGN_START, yPosition.ALIGN_TOPS);
11531150

11541151
config['position'] = position;
11551152

@@ -1160,11 +1157,31 @@ describe('$mdPanel', function() {
11601157
expect(panelCss.top).toBeApproximately(myButtonRect.top);
11611158
});
11621159

1160+
it('chooses first on-screen position from a list of positions', function() {
1161+
var position = mdPanelPosition
1162+
.relativeTo(myButton)
1163+
.addPanelPosition(xPosition.ALIGN_START, yPosition.ALIGN_TOPS)
1164+
.addPanelPosition(xPosition.ALIGN_END, yPosition.ALIGN_BOTTOMS)
1165+
.addPanelPosition(xPosition.ALIGN_OFFSET_END, yPosition.BELOW);
1166+
1167+
config['position'] = position;
1168+
1169+
openPanel(config);
1170+
1171+
expect(position.getActualPosition()).toEqual({
1172+
x: xPosition.ALIGN_START,
1173+
y: yPosition.ALIGN_TOPS,
1174+
});
1175+
var panelCss = document.querySelector(PANEL_EL).style;
1176+
expect(panelCss.left).toBeApproximately(myButtonRect.left);
1177+
expect(panelCss.top).toBeApproximately(myButtonRect.top);
1178+
});
1179+
11631180
describe('vertically', function() {
11641181
it('above an element', function() {
11651182
var position = mdPanelPosition
11661183
.relativeTo(myButton)
1167-
.withPanelYPosition(yPosition.ABOVE);
1184+
.addPanelPosition(null, yPosition.ABOVE);
11681185

11691186
config['position'] = position;
11701187

@@ -1178,7 +1195,7 @@ describe('$mdPanel', function() {
11781195
it('top aligned with an element', function() {
11791196
var position = mdPanelPosition
11801197
.relativeTo(myButton)
1181-
.withPanelYPosition(yPosition.ALIGN_TOPS);
1198+
.addPanelPosition(null, yPosition.ALIGN_TOPS);
11821199

11831200
config['position'] = position;
11841201

@@ -1192,7 +1209,7 @@ describe('$mdPanel', function() {
11921209
it('centered with an element', function() {
11931210
var position = mdPanelPosition
11941211
.relativeTo(myButton)
1195-
.withPanelYPosition(yPosition.CENTER);
1212+
.addPanelPosition(null, yPosition.CENTER);
11961213

11971214
config['position'] = position;
11981215

@@ -1209,7 +1226,7 @@ describe('$mdPanel', function() {
12091226
it('bottom aligned with an element', function() {
12101227
var position = mdPanelPosition
12111228
.relativeTo(myButton)
1212-
.withPanelYPosition(yPosition.ALIGN_BOTTOMS);
1229+
.addPanelPosition(null, yPosition.ALIGN_BOTTOMS);
12131230

12141231
config['position'] = position;
12151232

@@ -1223,7 +1240,7 @@ describe('$mdPanel', function() {
12231240
it('below an element', function() {
12241241
var position = mdPanelPosition
12251242
.relativeTo(myButton)
1226-
.withPanelYPosition(yPosition.BELOW);
1243+
.addPanelPosition(null, yPosition.BELOW);
12271244

12281245
config['position'] = position;
12291246

@@ -1239,7 +1256,7 @@ describe('$mdPanel', function() {
12391256
it('offset to the left of an element', function() {
12401257
var position = mdPanelPosition
12411258
.relativeTo(myButton)
1242-
.withPanelXPosition(xPosition.OFFSET_START);
1259+
.addPanelPosition(xPosition.OFFSET_START, null);
12431260

12441261
config['position'] = position;
12451262

@@ -1253,7 +1270,7 @@ describe('$mdPanel', function() {
12531270
it('right aligned with an element', function() {
12541271
var position = mdPanelPosition
12551272
.relativeTo(myButton)
1256-
.withPanelXPosition(xPosition.ALIGN_END);
1273+
.addPanelPosition(xPosition.ALIGN_END, null);
12571274

12581275
config['position'] = position;
12591276

@@ -1267,7 +1284,7 @@ describe('$mdPanel', function() {
12671284
it('centered with an element', function() {
12681285
var position = mdPanelPosition
12691286
.relativeTo(myButton)
1270-
.withPanelXPosition(xPosition.CENTER);
1287+
.addPanelPosition(xPosition.CENTER, null);
12711288

12721289
config['position'] = position;
12731290

@@ -1284,7 +1301,7 @@ describe('$mdPanel', function() {
12841301
it('left aligned with an element', function() {
12851302
var position = mdPanelPosition
12861303
.relativeTo(myButton)
1287-
.withPanelXPosition(xPosition.ALIGN_START);
1304+
.addPanelPosition(xPosition.ALIGN_START, null);
12881305

12891306
config['position'] = position;
12901307

@@ -1298,7 +1315,7 @@ describe('$mdPanel', function() {
12981315
it('offset to the right of an element', function() {
12991316
var position = mdPanelPosition
13001317
.relativeTo(myButton)
1301-
.withPanelXPosition(xPosition.OFFSET_END);
1318+
.addPanelPosition(xPosition.OFFSET_END, null);
13021319

13031320
config['position'] = position;
13041321

@@ -1319,7 +1336,7 @@ describe('$mdPanel', function() {
13191336
var expression = function() {
13201337
mdPanelPosition
13211338
.relativeTo(myButton)
1322-
.withPanelXPosition('fake-x-position');
1339+
.addPanelPosition('fake-x-position', null);
13231340
};
13241341

13251342
expect(expression).toThrow();

0 commit comments

Comments
 (0)