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

Commit

Permalink
feat(panel): Update the panel position on scroll.
Browse files Browse the repository at this point in the history
  • Loading branch information
ErinCoughlan committed May 10, 2016
1 parent 0d2e489 commit 18aa360
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 43 deletions.
3 changes: 2 additions & 1 deletion src/components/panel/demoBasicUsage/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ BasicDemoCtrl.prototype.showMenu = function(ev) {
openFrom: ev,
clickOutsideToClose: true,
escapeToClose: true,
focusOnOpen: false
focusOnOpen: false,
zIndex: 2
};

this._mdPanel.open(config);
Expand Down
73 changes: 57 additions & 16 deletions src/components/panel/panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,12 @@ function MdPanelRef(config, $injector) {
/** @private @const {!angular.$log} */
this._$log = $injector.get('$log');

/** @private @const {!angular.$window} */
this._$window = $injector.get('$window');

/** @private @const {!Function} */
this._$$rAF = $injector.get('$$rAF');

// Public variables.
/**
* Unique id for the panelRef.
Expand Down Expand Up @@ -1148,22 +1154,32 @@ MdPanelRef.prototype._addStyles = function() {
// correctly. This is necessary so that the panel will have a defined height
// and width.
self._$rootScope['$$postDigest'](function() {
positionConfig._calculatePanelPosition(self._panelEl);
self._panelEl.css('top', positionConfig.getTop());
self._panelEl.css('bottom', positionConfig.getBottom());
self._panelEl.css('left', positionConfig.getLeft());
self._panelEl.css('right', positionConfig.getRight());

// Use the vendor prefixed version of transform.
var prefixedTransform = self._$mdConstant.CSS.TRANSFORM;
self._panelEl.css(prefixedTransform, positionConfig.getTransform());

self._updatePosition();
resolve(self);
});
});
};


/**
* Calculates and updates the position of the panel.
* @private
*/
MdPanelRef.prototype._updatePosition = function() {
var positionConfig = this._config['position'];

positionConfig._calculatePanelPosition(this._panelEl);
this._panelEl.css('top', positionConfig.getTop());
this._panelEl.css('bottom', positionConfig.getBottom());
this._panelEl.css('left', positionConfig.getLeft());
this._panelEl.css('right', positionConfig.getRight());

// Use the vendor prefixed version of transform.
var prefixedTransform = this._$mdConstant.CSS.TRANSFORM;
this._panelEl.css(prefixedTransform, positionConfig.getTransform());
};


/**
* Focuses on the panel or the first focus target.
* @private
Expand Down Expand Up @@ -1221,6 +1237,7 @@ MdPanelRef.prototype._createBackdrop = function() {
MdPanelRef.prototype._addEventListeners = function() {
this._configureEscapeToClose();
this._configureClickOutsideToClose();
this._configureScrollListener();
};


Expand Down Expand Up @@ -1310,6 +1327,31 @@ MdPanelRef.prototype._configureClickOutsideToClose = function() {
};


/**
* Configures the listeners for updating the panel position on scroll.
* @private
*/
MdPanelRef.prototype._configureScrollListener = function() {
var updatePosition = angular.bind(this, this._updatePosition);
var debouncedUpdatePosition = this._$$rAF.throttle(updatePosition);
var self = this;

var onScroll = function() {
if (!self._config['disableParentScroll']) {
debouncedUpdatePosition();
}
};

// Add listeners.
this._$window.addEventListener('scroll', onScroll, true);

// Queue remove listeners function.
this._removeListeners.push(function() {
self._$window.removeEventListener('scroll', onScroll, true);
});
};


/**
* Setup the focus traps. These traps will wrap focus when tabbing past the
* panel. When shift-tabbing, the focus will stick in place.
Expand Down Expand Up @@ -1460,8 +1502,8 @@ function MdPanelPosition() {
/** @private {boolean} */
this._absolute = false;

/** @private {!DOMRect} */
this._relativeToRect;
/** @private {!angular.JQLite} */
this._relativeToEl;

/** @private {string} */
this._top = '';
Expand Down Expand Up @@ -1619,7 +1661,7 @@ MdPanelPosition.prototype.center = function() {
*/
MdPanelPosition.prototype.relativeTo = function(element) {
this._absolute = false;
this._relativeToRect = getElement(element)[0].getBoundingClientRect();
this._relativeToEl = getElement(element);
return this;
};

Expand All @@ -1631,7 +1673,7 @@ MdPanelPosition.prototype.relativeTo = function(element) {
* @returns {MdPanelPosition}
*/
MdPanelPosition.prototype.addPanelPosition = function(xPosition, yPosition) {
if (!this._relativeToRect) {
if (!this._relativeToEl) {
throw new Error('addPanelPosition can only be used with relative ' +
'positioning. Set relativeTo first.');
}
Expand Down Expand Up @@ -1810,14 +1852,13 @@ MdPanelPosition.prototype._calculatePanelPosition = function(panelEl) {
return;
}

// TODO(ErinCoughlan): Update position on scroll.
// TODO(ErinCoughlan): Position panel intelligently to keep it on screen.

var panelBounds = panelEl[0].getBoundingClientRect();
var panelWidth = panelBounds.width;
var panelHeight = panelBounds.height;

var targetBounds = this._relativeToRect;
var targetBounds = this._relativeToEl[0].getBoundingClientRect();

var targetLeft = targetBounds.left;
var targetRight = targetBounds.right;
Expand Down
46 changes: 20 additions & 26 deletions src/components/panel/panel.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
describe('$mdPanel', function() {
var $mdPanel, $rootScope, $rootEl, $templateCache, $q, $material, $mdConstant,
$mdUtil, $animate;
$mdUtil, $animate, $$rAF, $window;
var panelRef;
var attachedElements = [];
var PANEL_WRAPPER_CLASS = '.md-panel-outer-wrapper';
Expand Down Expand Up @@ -28,6 +28,8 @@ describe('$mdPanel', function() {
$mdConstant = $injector.get('$mdConstant');
$mdUtil = $injector.get('$mdUtil');
$animate = $injector.get('$animate');
$window = $injector.get('$window');
$$rAF = $injector.get('$$rAF');
};

beforeEach(function() {
Expand Down Expand Up @@ -1426,7 +1428,7 @@ describe('$mdPanel', function() {
.relativeTo(myButton)
.addPanelPosition(xPosition.ALIGN_START, yPosition.ALIGN_TOPS)
.addPanelPosition(xPosition.ALIGN_END, yPosition.ALIGN_BOTTOMS)
.addPanelPosition(xPosition.ALIGN_OFFSET_END, yPosition.BELOW);
.addPanelPosition(xPosition.OFFSET_END, yPosition.BELOW);

config['position'] = position;

Expand Down Expand Up @@ -1590,34 +1592,26 @@ describe('$mdPanel', function() {
expect(panelRect.left).toBeApproximately(myButtonRect.right);
});
});
});

it('should throw if xPosition is not valid', function() {
var myButton = '<button>myButton</button>';
attachToBody(myButton);
myButton = angular.element(document.querySelector('button'));

var expression = function() {
mdPanelPosition
.relativeTo(myButton)
.addPanelPosition('fake-x-position', null);
};

expect(expression).toThrow();
});
it('should throw if xPosition is not valid', function() {
var expression = function() {
mdPanelPosition
.relativeTo(myButton)
.addPanelPosition('fake-x-position', null);
};

it('should throw if yPosition is not valid', function() {
var myButton = '<button>myButton</button>';
attachToBody(myButton);
myButton = angular.element(document.querySelector('button'));
expect(expression).toThrow();
});

var expression = function() {
mdPanelPosition
.relativeTo(myButton)
.withPanelYPosition('fake-y-position');
};
it('should throw if yPosition is not valid', function() {
var expression = function() {
mdPanelPosition
.relativeTo(myButton)
.addPanelPosition(null, 'fake-y-position');
};

expect(expression).toThrow();
expect(expression).toThrow();
});
});
});

Expand Down

0 comments on commit 18aa360

Please sign in to comment.