|
99 | 99 | /** Default time in ms to debounce input event by. */
|
100 | 100 | var DEFAULT_DEBOUNCE_INTERVAL = 500;
|
101 | 101 |
|
| 102 | + /** |
| 103 | + * Height of the calendar pane used to check if the pane is going outside the boundary of |
| 104 | + * the viewport. See calendar.scss for how $md-calendar-height is computed; an extra 20px is |
| 105 | + * also added to space the pane away from the exact edge of the screen. |
| 106 | + * |
| 107 | + * This is computed statically now, but can be changed to be measured if the circumstances |
| 108 | + * of calendar sizing are changed. |
| 109 | + */ |
| 110 | + var CALENDAR_PANE_HEIGHT = 368; |
| 111 | + |
| 112 | + /** |
| 113 | + * Width of the calendar pane used to check if the pane is going outside the boundary of |
| 114 | + * the viewport. See calendar.scss for how $md-calendar-width is computed; an extra 20px is |
| 115 | + * also added to space the pane away from the exact edge of the screen. |
| 116 | + * |
| 117 | + * This is computed statically now, but can be changed to be measured if the circumstances |
| 118 | + * of calendar sizing are changed. |
| 119 | + */ |
| 120 | + var CALENDAR_PANE_WIDTH = 360; |
| 121 | + |
102 | 122 | /**
|
103 | 123 | * Controller for md-datepicker.
|
104 | 124 | *
|
|
187 | 207 | /** Pre-bound click handler is saved so that the event listener can be removed. */
|
188 | 208 | this.bodyClickHandler = angular.bind(this, this.handleBodyClick);
|
189 | 209 |
|
| 210 | + /** Pre-bound resize handler so that the event listener can be removed. */ |
| 211 | + this.windowResizeHandler = $mdUtil.debounce(angular.bind(this, this.closeCalendarPane), 100); |
| 212 | + |
190 | 213 | // Unless the user specifies so, the datepicker should not be a tab stop.
|
191 | 214 | // This is necessary because ngAria might add a tabindex to anything with an ng-model
|
192 | 215 | // (based on whether or not the user has turned that particular feature on/off).
|
|
328 | 351 | var elementRect = this.inputContainer.getBoundingClientRect();
|
329 | 352 | var bodyRect = document.body.getBoundingClientRect();
|
330 | 353 |
|
331 |
| - calendarPane.style.left = (elementRect.left - bodyRect.left) + 'px'; |
332 |
| - calendarPane.style.top = (elementRect.top - bodyRect.top) + 'px'; |
| 354 | + // Check to see if the calendar pane would go off the screen. If so, adjust position |
| 355 | + // accordingly to keep it within the viewport. |
| 356 | + var paneTop = elementRect.top - bodyRect.top; |
| 357 | + var paneLeft = elementRect.left - bodyRect.left; |
| 358 | + |
| 359 | + // If the right edge of the pane would be off the screen and shifting it left by the |
| 360 | + // difference would not go past the left edge of the screen. |
| 361 | + if (paneLeft + CALENDAR_PANE_WIDTH > bodyRect.right && |
| 362 | + bodyRect.right - CALENDAR_PANE_WIDTH > 0) { |
| 363 | + paneLeft = bodyRect.right - CALENDAR_PANE_WIDTH; |
| 364 | + calendarPane.classList.add('md-datepicker-pos-adjusted'); |
| 365 | + } |
| 366 | + |
| 367 | + // If the bottom edge of the pane would be off the screen and shifting it up by the |
| 368 | + // difference would not go past the top edge of the screen. |
| 369 | + if (paneTop + CALENDAR_PANE_HEIGHT > bodyRect.bottom && |
| 370 | + bodyRect.bottom - CALENDAR_PANE_HEIGHT > 0) { |
| 371 | + paneTop = bodyRect.bottom - CALENDAR_PANE_HEIGHT; |
| 372 | + calendarPane.classList.add('md-datepicker-pos-adjusted'); |
| 373 | + } |
| 374 | + |
| 375 | + calendarPane.style.left = paneLeft + 'px'; |
| 376 | + calendarPane.style.top = paneTop + 'px'; |
333 | 377 | document.body.appendChild(this.calendarPane);
|
334 | 378 |
|
335 | 379 | // The top of the calendar pane is a transparent box that shows the text input underneath.
|
336 |
| - // Since the pane is flowing, though, the page underneath the pane *adjacent* to the input is |
| 380 | + // Since the pane is floating, though, the page underneath the pane *adjacent* to the input is |
337 | 381 | // also shown unless we cover it up. The inputMask does this by filling up the remaining space
|
338 | 382 | // based on the width of the input.
|
339 | 383 | this.inputMask.style.left = elementRect.width + 'px';
|
|
344 | 388 | });
|
345 | 389 | };
|
346 | 390 |
|
| 391 | + DatePickerCtrl.prototype.positionCalendarPane = function() { |
| 392 | + |
| 393 | + }; |
| 394 | + |
347 | 395 | /** Detach the floating calendar pane from the document. */
|
348 | 396 | DatePickerCtrl.prototype.detachCalendarPane = function() {
|
349 | 397 | this.$element.removeClass('md-datepicker-open');
|
350 | 398 | this.calendarPane.classList.remove('md-pane-open');
|
| 399 | + this.calendarPane.classList.remove('md-datepicker-pos-adjusted'); |
351 | 400 |
|
352 | 401 | if (this.calendarPane.parentNode) {
|
353 | 402 | // Use native DOM removal because we do not want any of the angular state of this element
|
|
380 | 429 | this.$mdUtil.nextTick(function() {
|
381 | 430 | document.body.addEventListener('click', self.bodyClickHandler);
|
382 | 431 | }, false);
|
| 432 | + |
| 433 | + window.addEventListener('resize', this.windowResizeHandler); |
383 | 434 | }
|
384 | 435 | };
|
385 | 436 |
|
|
392 | 443 | this.$mdUtil.enableScrolling();
|
393 | 444 |
|
394 | 445 | document.body.removeEventListener('click', this.bodyClickHandler);
|
| 446 | + window.removeEventListener('resize', this.windowResizeHandler); |
395 | 447 | };
|
396 | 448 |
|
397 | 449 | /** Gets the controller instance for the calendar in the floating pane. */
|
|
0 commit comments