in src/components/datepicker/js/datepickerDirective.js [765:846]
DatePickerCtrl.prototype.attachCalendarPane = function() {
var calendarPane = this.calendarPane;
var body = document.body;
calendarPane.style.transform = '';
this.$element.addClass(OPEN_CLASS);
this.mdInputContainer && this.mdInputContainer.element.addClass(OPEN_CLASS);
angular.element(body).addClass('md-datepicker-is-showing');
var elementRect = this.inputContainer.getBoundingClientRect();
var bodyRect = body.getBoundingClientRect();
if (!this.topMargin || this.topMargin < 0) {
this.topMargin =
(this.inputMask.parent().prop('clientHeight')
- this.ngInputElement.prop('clientHeight')) / 2;
}
// Check to see if the calendar pane would go off the screen. If so, adjust position
// accordingly to keep it within the viewport.
var paneTop = elementRect.top - bodyRect.top - this.topMargin;
var paneLeft = elementRect.left - bodyRect.left - this.leftMargin;
// 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 = (bodyRect.left < 0 && document.body.scrollLeft === 0) ?
-bodyRect.left :
document.body.scrollLeft;
var viewportBottom = viewportTop + this.$window.innerHeight;
var viewportRight = viewportLeft + this.$window.innerWidth;
// Creates an overlay with a hole the same size as element. We remove a pixel or two
// on each end to make it overlap slightly. The overlay's background is added in
// the theme in the form of a box-shadow with a huge spread.
this.inputMask.css({
position: 'absolute',
left: this.leftMargin + 'px',
top: this.topMargin + 'px',
width: (elementRect.width - 1) + 'px',
height: (elementRect.height - 2) + 'px'
});
// 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
// big to fit on the screen at all, move it to the left of the screen and scale the entire
// element down to fit.
if (paneLeft + CALENDAR_PANE_WIDTH > viewportRight) {
if (viewportRight - CALENDAR_PANE_WIDTH > 0) {
paneLeft = viewportRight - CALENDAR_PANE_WIDTH;
} else {
paneLeft = viewportLeft;
var scale = this.$window.innerWidth / CALENDAR_PANE_WIDTH;
calendarPane.style.transform = 'scale(' + scale + ')';
}
calendarPane.classList.add('md-datepicker-pos-adjusted');
}
// If the bottom edge of the pane would be off the screen and shifting it up by the
// difference would not go past the top edge of the screen.
if (paneTop + CALENDAR_PANE_HEIGHT > viewportBottom &&
viewportBottom - CALENDAR_PANE_HEIGHT > viewportTop) {
paneTop = viewportBottom - CALENDAR_PANE_HEIGHT;
calendarPane.classList.add('md-datepicker-pos-adjusted');
}
calendarPane.style.left = paneLeft + 'px';
calendarPane.style.top = paneTop + 'px';
document.body.appendChild(calendarPane);
// Add CSS class after one frame to trigger open animation.
this.$$rAF(function() {
calendarPane.classList.add('md-pane-open');
});
};