|
11 | 11 | 'material.core', 'material.components.icon'
|
12 | 12 | ]).directive('mdCalendar', calendarDirective);
|
13 | 13 |
|
14 |
| - // FUTURE VERSION |
15 |
| - // TODO(jelbourn): Animated month transition on ng-model change. |
16 |
| - // TODO(jelbourn): Scroll snapping |
17 |
| - // TODO(jelbourn): Month headers stick to top when scrolling |
18 |
| - // TODO(jelbourn): Previous month opacity is lowered when partially scrolled out of view. |
19 |
| - // TODO(jelbourn): Support md-calendar standalone on a page (as a tabstop w/ aria-live |
20 |
| - // announcement and key handling). |
21 |
| - |
22 | 14 |
|
23 | 15 | // PRE RELEASE
|
24 | 16 | // TODO(jelbourn): Base colors on the theme
|
25 |
| - // TODO(jelbourn): Align style with spec |
26 | 17 | // TODO(jelbourn): read-only state.
|
27 | 18 | // TODO(jelbourn): Make sure the *time* on the written date makes sense (probably midnight).
|
28 | 19 | // TODO(jelbourn): Date "isComplete" logic
|
29 | 20 | // TODO(jelbourn): Apple + up / down == PgDown and PgUp
|
30 | 21 | // TODO(jelbourn): Documentation
|
31 | 22 | // TODO(jelbourn): Demo that uses moment.js
|
| 23 | + // TODO(jelbourn): Fix NVDA stealing key presses (IE) ??? |
| 24 | + |
| 25 | + // FUTURE VERSION |
| 26 | + // TODO(jelbourn): Animated month transition on ng-model change. |
| 27 | + // TODO(jelbourn): Scroll snapping |
| 28 | + // TODO(jelbourn): Month headers stick to top when scrolling |
| 29 | + // TODO(jelbourn): Previous month opacity is lowered when partially scrolled out of view. |
| 30 | + // TODO(jelbourn): Support md-calendar standalone on a page (as a tabstop w/ aria-live |
| 31 | + // announcement and key handling). |
32 | 32 |
|
33 | 33 | // COULD GO EITHER WAY
|
34 | 34 | // TODO(jelbourn): Clicking on the month label opens the month-picker.
|
|
47 | 47 | '<table class="md-calendar-day-header"><thead></thead></table>' +
|
48 | 48 | '<div class="md-calendar-scroll-mask">' +
|
49 | 49 | '<md-virtual-repeat-container class="md-calendar-scroller">' +
|
50 |
| - '<table class="md-calendar">' + |
51 |
| - '<tbody md-virtual-repeat="i in ctrl.items" md-calendar-month ' + |
| 50 | + '<table role="grid" class="md-calendar">' + |
| 51 | + '<tbody role="rowgroup" md-virtual-repeat="i in ctrl.items" md-calendar-month ' + |
52 | 52 | 'md-month-offset="$index" class="md-calendar-month" aria-hidden="true" ' +
|
53 |
| - 'md-start-index="1000" ' + |
| 53 | + 'md-start-index="ctrl.getSelectedMonthIndex()" ' + |
54 | 54 | 'md-item-size="' + TBODY_HEIGHT + '"></tbody>' +
|
55 | 55 | '</table>' +
|
56 | 56 | '</md-virtual-repeat-container>' +
|
|
87 | 87 | $$mdDateUtil, $$mdDateLocale, $mdInkRipple, $mdUtil) {
|
88 | 88 |
|
89 | 89 | /** @type {Array<number>} Dummy array-like object for virtual-repeat to iterate over. */
|
90 |
| - this.items = {length: 2000}; |
| 90 | + this.items = {length: 2000 * 12}; |
91 | 91 |
|
92 | 92 | /** @final {!angular.$animate} */
|
93 | 93 | this.$animate = $animate;
|
|
156 | 156 | */
|
157 | 157 | this.displayDate = null;
|
158 | 158 |
|
| 159 | + /** |
| 160 | + * The date that has or should have browser focus. |
| 161 | + * @type {Date} |
| 162 | + */ |
| 163 | + this.focusDate = null; |
| 164 | + |
159 | 165 | /** @type {boolean} */
|
160 | 166 | this.isInitialized = false;
|
161 | 167 |
|
|
184 | 190 | }
|
185 | 191 | };
|
186 | 192 |
|
187 |
| - // Do a one-time scroll to the selected date once the months have done their initial render. |
188 |
| - var off = $scope.$on('md-calendar-month-initial-render', function() { |
189 |
| - //self.scrollToMonth(self.selectedDate); |
190 |
| - off(); |
191 |
| - }); |
192 |
| - |
193 | 193 | this.attachCalendarEventListeners();
|
194 | 194 |
|
195 | 195 | // DEBUG
|
|
224 | 224 | this.isInitialized = true;
|
225 | 225 | };
|
226 | 226 |
|
| 227 | + /** |
| 228 | + * Gets the "index" of the currently selected date as it would be in the virtual-repeat. |
| 229 | + * @returns {number} |
| 230 | + */ |
| 231 | + CalendarCtrl.prototype.getSelectedMonthIndex = function() { |
| 232 | + return this.dateUtil.getMonthDistance(firstRenderableDate, this.selectedDate || this.today); |
| 233 | + }; |
| 234 | + |
227 | 235 | /**
|
228 | 236 | * Hides the vertical scrollbar on the calendar scroller by setting the width on the
|
229 | 237 | * calendar scroller and the `overflow: hidden` wrapper around the scroller, and then setting
|
|
263 | 271 | */
|
264 | 272 | CalendarCtrl.prototype.attachCalendarEventListeners = function() {
|
265 | 273 | // Keyboard interaction.
|
266 |
| - angular.element(this.calendarElement).on('keydown', this.handleKeyEvent.bind(this)); |
| 274 | + this.$element.on('keydown', this.handleKeyEvent.bind(this)); |
267 | 275 | };
|
268 | 276 |
|
269 | 277 | /*** User input handling ***/
|
|
293 | 301 |
|
294 | 302 | // Selection isn't occuring, so the key event is either navigation or nothing.
|
295 | 303 | var date = self.getFocusDateFromKeyEvent(event);
|
296 |
| - |
297 |
| - // Prevent the default on the key event only if it triggered a date navigation. |
298 |
| - if (!self.dateUtil.isSameDay(date, self.displayDate)) { |
299 |
| - event.preventDefault(); |
300 |
| - } |
| 304 | + event.preventDefault(); |
301 | 305 |
|
302 | 306 | // Since this is a keyboard interaction, actually give the newly focused date keyboard
|
303 | 307 | // focus after the been brought into view.
|
|
344 | 348 | * @param {Date=} opt_date
|
345 | 349 | */
|
346 | 350 | CalendarCtrl.prototype.focus = function(opt_date) {
|
347 |
| - var cellId = this.getDateId(opt_date || this.selectedDate); |
| 351 | + var date = opt_date || this.selectedDate; |
| 352 | + var cellId = this.getDateId(date); |
348 | 353 | var cell = this.calendarElement.querySelector('#' + cellId);
|
349 | 354 | if (cell) {
|
350 | 355 | cell.focus();
|
| 356 | + } else { |
| 357 | + this.focusDate = date; |
351 | 358 | }
|
352 | 359 | };
|
353 | 360 |
|
|
0 commit comments