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

Commit

Permalink
fix(datepicker): correctly position datepicker inside dialogs. Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jelbourn committed Nov 25, 2015
1 parent b19d5cb commit d423a65
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 5 deletions.
19 changes: 14 additions & 5 deletions src/components/datepicker/datePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@
DatePickerCtrl.prototype.isDateEnabled = function(opt_date) {
return this.dateUtil.isDateWithinRange(opt_date, this.minDate, this.maxDate) &&
(!angular.isFunction(this.dateFilter) || this.dateFilter(opt_date));
}
};

/** Position and attach the floating calendar to the document. */
DatePickerCtrl.prototype.attachCalendarPane = function() {
Expand All @@ -426,11 +426,20 @@
var paneTop = elementRect.top - bodyRect.top;
var paneLeft = elementRect.left - bodyRect.left;

var viewportTop = document.body.scrollTop;
var viewportBottom = viewportTop + this.$window.innerHeight;
// If ng-material has disabled body scrolling (for example, if a dialog is open),
// then it's possible that the already-scrolled body has a negative top/left. In this case,
// we want to treat the "real" top as (0 - bodyRect.top). In a normal scrolling situation,
// though, the top of the viewport should just be the body's scroll position.
var viewportTop = (bodyRect.top < 0 && document.body.scrollTop == 0) ?
-bodyRect.top :
document.body.scrollTop;

var viewportLeft = document.body.scrollLeft;
var viewportRight = document.body.scrollLeft + this.$window.innerWidth;
var viewportLeft = (bodyRect.left < 0 && document.body.scrollLeft == 0) ?
-bodyRect.left :
document.body.scrollLeft;

var viewportBottom = viewportTop + this.$window.innerHeight;
var viewportRight = viewportLeft + this.$window.innerWidth;

// If the right edge of the pane would be off the screen and shifting it left by the
// difference would not go past the left edge of the screen. If the calendar pane is too
Expand Down
34 changes: 34 additions & 0 deletions src/components/datepicker/datePicker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,40 @@ describe('md-date-picker', function() {
document.body.removeChild(element);
});

it('should adjust the pane position if it would go off-screen if body is not scrollable',
function() {
// Make the body super huge and scroll halfway down.
var body = document.body;
var superLongElement = document.createElement('div');
superLongElement.style.height = '10000px';
superLongElement.style.width = '1px';
body.appendChild(superLongElement);
body.scrollTop = 700;

// Absolutely position the picker near (say ~30px) the edge of the viewport.
element.style.position = 'absolute';
element.style.top = (document.body.scrollTop + window.innerHeight - 30) + 'px';
element.style.left = '0';
body.appendChild(element);

// Make the body non-scrollable.
var previousBodyOverflow = body.style.overflow;
body.style.overflow = 'hidden';

// Open the pane.
element.querySelector('md-button').click();
$timeout.flush();

// Expect that the pane is on-screen.
var paneRect = controller.calendarPane.getBoundingClientRect();
expect(paneRect.bottom).toBeLessThan(window.innerHeight + 1);
body.removeChild(superLongElement);

// Restore body to pre-test state.
body.removeChild(element);
body.style.overflow = previousBodyOverflow;
});

it('should shink the calendar pane when it would otherwise not fit on the screen', function() {
// Fake the window being very narrow so that the calendar pane won't fit on-screen.
controller.$window = {innerWidth: 200, innherHeight: 800};
Expand Down

0 comments on commit d423a65

Please sign in to comment.