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

Commit a899c5b

Browse files
jelbournThomasBurleson
authored andcommitted
fix(datepicker): prevent calendar pane being in wrong position after body scrolling is disabled.
Fixes #5201. Closes #5918.
1 parent a81deea commit a899c5b

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

src/components/datepicker/datePicker.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,6 @@
502502
if (!this.isCalendarOpen && !this.isDisabled) {
503503
this.isCalendarOpen = true;
504504
this.calendarPaneOpenedFrom = event.target;
505-
this.attachCalendarPane();
506-
this.focusCalendar();
507505

508506
// Because the calendar pane is attached directly to the body, it is possible that the
509507
// rest of the component (input, etc) is in a different scrolling container, such as
@@ -512,11 +510,14 @@
512510
// also matches the native behavior for things like `<select>` on Mac and Windows.
513511
this.$mdUtil.disableScrollAround(this.calendarPane);
514512

513+
this.attachCalendarPane();
514+
this.focusCalendar();
515+
515516
// Attach click listener inside of a timeout because, if this open call was triggered by a
516517
// click, we don't want it to be immediately propogated up to the body and handled.
517518
var self = this;
518519
this.$mdUtil.nextTick(function() {
519-
document.body.addEventListener('click', self.bodyClickHandler);
520+
document.documentElement.addEventListener('click', self.bodyClickHandler);
520521
}, false);
521522

522523
window.addEventListener('resize', this.windowResizeHandler);
@@ -532,7 +533,7 @@
532533
this.calendarPaneOpenedFrom = null;
533534
this.$mdUtil.enableScrolling();
534535

535-
document.body.removeEventListener('click', this.bodyClickHandler);
536+
document.documentElement.removeEventListener('click', this.bodyClickHandler);
536537
window.removeEventListener('resize', this.windowResizeHandler);
537538
}
538539
};

src/components/datepicker/datePicker.spec.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,14 @@ describe('md-date-picker', function() {
333333
// Expect that the pane is on-screen.
334334
var paneRect = controller.calendarPane.getBoundingClientRect();
335335
expect(paneRect.bottom).toBeLessThan(window.innerHeight + 1);
336-
document.body.removeChild(superLongElement);
337336

338337
document.body.removeChild(element);
338+
document.body.removeChild(superLongElement);
339339
});
340340

341341
it('should adjust the pane position if it would go off-screen if body is not scrollable',
342342
function() {
343-
// Make the body super huge and scroll halfway down.
343+
// Make the body super huge and scroll down a bunch.
344344
var body = document.body;
345345
var superLongElement = document.createElement('div');
346346
superLongElement.style.height = '10000px';
@@ -365,13 +365,43 @@ describe('md-date-picker', function() {
365365
// Expect that the pane is on-screen.
366366
var paneRect = controller.calendarPane.getBoundingClientRect();
367367
expect(paneRect.bottom).toBeLessThan(window.innerHeight + 1);
368-
body.removeChild(superLongElement);
369368

370369
// Restore body to pre-test state.
371370
body.removeChild(element);
371+
body.removeChild(superLongElement);
372372
body.style.overflow = previousBodyOverflow;
373373
});
374374

375+
it('should keep the calendar pane in the right place with body scrolling disabled', function() {
376+
// Make the body super huge and scroll down a bunch.
377+
var body = document.body;
378+
var superLongElement = document.createElement('div');
379+
superLongElement.style.height = '10000px';
380+
superLongElement.style.width = '1px';
381+
body.appendChild(superLongElement);
382+
body.scrollTop = 700;
383+
384+
// Absolutely position the picker such that the pane position doesn't need to be adjusted.
385+
// (1/10 of the way down the screen).
386+
element.style.position = 'absolute';
387+
element.style.top = (document.body.scrollTop + (window.innerHeight * 0.10)) + 'px';
388+
element.style.left = '0';
389+
body.appendChild(element);
390+
391+
// Open the pane.
392+
element.querySelector('md-button').click();
393+
$timeout.flush();
394+
395+
// Expect that the calendar pane is in the same position as the inline datepicker.
396+
var paneRect = controller.calendarPane.getBoundingClientRect();
397+
var triggerRect = controller.inputContainer.getBoundingClientRect();
398+
expect(paneRect.top).toBe(triggerRect.top);
399+
400+
// Restore body to pre-test state.
401+
body.removeChild(superLongElement);
402+
body.removeChild(element);
403+
});
404+
375405
it('should shink the calendar pane when it would otherwise not fit on the screen', function() {
376406
// Fake the window being very narrow so that the calendar pane won't fit on-screen.
377407
controller.$window = {innerWidth: 200, innherHeight: 800};

0 commit comments

Comments
 (0)