@@ -41,6 +41,14 @@ import {MAT_DATE_FORMATS, MatDateFormats} from '../datetime/date-formats';
41
41
* Possible views for the calendar.
42
42
* @docs -private
43
43
*/
44
+ export enum SelectionModeType {
45
+ Date = 'date' ,
46
+ Range = 'range' ,
47
+ Since = 'since' ,
48
+ Until = 'until' ,
49
+
50
+ Default = Date
51
+ } ;
44
52
export type SatCalendarView = 'month' | 'year' | 'multi-year' ;
45
53
46
54
/** Default header for SatCalendar */
@@ -204,24 +212,25 @@ export class SatCalendarFooter<D> {
204
212
} )
205
213
export class SatCalendar < D > implements AfterContentInit , AfterViewChecked , OnDestroy , OnChanges {
206
214
207
- /** Beginning of date range. */
208
- @Input ( )
209
- get beginDate ( ) : D | null { return this . _beginDate ; }
210
- set beginDate ( value : D | null ) {
211
- this . _beginDate = this . _getValidDateOrNull ( this . _dateAdapter . deserialize ( value ) ) ;
212
- }
213
- private _beginDate : D | null ;
214
-
215
- /** Date range end. */
216
- @Input ( )
217
- get endDate ( ) : D | null { return this . _endDate ; }
218
- set endDate ( value : D | null ) {
219
- this . _endDate = this . _getValidDateOrNull ( this . _dateAdapter . deserialize ( value ) ) ;
220
- }
221
- private _endDate : D | null ;
215
+ /** Beginning of date range. */
216
+ @Input ( )
217
+ get beginDate ( ) {
218
+ return this . _beginDate ;
219
+ }
220
+ set beginDate ( value ) {
221
+ this . _beginDate = this . _getValidDateOrNull ( this . _dateAdapter . deserialize ( value ) ) ;
222
+ }
223
+ private _beginDate ;
222
224
223
- /** Whenever datepicker is for selecting range of dates. */
224
- @Input ( ) rangeMode = false ;
225
+ /** Date range end. */
226
+ @Input ( )
227
+ get endDate ( ) {
228
+ return this . _endDate ;
229
+ }
230
+ set endDate ( value ) {
231
+ this . _endDate = this . _getValidDateOrNull ( this . _dateAdapter . deserialize ( value ) ) ;
232
+ }
233
+ private _endDate ;
225
234
226
235
/** Enables datepicker closing after selection */
227
236
@Input ( ) closeAfterSelection = true ;
@@ -259,11 +268,11 @@ export class SatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
259
268
260
269
/** A date representing the period (month or year) to start the calendar in. */
261
270
@Input ( )
262
- get startAt ( ) : D | null { return this . _startAt ; }
263
- set startAt ( value : D | null ) {
271
+ get startAt ( ) : D | number | null { return this . _startAt ; }
272
+ set startAt ( value : D | number | null ) {
264
273
this . _startAt = this . _getValidDateOrNull ( this . _dateAdapter . deserialize ( value ) ) ;
265
274
}
266
- private _startAt : D | null ;
275
+ private _startAt : D | number | null ;
267
276
268
277
/** Whether the calendar should be started in month or year view. */
269
278
@Input ( ) startView : SatCalendarView = 'month' ;
@@ -301,6 +310,33 @@ export class SatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
301
310
/** Order the views when clicking on period label button */
302
311
@Input ( ) orderPeriodLabel : 'multi-year' | 'month' = 'multi-year' ;
303
312
313
+ /** Initial selectiom mode */
314
+ @Input ( )
315
+ get initialSelectionMode ( ) : SelectionModeType { return this . _initialSelectionMode ; }
316
+ set initialSelectionMode ( mode : SelectionModeType ) {
317
+ if ( mode ) {
318
+ this . _initialSelectionMode = mode ;
319
+ }
320
+ }
321
+ _initialSelectionMode = SelectionModeType . Default ;
322
+
323
+ /** Selection mode */
324
+ @Input ( )
325
+ set selectionMode ( mode ) {
326
+ this . _selectionMode = mode ;
327
+ }
328
+ get selectionMode ( ) {
329
+ if ( ! this . _selectionMode ) {
330
+ this . _selectionMode = this . initialSelectionMode ;
331
+ }
332
+
333
+ return this . _selectionMode ;
334
+ }
335
+ _selectionMode : SelectionModeType = this . initialSelectionMode ;
336
+
337
+ /** Possible selection modes, in the order that they should appear */
338
+ @Input ( ) selectionModes = [ ] ;
339
+
304
340
/** Emits when the currently selected date changes. */
305
341
@Output ( ) readonly selectedChange : EventEmitter < D > = new EventEmitter < D > ( ) ;
306
342
@@ -332,13 +368,13 @@ export class SatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
332
368
* The current active date. This determines which time period is shown and which date is
333
369
* highlighted when using keyboard navigation.
334
370
*/
335
- get activeDate ( ) : D { return this . _clampedActiveDate ; }
336
- set activeDate ( value : D ) {
371
+ get activeDate ( ) { return this . _clampedActiveDate ; }
372
+ set activeDate ( value ) {
337
373
this . _clampedActiveDate = this . _dateAdapter . clampDate ( value , this . minDate , this . maxDate ) ;
338
374
this . stateChanges . next ( ) ;
339
375
this . _changeDetectorRef . markForCheck ( ) ;
340
376
}
341
- private _clampedActiveDate : D ;
377
+ private _clampedActiveDate ;
342
378
343
379
/** Whether the calendar is in month view. */
344
380
get currentView ( ) : SatCalendarView { return this . _currentView ; }
@@ -419,29 +455,60 @@ export class SatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
419
455
/** Updates today's date after an update of the active date */
420
456
updateTodaysDate ( ) {
421
457
let view = this . currentView == 'month' ? this . monthView :
422
- ( this . currentView == 'year' ? this . yearView : this . multiYearView ) ;
458
+ ( this . currentView == 'year' ? this . yearView : this . multiYearView ) ;
423
459
424
460
view . ngAfterContentInit ( ) ;
425
461
}
426
462
427
463
/** Handles date selection in the month view. */
428
- _dateSelected ( date : D ) : void {
429
- if ( this . rangeMode ) {
430
- if ( ! this . beginDateSelected ) {
431
- this . beginDateSelected = date ;
432
- this . beginDate = date ;
433
- this . endDate = date ;
434
- this . beginDateSelectedChange . emit ( date ) ;
435
- } else {
436
- this . beginDateSelected = false ;
437
- if ( this . _dateAdapter . compareDate ( < D > this . beginDate , date ) <= 0 ) {
438
- this . endDate = date ;
439
- } else {
440
- this . endDate = this . beginDate ;
441
- this . beginDate = date ;
442
- }
443
- this . dateRangesChange . emit ( { begin : < D > this . beginDate , end : this . endDate } ) ;
464
+ _dateSelected ( date ) : void {
465
+ if ( this . selectionMode == 'range' ) {
466
+
467
+ if ( ! this . beginDateSelected ) {
468
+ this . beginDateSelected = date ;
469
+ this . beginDate = date ;
470
+ this . endDate = date ;
471
+ this . beginDateSelectedChange . emit ( date ) ;
472
+ } else {
473
+ /*
474
+ Problem: Assign each date from the range accordingly with the user
475
+ selection, knowing that each "Date" assignment has to be cloned before,
476
+ preventing assigning a variable to a variable's reference.
477
+
478
+ Compare the two dates selected and if they are different,
479
+ clone them into new consts isolated in this iteration.
480
+
481
+ If they are equal just set both dates to
482
+ the "date" variable, as it only exists in this current iteration
483
+
484
+ Emit the change in the end
485
+ */
486
+
487
+ this . beginDateSelected = false ;
488
+ const sumDates = this . _dateAdapter . compareDate ( this . beginDate , date ) ;
489
+
490
+ if ( sumDates < 0 ) { // Seconds date is greater than first date
491
+ const start = new Date ( this . beginDate . getTime ( ) ) ;
492
+ const end = new Date ( date . getTime ( ) ) ;
493
+
494
+ this . beginDate = start ;
495
+ this . endDate = end ;
496
+ } else if ( sumDates > 0 ) { // First date is greater than second date
497
+ const start = new Date ( date . getTime ( ) ) ;
498
+ const end = new Date ( this . beginDate . getTime ( ) ) ;
499
+
500
+ this . beginDate = start ;
501
+ this . endDate = end ;
502
+ } else { // Dates are equal
503
+ this . beginDate = this . endDate = date ;
444
504
}
505
+
506
+ this . dateRangesChange . emit ( { begin : this . beginDate , end : this . endDate } ) ;
507
+ }
508
+ } else if ( this . selectionMode === 'since' ) {
509
+ this . dateRangesChange . emit ( { begin : date , end : Infinity } ) ;
510
+ } else if ( this . selectionMode === 'until' ) {
511
+ this . dateRangesChange . emit ( { begin : Infinity , end : date } ) ;
445
512
} else if ( ! this . _dateAdapter . sameDate ( date , this . selected ) ) {
446
513
this . selectedChange . emit ( date ) ;
447
514
}
@@ -472,7 +539,7 @@ export class SatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
472
539
* @returns The given object if it is both a date instance and valid, otherwise null.
473
540
*/
474
541
private _getValidDateOrNull ( obj : any ) : D | null {
475
- return ( this . _dateAdapter . isDateInstance ( obj ) && this . _dateAdapter . isValid ( obj ) ) ? obj : null ;
542
+ return ( obj === Infinity || ( this . _dateAdapter . isDateInstance ( obj ) && this . _dateAdapter . isValid ( obj ) ) ) ? obj : null ;
476
543
}
477
544
478
545
/** Returns the component instance that corresponds to the current calendar view. */
0 commit comments