6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
9
+ import { FactoryProvider , Injectable , OnDestroy , Optional , SkipSelf } from '@angular/core' ;
9
10
import { DateAdapter } from '@angular/material/core' ;
10
- import { FactoryProvider , Optional , SkipSelf , Injectable } from '@angular/core' ;
11
- import { Subject , Observable } from 'rxjs' ;
11
+ import { Observable , Subject } from 'rxjs' ;
12
12
13
- export abstract class MatDateSelectionModel < D > {
14
- protected _valueChangesSubject = new Subject < void > ( ) ;
13
+ /** A class representing a range of dates. */
14
+ export class DateRange < D > {
15
+ /**
16
+ * Ensures that objects with a `start` and `end` property can't be assigned to a variable that
17
+ * expects a `DateRange`
18
+ */
19
+ // tslint:disable-next-line:no-unused-variable
20
+ private _disableStructuralEquivalency : never ;
21
+
22
+ /** The start date of the range. */
23
+ readonly start : D | null ;
24
+
25
+ /** The end date of the range. */
26
+ readonly end : D | null ;
27
+
28
+ constructor ( range ?: { start ?: D | null , end ?: D | null } | null ) {
29
+ this . start = range && range . start || null ;
30
+ this . end = range && range . end || null ;
31
+ }
32
+ }
33
+
34
+ type ExtractDateTypeFromSelection < T > = T extends DateRange < infer D > ? D : NonNullable < T > ;
35
+
36
+ /** A selection model containing a date selection. */
37
+ export abstract class MatDateSelectionModel < S , D = ExtractDateTypeFromSelection < S > >
38
+ implements OnDestroy {
39
+ /** Subject used to emit value change events. */
40
+ private _valueChangesSubject = new Subject < void > ( ) ;
41
+
42
+ /** Observable of value change events. */
15
43
valueChanges : Observable < void > = this . _valueChangesSubject . asObservable ( ) ;
16
44
17
- constructor ( protected readonly adapter : DateAdapter < D > ) { }
45
+ /** The current selection. */
46
+ get selection ( ) : S { return this . _selection ; }
47
+ set selection ( s : S ) {
48
+ this . _selection = s ;
49
+ this . _valueChangesSubject . next ( ) ;
50
+ }
18
51
19
- destroy ( ) {
52
+ protected constructor ( protected readonly adapter : DateAdapter < D > , private _selection : S ) { }
53
+
54
+ ngOnDestroy ( ) {
20
55
this . _valueChangesSubject . complete ( ) ;
21
56
}
22
57
58
+ /** Adds a date to the current selection. */
23
59
abstract add ( date : D | null ) : void ;
60
+
61
+ /** Checks whether the current selection is complete. */
24
62
abstract isComplete ( ) : boolean ;
63
+
64
+ /**
65
+ * Checks whether the current selection is the same as the selection in the given selection model.
66
+ */
25
67
abstract isSame ( other : MatDateSelectionModel < D > ) : boolean ;
68
+
69
+ /** Checks whether the current selection is valid. */
26
70
abstract isValid ( ) : boolean ;
27
- abstract overlaps ( range : DateRange < D > ) : boolean ;
28
- }
29
71
30
- export interface DateRange < D > {
31
- start : D | null ;
32
- end : D | null ;
72
+ /** Checks whether the current selection overlaps with the given range. */
73
+ abstract overlaps ( range : DateRange < D > ) : boolean ;
33
74
}
34
75
35
- /**
36
- * Concrete implementation of a MatDateSelectionModel that holds a single date.
37
- */
76
+ /** A selection model that contains a single date. */
38
77
@Injectable ( )
39
- export class MatSingleDateSelectionModel < D > extends MatDateSelectionModel < D > {
40
- private _date : D | null = null ;
41
-
78
+ export class MatSingleDateSelectionModel < D > extends MatDateSelectionModel < D | null , D > {
42
79
constructor ( adapter : DateAdapter < D > , date ?: D | null ) {
43
- super ( adapter ) ;
44
- this . _date = date === undefined ? null : date ;
80
+ super ( adapter , date || null ) ;
45
81
}
46
82
83
+ /**
84
+ * Adds a date to the current selection. In the case of a single date selection, the added date
85
+ * simply overwrites the previous selection
86
+ */
47
87
add ( date : D | null ) {
48
- this . _date = date ;
49
- this . _valueChangesSubject . next ( ) ;
88
+ this . selection = date ;
50
89
}
51
90
52
- compareDate ( other : MatSingleDateSelectionModel < D > ) {
53
- const date = this . asDate ( ) ;
54
- const otherDate = other . asDate ( ) ;
55
- if ( date != null && otherDate != null ) {
56
- return this . adapter . compareDate ( date , otherDate ) ;
57
- }
58
- return date === otherDate ;
59
- }
60
-
61
- isComplete ( ) { return this . _date != null ; }
91
+ /**
92
+ * Checks whether the current selection is complete. In the case of a single date selection, this
93
+ * is true if the current selection is not null.
94
+ */
95
+ isComplete ( ) { return this . selection != null ; }
62
96
63
- isSame ( other : MatDateSelectionModel < D > ) : boolean {
97
+ /**
98
+ * Checks whether the current selection is the same as the selection in the given selection model.
99
+ */
100
+ isSame ( other : MatDateSelectionModel < any > ) : boolean {
64
101
return other instanceof MatSingleDateSelectionModel &&
65
- this . adapter . sameDate ( other . asDate ( ) , this . _date ) ;
102
+ this . adapter . sameDate ( other . selection , this . selection ) ;
66
103
}
67
104
105
+ /**
106
+ * Checks whether the current selection is valid. In the case of a single date selection, this
107
+ * means that the current selection is not null and is a valid date.
108
+ */
68
109
isValid ( ) : boolean {
69
- return this . _date != null && this . adapter . isDateInstance ( this . _date ) &&
70
- this . adapter . isValid ( this . _date ) ;
110
+ return this . selection != null && this . adapter . isDateInstance ( this . selection ) &&
111
+ this . adapter . isValid ( this . selection ) ;
71
112
}
72
113
73
- asDate ( ) : D | null {
74
- return this . isValid ( ) ? this . _date : null ;
75
- }
76
-
77
- setDate ( date : D | null ) {
78
- this . _date = date ;
79
- this . _valueChangesSubject . next ( ) ;
80
- }
81
-
82
- /**
83
- * Determines if the single date is within a given date range. Retuns false if either dates of
84
- * the range is null or if the selection is undefined.
85
- */
114
+ /** Checks whether the current selection overlaps with the given range. */
86
115
overlaps ( range : DateRange < D > ) : boolean {
87
- return ! ! ( this . _date && range . start && range . end &&
88
- this . adapter . compareDate ( range . start , this . _date ) <= 0 &&
89
- this . adapter . compareDate ( this . _date , range . end ) <= 0 ) ;
116
+ return ! ! ( this . selection && range . start && range . end &&
117
+ this . adapter . compareDate ( range . start , this . selection ) <= 0 &&
118
+ this . adapter . compareDate ( this . selection , range . end ) <= 0 ) ;
90
119
}
91
120
}
92
121
93
- /**
94
- * Concrete implementation of a MatDateSelectionModel that holds a date range, represented by
95
- * a start date and an end date.
96
- */
122
+ /** A selection model that contains a date range. */
97
123
@Injectable ( )
98
- export class MatRangeDateSelectionModel < D > extends MatDateSelectionModel < D > {
99
- private _start : D | null = null ;
100
- private _end : D | null = null ;
101
-
102
- constructor ( adapter : DateAdapter < D > , start ?: D | null , end ?: D | null ) {
103
- super ( adapter ) ;
104
- this . _start = start === undefined ? null : start ;
105
- this . _end = end === undefined ? null : end ;
124
+ export class MatRangeDateSelectionModel < D > extends MatDateSelectionModel < DateRange < D > , D > {
125
+ constructor ( adapter : DateAdapter < D > , range ?: { start ?: D | null , end ?: D | null } | null ) {
126
+ super ( adapter , new DateRange ( range ) ) ;
106
127
}
107
128
108
129
/**
109
- * Adds an additional date to the range. If no date is set thus far, it will set it to the
110
- * beginning. If the beginning is set, it will set it to the end.
111
- * If add is called on a complete selection, it will empty the selection and set it as the start .
130
+ * Adds a date to the current selection. In the case of a date range selection, the added date
131
+ * fills in the next `null` value in the range. If both the start and the end already have a date,
132
+ * the selection is reset so that the given date is the new `start` and the `end` is null .
112
133
*/
113
134
add ( date : D | null ) : void {
114
- if ( this . _start == null ) {
115
- this . _start = date ;
116
- } else if ( this . _end == null ) {
117
- this . _end = date ;
135
+ let { start, end} = this . selection ;
136
+
137
+ if ( start == null ) {
138
+ start = date ;
139
+ } else if ( end == null ) {
140
+ end = date ;
118
141
} else {
119
- this . _start = date ;
120
- this . _end = null ;
142
+ start = date ;
143
+ end = null ;
121
144
}
122
145
123
- this . _valueChangesSubject . next ( ) ;
124
- }
125
-
126
- setRange ( start : D | null , end : D | null ) {
127
- this . _start = start ;
128
- this . _end = end ;
146
+ this . selection = new DateRange < D > ( { start, end} ) ;
129
147
}
130
148
149
+ /**
150
+ * Checks whether the current selection is complete. In the case of a date range selection, this
151
+ * is true if the current selection has a non-null `start` and `end`.
152
+ */
131
153
isComplete ( ) : boolean {
132
- return this . _start != null && this . _end != null ;
154
+ return this . selection . start != null && this . selection . end != null ;
133
155
}
134
156
135
- isSame ( other : MatDateSelectionModel < D > ) : boolean {
157
+ /**
158
+ * Checks whether the current selection is the same as the selection in the given selection model.
159
+ */
160
+ isSame ( other : MatDateSelectionModel < any > ) : boolean {
136
161
if ( other instanceof MatRangeDateSelectionModel ) {
137
- const otherRange = other . asRange ( ) ;
138
- return this . adapter . sameDate ( this . _start , otherRange . start ) &&
139
- this . adapter . sameDate ( this . _end , otherRange . end ) ;
162
+ return this . adapter . sameDate ( this . selection . start , other . selection . start ) &&
163
+ this . adapter . sameDate ( this . selection . end , other . selection . end ) ;
140
164
}
141
165
return false ;
142
166
}
143
167
168
+ /**
169
+ * Checks whether the current selection is valid. In the case of a date range selection, this
170
+ * means that the current selection has a `start` and `end` that are both non-null and valid
171
+ * dates.
172
+ */
144
173
isValid ( ) : boolean {
145
- return this . _start != null && this . _end != null &&
146
- this . adapter . isValid ( this . _start ! ) && this . adapter . isValid ( this . _end ! ) ;
147
- }
148
-
149
- asRange ( ) : DateRange < D > {
150
- return {
151
- start : this . _start ,
152
- end : this . _end ,
153
- } ;
174
+ return this . selection . start != null && this . selection . end != null &&
175
+ this . adapter . isValid ( this . selection . start ! ) && this . adapter . isValid ( this . selection . end ! ) ;
154
176
}
155
177
156
178
/**
157
179
* Returns true if the given range and the selection overlap in any way. False if otherwise, that
158
180
* includes incomplete selections or ranges.
159
181
*/
160
182
overlaps ( range : DateRange < D > ) : boolean {
161
- if ( ! ( this . _start && this . _end && range . start && range . end ) ) {
183
+ if ( ! ( this . selection . start && this . selection . end && range . start && range . end ) ) {
162
184
return false ;
163
185
}
164
186
165
187
return (
166
- this . _isBetween ( range . start , this . _start , this . _end ) ||
167
- this . _isBetween ( range . end , this . _start , this . _end ) ||
168
- (
169
- this . adapter . compareDate ( range . start , this . _start ) <= 0 &&
170
- this . adapter . compareDate ( this . _end , range . end ) <= 0
171
- )
188
+ this . _isBetween ( range . start , this . selection . start , this . selection . end ) ||
189
+ this . _isBetween ( range . end , this . selection . start , this . selection . end ) ||
190
+ (
191
+ this . adapter . compareDate ( range . start , this . selection . start ) <= 0 &&
192
+ this . adapter . compareDate ( this . selection . end , range . end ) <= 0
193
+ )
172
194
) ;
173
195
}
174
196
@@ -177,9 +199,8 @@ export class MatRangeDateSelectionModel<D> extends MatDateSelectionModel<D> {
177
199
}
178
200
}
179
201
180
- export function MAT_SINGLE_DATE_SELECTION_MODEL_FACTORY < D > ( parent :
181
- MatSingleDateSelectionModel < D > ,
182
- adapter : DateAdapter < D > ) {
202
+ export function MAT_SINGLE_DATE_SELECTION_MODEL_FACTORY (
203
+ parent : MatSingleDateSelectionModel < unknown > , adapter : DateAdapter < unknown > ) {
183
204
return parent || new MatSingleDateSelectionModel ( adapter ) ;
184
205
}
185
206
0 commit comments