-
Notifications
You must be signed in to change notification settings - Fork 6.7k
/
year-view.ts
154 lines (132 loc) · 5 KB
/
year-view.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {
AfterContentInit,
ChangeDetectionStrategy,
Component,
EventEmitter,
Inject,
Input,
Optional,
Output,
ViewEncapsulation
} from '@angular/core';
import {MdCalendarCell} from './calendar-body';
import {DateAdapter} from '../core/datetime/index';
import {createMissingDateImplError} from './datepicker-errors';
import {MD_DATE_FORMATS, MdDateFormats} from '../core/datetime/date-formats';
/**
* An internal component used to display a single year in the datepicker.
* @docs-private
*/
@Component({
moduleId: module.id,
selector: 'md-year-view',
templateUrl: 'year-view.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MdYearView<D> implements AfterContentInit {
/** The date to display in this year view (everything other than the year is ignored). */
@Input()
get activeDate(): D { return this._activeDate; }
set activeDate(value: D) {
let oldActiveDate = this._activeDate;
this._activeDate = value || this._dateAdapter.today();
if (this._dateAdapter.getYear(oldActiveDate) != this._dateAdapter.getYear(this._activeDate)) {
this._init();
}
}
private _activeDate: D;
/** The currently selected date. */
@Input()
get selected(): D { return this._selected; }
set selected(value: D) {
this._selected = value;
this._selectedMonth = this._getMonthInCurrentYear(this.selected);
}
private _selected: D;
/** A function used to filter which dates are selectable. */
@Input() dateFilter: (date: D) => boolean;
/** Emits when a new month is selected. */
@Output() selectedChange = new EventEmitter<D>();
/** Grid of calendar cells representing the months of the year. */
_months: MdCalendarCell[][];
/** The label for this year (e.g. "2017"). */
_yearLabel: string;
/** The month in this year that today falls on. Null if today is in a different year. */
_todayMonth: number | null;
/**
* The month in this year that the selected Date falls on.
* Null if the selected Date is in a different year.
*/
_selectedMonth: number | null;
constructor(@Optional() public _dateAdapter: DateAdapter<D>,
@Optional() @Inject(MD_DATE_FORMATS) private _dateFormats: MdDateFormats) {
if (!this._dateAdapter) {
throw createMissingDateImplError('DateAdapter');
}
if (!this._dateFormats) {
throw createMissingDateImplError('MD_DATE_FORMATS');
}
this._activeDate = this._dateAdapter.today();
}
ngAfterContentInit() {
this._init();
}
/** Handles when a new month is selected. */
_monthSelected(month: number) {
let daysInMonth = this._dateAdapter.getNumDaysInMonth(
this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), month, 1));
this.selectedChange.emit(this._dateAdapter.createDate(
this._dateAdapter.getYear(this.activeDate), month,
Math.min(this._dateAdapter.getDate(this.activeDate), daysInMonth)));
}
/** Initializes this month view. */
private _init() {
this._selectedMonth = this._getMonthInCurrentYear(this.selected);
this._todayMonth = this._getMonthInCurrentYear(this._dateAdapter.today());
this._yearLabel = this._dateAdapter.getYearName(this.activeDate);
let monthNames = this._dateAdapter.getMonthNames('short');
// First row of months only contains 5 elements so we can fit the year label on the same row.
this._months = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]].map(row => row.map(
month => this._createCellForMonth(month, monthNames[month])));
}
/**
* Gets the month in this year that the given Date falls on.
* Returns null if the given Date is in another year.
*/
private _getMonthInCurrentYear(date: D) {
return date && this._dateAdapter.getYear(date) == this._dateAdapter.getYear(this.activeDate) ?
this._dateAdapter.getMonth(date) : null;
}
/** Creates an MdCalendarCell for the given month. */
private _createCellForMonth(month: number, monthName: string) {
let ariaLabel = this._dateAdapter.format(
this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), month, 1),
this._dateFormats.display.monthYearA11yLabel);
return new MdCalendarCell(
month, monthName.toLocaleUpperCase(), ariaLabel, this._isMonthEnabled(month));
}
/** Whether the given month is enabled. */
private _isMonthEnabled(month: number) {
if (!this.dateFilter) {
return true;
}
let firstOfMonth = this._dateAdapter.createDate(
this._dateAdapter.getYear(this.activeDate), month, 1);
// If any date in the month is enabled count the month as enabled.
for (let date = firstOfMonth; this._dateAdapter.getMonth(date) == month;
date = this._dateAdapter.addCalendarDays(date, 1)) {
if (this.dateFilter(date)) {
return true;
}
}
return false;
}
}