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

Commit d423a65

Browse files
committed
fix(datepicker): correctly position datepicker inside dialogs. Fixes
1 parent b19d5cb commit d423a65

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

src/components/datepicker/datePicker.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@
410410
DatePickerCtrl.prototype.isDateEnabled = function(opt_date) {
411411
return this.dateUtil.isDateWithinRange(opt_date, this.minDate, this.maxDate) &&
412412
(!angular.isFunction(this.dateFilter) || this.dateFilter(opt_date));
413-
}
413+
};
414414

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

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

432-
var viewportLeft = document.body.scrollLeft;
433-
var viewportRight = document.body.scrollLeft + this.$window.innerWidth;
437+
var viewportLeft = (bodyRect.left < 0 && document.body.scrollLeft == 0) ?
438+
-bodyRect.left :
439+
document.body.scrollLeft;
440+
441+
var viewportBottom = viewportTop + this.$window.innerHeight;
442+
var viewportRight = viewportLeft + this.$window.innerWidth;
434443

435444
// If the right edge of the pane would be off the screen and shifting it left by the
436445
// difference would not go past the left edge of the screen. If the calendar pane is too

src/components/datepicker/datePicker.spec.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,40 @@ describe('md-date-picker', function() {
338338
document.body.removeChild(element);
339339
});
340340

341+
it('should adjust the pane position if it would go off-screen if body is not scrollable',
342+
function() {
343+
// Make the body super huge and scroll halfway down.
344+
var body = document.body;
345+
var superLongElement = document.createElement('div');
346+
superLongElement.style.height = '10000px';
347+
superLongElement.style.width = '1px';
348+
body.appendChild(superLongElement);
349+
body.scrollTop = 700;
350+
351+
// Absolutely position the picker near (say ~30px) the edge of the viewport.
352+
element.style.position = 'absolute';
353+
element.style.top = (document.body.scrollTop + window.innerHeight - 30) + 'px';
354+
element.style.left = '0';
355+
body.appendChild(element);
356+
357+
// Make the body non-scrollable.
358+
var previousBodyOverflow = body.style.overflow;
359+
body.style.overflow = 'hidden';
360+
361+
// Open the pane.
362+
element.querySelector('md-button').click();
363+
$timeout.flush();
364+
365+
// Expect that the pane is on-screen.
366+
var paneRect = controller.calendarPane.getBoundingClientRect();
367+
expect(paneRect.bottom).toBeLessThan(window.innerHeight + 1);
368+
body.removeChild(superLongElement);
369+
370+
// Restore body to pre-test state.
371+
body.removeChild(element);
372+
body.style.overflow = previousBodyOverflow;
373+
});
374+
341375
it('should shink the calendar pane when it would otherwise not fit on the screen', function() {
342376
// Fake the window being very narrow so that the calendar pane won't fit on-screen.
343377
controller.$window = {innerWidth: 200, innherHeight: 800};

0 commit comments

Comments
 (0)