@progress/kendo-angular-dateinputs 16.0.0-develop.12 → 16.0.0-develop.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/calendar/calendar.component.d.ts +42 -8
  2. package/calendar/horizontal-view-list.component.d.ts +4 -3
  3. package/calendar/models/cell-context.interface.d.ts +4 -0
  4. package/calendar/models/selection-range.interface.d.ts +2 -2
  5. package/calendar/models/selection.d.ts +11 -1
  6. package/calendar/multiview-calendar.component.d.ts +40 -8
  7. package/calendar/view-list.component.d.ts +7 -1
  8. package/calendar/view.component.d.ts +2 -1
  9. package/common/utils.d.ts +4 -0
  10. package/daterange/date-range-popup.component.d.ts +15 -2
  11. package/datetimepicker/datetimepicker.component.d.ts +5 -0
  12. package/esm2020/calendar/calendar.component.mjs +233 -45
  13. package/esm2020/calendar/horizontal-view-list.component.mjs +9 -5
  14. package/esm2020/calendar/models/selection.mjs +34 -1
  15. package/esm2020/calendar/multiview-calendar.component.mjs +226 -45
  16. package/esm2020/calendar/services/century-view.service.mjs +26 -5
  17. package/esm2020/calendar/services/decade-view.service.mjs +26 -5
  18. package/esm2020/calendar/services/month-view.service.mjs +26 -5
  19. package/esm2020/calendar/services/year-view.service.mjs +26 -5
  20. package/esm2020/calendar/view-list.component.mjs +20 -3
  21. package/esm2020/calendar/view.component.mjs +6 -3
  22. package/esm2020/common/utils.mjs +4 -0
  23. package/esm2020/datepicker/datepicker.component.mjs +1 -1
  24. package/esm2020/daterange/date-range-popup.component.mjs +64 -11
  25. package/esm2020/daterange/date-range.component.mjs +1 -1
  26. package/esm2020/datetimepicker/datetimepicker.component.mjs +14 -2
  27. package/esm2020/package-metadata.mjs +2 -2
  28. package/esm2020/timepicker/timepicker.component.mjs +1 -1
  29. package/esm2020/timepicker/timeselector.component.mjs +22 -7
  30. package/fesm2015/progress-kendo-angular-dateinputs.mjs +748 -142
  31. package/fesm2020/progress-kendo-angular-dateinputs.mjs +736 -141
  32. package/package.json +8 -8
  33. package/timepicker/timeselector.component.d.ts +2 -1
@@ -6,7 +6,7 @@ import { Component, ChangeDetectorRef, ChangeDetectionStrategy, ContentChild, Ev
6
6
  import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
7
7
  import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n';
8
8
  import { cloneDate, isEqual } from '@progress/kendo-date-math';
9
- import { hasObservers, guid, Keys } from '@progress/kendo-angular-common';
9
+ import { hasObservers, guid, Keys, isObject } from '@progress/kendo-angular-common';
10
10
  import { HorizontalViewListComponent } from './horizontal-view-list.component';
11
11
  import { HeaderComponent } from './header.component';
12
12
  import { BusViewService } from './services/bus-view.service';
@@ -21,13 +21,14 @@ import { WeekNumberCellTemplateDirective } from './templates/weeknumber-cell-tem
21
21
  import { HeaderTitleTemplateDirective } from './templates/header-title-template.directive';
22
22
  import { Action } from './models/navigation-action.enum';
23
23
  import { CalendarViewEnum } from './models/view.enum';
24
+ import { handleRangeSelection } from './models/selection';
24
25
  import { minValidator } from '../validators/min.validator';
25
26
  import { maxValidator } from '../validators/max.validator';
26
27
  import { disabledDatesRangeValidator } from '../validators/disabled-dates-range.validator';
27
28
  import { MIN_DATE, MAX_DATE } from '../defaults';
28
29
  import { areDatesEqual, dateInRange, getToday, hasExistingValue, last, noop } from '../util';
29
30
  import { Subscription } from 'rxjs';
30
- import { isArrowWithShiftPressed, isPresent } from '../common/utils';
31
+ import { isArrowWithShiftPressed, isNullOrDate, isPresent } from '../common/utils';
31
32
  import { NavigationService } from './services/navigation.service';
32
33
  import { HeaderTemplateDirective } from './templates/header-template.directive';
33
34
  import { FooterTemplateDirective } from './templates/footer-template.directivе';
@@ -112,15 +113,14 @@ export class MultiViewCalendarComponent {
112
113
  * ([see example]({% slug disabled_dates_multiviewcalendar %}#toc-validation)).
113
114
  */
114
115
  this.disabledDatesRangeValidation = false;
116
+ this._selection = 'single';
115
117
  /**
116
- * Sets the Calendar selection mode
117
- * ([see example]({% slug multiple_selection_multiviewcalendar %})).
118
+ * Allows reverse selection when using `range` selection.
119
+ * If `allowReverse` is set to `true`, the component skips the validation of whether the start date is after the end date.
118
120
  *
119
- * The available values are:
120
- * * `single` (default)
121
- * * `multiple`
121
+ * @default false
122
122
  */
123
- this.selection = 'single';
123
+ this.allowReverse = false;
124
124
  /**
125
125
  * Sets or gets the `disabled` property of the Calendar and
126
126
  * determines whether the component is active
@@ -215,6 +215,11 @@ export class MultiViewCalendarComponent {
215
215
  * ([see example](slug:events_multiviewcalendar)).
216
216
  */
217
217
  this.valueChange = new EventEmitter();
218
+ /**
219
+ * @hidden
220
+ * Fires when the range selection changes.
221
+ */
222
+ this.rangeSelectionChange = new EventEmitter();
218
223
  /**
219
224
  * Fires each time the MultiViewCalendar gets blurred
220
225
  * ([see example](slug:events_multiviewcalendar)).
@@ -248,9 +253,15 @@ export class MultiViewCalendarComponent {
248
253
  this.prevView = Action.PrevView;
249
254
  this.nextView = Action.NextView;
250
255
  this.selectedDates = [];
256
+ this.shouldHoverWhenNoStart = false;
257
+ this.canHover = false;
258
+ this.changes = {};
259
+ this.valueSetter = false;
260
+ this.selectionSetter = false;
251
261
  this._min = new Date(MIN_DATE);
252
262
  this._max = new Date(MAX_DATE);
253
263
  this._focusedDate = getToday();
264
+ this._selectionRange = { start: null, end: null };
254
265
  this.resolvedPromise = Promise.resolve();
255
266
  this.onControlChange = noop;
256
267
  this.onControlTouched = noop;
@@ -315,29 +326,37 @@ export class MultiViewCalendarComponent {
315
326
  get max() {
316
327
  return this._max;
317
328
  }
329
+ /**
330
+ * Sets the Calendar selection mode
331
+ * ([see example]({% slug multiple_selection_multiviewcalendar %})).
332
+ *
333
+ * The available values are:
334
+ * * `single` (default)
335
+ * * `multiple`
336
+ * * `range`
337
+ */
338
+ set selection(_selection) {
339
+ this.selectionSetter = true;
340
+ this._selection = _selection;
341
+ }
342
+ get selection() {
343
+ return this._selection;
344
+ }
318
345
  /**
319
346
  * Sets or gets the `value` property of the Calendar and defines the selected value of the component.
320
347
  *
321
348
  * > The `value` has to be a valid
322
349
  * [JavaScript `Date`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date)
323
- * instance when in `single` selection mode or an array of valid JavaScript Date instances when in `multiple` selection mode.
350
+ * instance when in `single` selection mode, an array of valid JavaScript Date instances when in `multiple` selection mode, or
351
+ * an object of type `SelectionRange` when in `range` selection mode.
324
352
  */
353
+ set value(candidate) {
354
+ this.valueSetter = true;
355
+ this._value = candidate;
356
+ }
325
357
  get value() {
326
358
  return this._value;
327
359
  }
328
- set value(candidate) {
329
- this.verifyValue(candidate);
330
- this._value = Array.isArray(candidate) ?
331
- candidate.filter(date => isPresent(date)).map(element => cloneDate(element)) :
332
- cloneDate(candidate);
333
- const selection = [].concat(candidate).filter(date => isPresent(date)).map(date => cloneDate(date));
334
- if (!areDatesEqual(selection, this.selectedDates)) {
335
- const lastSelected = last(selection);
336
- this.rangePivot = cloneDate(lastSelected);
337
- this.focusedDate = cloneDate(lastSelected) || this.focusedDate;
338
- this.selectedDates = selection;
339
- }
340
- }
341
360
  /**
342
361
  * @hidden
343
362
  */
@@ -354,10 +373,23 @@ export class MultiViewCalendarComponent {
354
373
  set disabledDates(value) {
355
374
  this.disabledDatesService.initialize(value);
356
375
  }
376
+ /**
377
+ * Specify, which end of the defined selection range should be marked as active.
378
+ *
379
+ * > Value will be ignored if the selection range is undefined.
380
+ * > If range selection is used then the default value is 'start'.
381
+ */
382
+ set activeRangeEnd(_activeRangeEnd) {
383
+ this._activeRangeEnd = _activeRangeEnd;
384
+ }
385
+ get activeRangeEnd() {
386
+ return (this.selection === 'range' && !this._activeRangeEnd) ? 'start' : this._activeRangeEnd;
387
+ }
357
388
  /**
358
389
  * Sets or gets the `selectionRange` property of the Calendar and
359
390
  * defines the selection range of the component
360
391
  * ([see example]({% slug dates_multiviewcalendar %}#toc-selection-range)).
392
+ * > We recommend using the `value` property as it now supports `range` selection.
361
393
  */
362
394
  set selectionRange(range) {
363
395
  this._selectionRange = range;
@@ -581,8 +613,13 @@ export class MultiViewCalendarComponent {
581
613
  return;
582
614
  }
583
615
  else if (onEnterKeyPress) {
584
- this.selectionService.lastClicked = this.focusedDate;
585
- this.performSelection(this.focusedDate, event);
616
+ if (this.selection !== 'range') {
617
+ this.selectionService.lastClicked = this.focusedDate;
618
+ this.performSelection(this.focusedDate, event);
619
+ }
620
+ else {
621
+ this.performRangeSelection(this.focusedDate);
622
+ }
586
623
  }
587
624
  if (this.views >= 2) {
588
625
  if ((escKey || (altKey && onArrowUpPress))) {
@@ -605,7 +642,7 @@ export class MultiViewCalendarComponent {
605
642
  if (!isSameView) {
606
643
  this.emitNavigate(this.focusedDate);
607
644
  }
608
- if (isArrowWithShiftPressed(event)) {
645
+ if (isArrowWithShiftPressed(event) && this.selection !== 'range') {
609
646
  event['anyArrow'] = true;
610
647
  this.performSelection(this.focusedDate, event);
611
648
  }
@@ -619,21 +656,30 @@ export class MultiViewCalendarComponent {
619
656
  }));
620
657
  }
621
658
  ngOnChanges(changes) {
659
+ this.changes = changes;
622
660
  this.verifyChanges();
623
661
  this.bus.configure(this.bottomViewEnum, this.topViewEnum);
624
- if (hasExistingValue(changes, 'focusedDate')) {
625
- const focusedDate = changes.focusedDate.currentValue;
662
+ }
663
+ ngDoCheck() {
664
+ if (this.valueSetter || this.selectionSetter) {
665
+ this.setValue(this.value);
666
+ this.valueSetter = false;
667
+ this.selectionSetter = false;
668
+ }
669
+ if (hasExistingValue(this.changes, 'focusedDate')) {
670
+ const focusedDate = this.changes.focusedDate.currentValue;
626
671
  this.focusedDate = dateInRange(focusedDate, this.min, this.max);
627
672
  }
628
- if (changes.min || changes.max || changes.rangeValidation || changes.disabledDates || changes.disabledDatesRangeValidation) {
673
+ if (this.changes.min || this.changes.max || this.changes.rangeValidation || this.changes.disabledDates || this.changes.disabledDatesRangeValidation) {
629
674
  this.minValidateFn = this.rangeValidation ? minValidator(this.min) : noop;
630
675
  this.maxValidateFn = this.rangeValidation ? maxValidator(this.max) : noop;
631
676
  this.disabledDatesRangeValidateFn = this.disabledDatesRangeValidation ? disabledDatesRangeValidator(this.disabledDatesService.isDateDisabled) : noop;
632
677
  this.onValidatorChange();
633
678
  }
634
- if (changes.min || changes.max || changes.focusedDate || changes.activeView) {
679
+ if (this.changes.min || this.changes.max || this.changes.focusedDate || this.changes.activeView) {
635
680
  this.updateButtonState();
636
681
  }
682
+ this.changes = {};
637
683
  }
638
684
  ngOnDestroy() {
639
685
  this.subscriptions.unsubscribe();
@@ -692,11 +738,48 @@ export class MultiViewCalendarComponent {
692
738
  if (this.disabledDatesService.isDateDisabled(this.focusedDate)) {
693
739
  return;
694
740
  }
741
+ if (this.selection === 'range') {
742
+ return;
743
+ }
695
744
  this.selectedDates = availableDates.map(date => cloneDate(date));
696
745
  this.value = this.parseSelectionToValue(availableDates);
697
746
  this.onControlChange(this.parseSelectionToValue(availableDates));
698
747
  this.valueChange.emit(this.parseSelectionToValue(availableDates));
699
748
  }
749
+ /**
750
+ * @hidden
751
+ */
752
+ onCellEnter(cellEnter, date) {
753
+ this.emitCellEvent(cellEnter, date);
754
+ if (this.selection === 'range' && (this.canHover || this.shouldHoverWhenNoStart)) {
755
+ this.zone.run(() => {
756
+ if (this.canHover && !this.shouldHoverWhenNoStart) {
757
+ if (this.allowReverse) {
758
+ if (this.activeRangeEnd === 'end' && this.selectionRange.start) {
759
+ this.selectionRange = { start: this.selectionRange.start, end: date };
760
+ }
761
+ if (this.activeRangeEnd === 'start' && this.selectionRange.end) {
762
+ this.selectionRange = { start: date, end: this.selectionRange.end };
763
+ }
764
+ }
765
+ else {
766
+ if (this.activeRangeEnd === 'end' && this.selectionRange.start && date >= this.selectionRange.start) {
767
+ this.selectionRange = { start: this.selectionRange.start, end: date };
768
+ }
769
+ if (this.selectionRange.start && date < this.selectionRange.start) {
770
+ this.selectionRange = { start: this.selectionRange.start, end: null };
771
+ }
772
+ }
773
+ }
774
+ else if (this.shouldHoverWhenNoStart && date <= this.selectionRange.end) {
775
+ this.selectionRange = { start: date, end: this.selectionRange.end };
776
+ }
777
+ else {
778
+ this.selectionRange = { start: null, end: this.selectionRange.end };
779
+ }
780
+ });
781
+ }
782
+ }
700
783
  /**
701
784
  * @hidden
702
785
  */
@@ -801,8 +884,13 @@ export class MultiViewCalendarComponent {
801
884
  * @hidden
802
885
  */
803
886
  handleCellClick({ date, modifiers }) {
804
- this.selectionService.lastClicked = date;
805
- this.performSelection(date, modifiers);
887
+ if (this.selection === 'range') {
888
+ this.performRangeSelection(date);
889
+ }
890
+ else {
891
+ this.selectionService.lastClicked = date;
892
+ this.performSelection(date, modifiers);
893
+ }
806
894
  const isSameView = this.bus.service(this.activeViewEnum).isInArray(this.focusedDate, this.viewList.dates);
807
895
  if (!isSameView) {
808
896
  this.emitNavigate(this.focusedDate);
@@ -816,10 +904,23 @@ export class MultiViewCalendarComponent {
816
904
  return;
817
905
  }
818
906
  this.zone.run(() => {
819
- this.handleDateChange({
820
- selectedDates: dates,
821
- focusedDate: last(dates)
822
- });
907
+ if (this.selection === 'multiple') {
908
+ this.handleDateChange({
909
+ selectedDates: dates,
910
+ focusedDate: last(dates),
911
+ });
912
+ }
913
+ if (this.selection === 'range') {
914
+ this.activeRangeEnd = 'start';
915
+ const shouldEmitValueChange = this.selectionRange.start?.getTime() !== dates[0].getTime() ||
916
+ this.selectionRange.end?.getTime() !== last(dates).getTime();
917
+ this.selectionRange.start = dates[0];
918
+ this.selectionRange.end = last(dates);
919
+ this.value = this.selectionRange;
920
+ if (shouldEmitValueChange) {
921
+ this.valueChange.emit(this.value);
922
+ }
923
+ }
823
924
  });
824
925
  }
825
926
  setClasses(element) {
@@ -842,15 +943,23 @@ export class MultiViewCalendarComponent {
842
943
  if (!isDevMode()) {
843
944
  return;
844
945
  }
845
- if (this.selection === 'single' && candidate && !(candidate instanceof Date)) {
846
- throw new Error(`The 'value' should be a valid JavaScript Date instance. Check ${VALUE_DOC_LINK} for possible resolution.`);
946
+ if (this.selection === 'single' && candidate && !(isNullOrDate(candidate))) {
947
+ throw new Error(`When using 'single' selection the 'value' should be a valid JavaScript Date instance. Check ${VALUE_DOC_LINK} for possible resolution.`);
847
948
  }
848
- else if (this.selection === 'multiple' && candidate && Array.isArray(candidate)) {
849
- const onlyDates = candidate.every(value => value instanceof Date);
850
- if (!onlyDates) {
851
- throw new Error(`The 'value' should be an array of valid JavaScript Date instances. Check ${VALUE_DOC_LINK} for possible resolution.`);
949
+ else if (this.selection === 'multiple' && candidate) {
950
+ if (Array.isArray(candidate)) {
951
+ const onlyDates = candidate.every(value => value instanceof Date);
952
+ if (!onlyDates) {
953
+ throw new Error(`When using 'multiple' selection the 'value' should be an array of valid JavaScript Date instances. Check ${VALUE_DOC_LINK} for possible resolution.`);
954
+ }
955
+ }
956
+ if (Object.keys(candidate).find(k => k === 'start') && Object.keys(candidate).find(k => k === 'end')) {
957
+ throw new Error(`When using 'multiple' selection the 'value' should be an array of valid JavaScript Date instances. Check ${VALUE_DOC_LINK} for possible resolution.`);
852
958
  }
853
959
  }
960
+ else if (this.selection === 'range' && candidate && !(isNullOrDate(candidate['start']) && isNullOrDate(candidate['end']))) {
961
+ throw new Error(`The 'value' should be an object with start and end dates. Check ${VALUE_DOC_LINK} for possible resolution.`);
962
+ }
854
963
  }
855
964
  updateButtonState() {
856
965
  this.resolvedPromise.then(() => {
@@ -863,6 +972,72 @@ export class MultiViewCalendarComponent {
863
972
  selection = selection || [];
864
973
  return this.selection === 'single' ? cloneDate(last(selection)) : selection.map(date => cloneDate(date));
865
974
  }
975
+ setValue(candidate) {
976
+ this.verifyValue(candidate);
977
+ if (candidate === null) {
978
+ this._value = null;
979
+ this.selectedDates = [];
980
+ }
981
+ else if (Array.isArray(candidate)) {
982
+ this.selectionRange = { start: null, end: null };
983
+ this._value = candidate.filter(date => isPresent(date)).map(element => cloneDate(element));
984
+ }
985
+ else if (isObject(candidate) && Object.keys(candidate).find(k => k === 'start') && Object.keys(candidate).find(k => k === 'end')) {
986
+ this.selectedDates = [];
987
+ this.selectionRange = { start: null, end: null };
988
+ this._value = { start: null, end: null };
989
+ this._value.start = candidate.start instanceof Date ? cloneDate(candidate.start) : null;
990
+ this._value.end = candidate.end instanceof Date ? cloneDate(candidate.end) : null;
991
+ this.selectionRange = Object.assign({}, this._value);
992
+ if (this._value?.start && !this._value?.end) {
993
+ this.activeRangeEnd = 'end';
994
+ this.canHover = true;
995
+ }
996
+ if (this._value?.end && !this._value?.start) {
997
+ this.activeRangeEnd = 'start';
998
+ this.canHover = true;
999
+ }
1000
+ if (this.activeRangeEnd === 'end') {
1001
+ this.focusedDate = this.selectionRange.start || this.selectionRange.end || getToday();
1002
+ }
1003
+ else {
1004
+ this.focusedDate = this.selectionRange.end || this.selectionRange.start || getToday();
1005
+ }
1006
+ }
1007
+ else {
1008
+ this.selectionRange = { start: null, end: null };
1009
+ this._value = cloneDate(candidate);
1010
+ }
1011
+ if (this.selection !== 'range') {
1012
+ const selection = [].concat(candidate).filter(date => isPresent(date)).map(date => cloneDate(date));
1013
+ if (!areDatesEqual(selection, this.selectedDates)) {
1014
+ const lastSelected = last(selection);
1015
+ this.rangePivot = cloneDate(lastSelected);
1016
+ this.focusedDate = cloneDate(lastSelected) || this.focusedDate;
1017
+ this.selectedDates = selection;
1018
+ }
1019
+ }
1020
+ }
1021
+ performRangeSelection(date) {
1022
+ const clonedRangeSelection = Object.assign({}, this.selectionRange);
1023
+ const emitValueChange = (this.activeRangeEnd === 'start' && this.value?.start?.getTime() !== date?.getTime()) ||
1024
+ (this.activeRangeEnd === 'end' && this.value?.end?.getTime() !== date?.getTime());
1025
+ this.zone.run(() => {
1026
+ const rangeSelection = handleRangeSelection(date, clonedRangeSelection, this.activeRangeEnd, this.allowReverse);
1027
+ this.activeRangeEnd = rangeSelection.activeRangeEnd;
1028
+ if (this.canHover && rangeSelection.activeRangeEnd === 'end' && rangeSelection.selectionRange.end?.getTime() === date.getTime()) {
1029
+ this.activeRangeEnd = 'start';
1030
+ }
1031
+ this.canHover = this.activeRangeEnd === 'end' && rangeSelection.selectionRange.start && !rangeSelection.selectionRange.end;
1032
+ if (emitValueChange && (this.value?.start?.getTime() !== rangeSelection.selectionRange?.start?.getTime() ||
1033
+ this.value?.end?.getTime() !== rangeSelection.selectionRange?.end?.getTime())) {
1034
+ this.value = rangeSelection.selectionRange;
1035
+ this.valueChange.emit(this.value);
1036
+ this.rangeSelectionChange.emit(rangeSelection);
1037
+ }
1038
+ this.cdr.markForCheck();
1039
+ });
1040
+ }
866
1041
  performSelection(date, selectionModifiers) {
867
1042
  const selection = this.selectionService.performSelection({
868
1043
  date: date,
@@ -880,7 +1055,7 @@ export class MultiViewCalendarComponent {
880
1055
  }
881
1056
  }
882
1057
  MultiViewCalendarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MultiViewCalendarComponent, deps: [{ token: i1.BusViewService }, { token: i0.ElementRef }, { token: i2.NavigationService }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i3.DisabledDatesService }, { token: i4.SelectionService }], target: i0.ɵɵFactoryTarget.Component });
883
- MultiViewCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: MultiViewCalendarComponent, selector: "kendo-multiviewcalendar", inputs: { showOtherMonthDays: "showOtherMonthDays", showCalendarHeader: "showCalendarHeader", id: "id", focusedDate: "focusedDate", footer: "footer", min: "min", max: "max", rangeValidation: "rangeValidation", disabledDatesRangeValidation: "disabledDatesRangeValidation", selection: "selection", value: "value", disabled: "disabled", tabindex: "tabindex", tabIndex: "tabIndex", weekDaysFormat: "weekDaysFormat", isActive: "isActive", disabledDates: "disabledDates", activeView: "activeView", bottomView: "bottomView", topView: "topView", showViewHeader: "showViewHeader", animateNavigation: "animateNavigation", weekNumber: "weekNumber", activeRangeEnd: "activeRangeEnd", selectionRange: "selectionRange", views: "views", orientation: "orientation", cellTemplateRef: ["cellTemplate", "cellTemplateRef"], monthCellTemplateRef: ["monthCellTemplate", "monthCellTemplateRef"], yearCellTemplateRef: ["yearCellTemplate", "yearCellTemplateRef"], decadeCellTemplateRef: ["decadeCellTemplate", "decadeCellTemplateRef"], centuryCellTemplateRef: ["centuryCellTemplate", "centuryCellTemplateRef"], weekNumberTemplateRef: ["weekNumberTemplate", "weekNumberTemplateRef"], footerTemplateRef: ["footerTemplate", "footerTemplateRef"], headerTitleTemplateRef: ["headerTitleTemplate", "headerTitleTemplateRef"], headerTemplateRef: ["headerTemplate", "headerTemplateRef"] }, outputs: { activeViewChange: "activeViewChange", navigate: "navigate", cellEnter: "cellEnter", cellLeave: "cellLeave", valueChange: "valueChange", blurEvent: "blur", focusEvent: "focus", focusCalendar: "focusCalendar", onClosePopup: "onClosePopup", onTabPress: "onTabPress", onShiftTabPress: "onShiftTabPress" }, host: { listeners: { "mouseenter": "handleMouseEnter()", "mouseleave": "handleMouseLeave()", "mousedown": "handleMousedown($event)", "click": "handleClick()", "keydown": "keydown($event)" }, properties: { "attr.id": "this.widgetId", "attr.aria-disabled": "this.ariaDisabled", "class.k-disabled": "this.ariaDisabled" } }, providers: [
1058
+ MultiViewCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: MultiViewCalendarComponent, selector: "kendo-multiviewcalendar", inputs: { showOtherMonthDays: "showOtherMonthDays", showCalendarHeader: "showCalendarHeader", id: "id", focusedDate: "focusedDate", footer: "footer", min: "min", max: "max", rangeValidation: "rangeValidation", disabledDatesRangeValidation: "disabledDatesRangeValidation", selection: "selection", allowReverse: "allowReverse", value: "value", disabled: "disabled", tabindex: "tabindex", tabIndex: "tabIndex", weekDaysFormat: "weekDaysFormat", isActive: "isActive", disabledDates: "disabledDates", activeView: "activeView", bottomView: "bottomView", topView: "topView", showViewHeader: "showViewHeader", animateNavigation: "animateNavigation", weekNumber: "weekNumber", activeRangeEnd: "activeRangeEnd", selectionRange: "selectionRange", views: "views", orientation: "orientation", cellTemplateRef: ["cellTemplate", "cellTemplateRef"], monthCellTemplateRef: ["monthCellTemplate", "monthCellTemplateRef"], yearCellTemplateRef: ["yearCellTemplate", "yearCellTemplateRef"], decadeCellTemplateRef: ["decadeCellTemplate", "decadeCellTemplateRef"], centuryCellTemplateRef: ["centuryCellTemplate", "centuryCellTemplateRef"], weekNumberTemplateRef: ["weekNumberTemplate", "weekNumberTemplateRef"], footerTemplateRef: ["footerTemplate", "footerTemplateRef"], headerTitleTemplateRef: ["headerTitleTemplate", "headerTitleTemplateRef"], headerTemplateRef: ["headerTemplate", "headerTemplateRef"] }, outputs: { activeViewChange: "activeViewChange", navigate: "navigate", cellEnter: "cellEnter", cellLeave: "cellLeave", valueChange: "valueChange", rangeSelectionChange: "rangeSelectionChange", blurEvent: "blur", focusEvent: "focus", focusCalendar: "focusCalendar", onClosePopup: "onClosePopup", onTabPress: "onTabPress", onShiftTabPress: "onShiftTabPress" }, host: { listeners: { "mouseenter": "handleMouseEnter()", "mouseleave": "handleMouseLeave()", "mousedown": "handleMousedown($event)", "click": "handleClick()", "keydown": "keydown($event)" }, properties: { "attr.id": "this.widgetId", "attr.aria-disabled": "this.ariaDisabled", "class.k-disabled": "this.ariaDisabled" } }, providers: [
884
1059
  BusViewService,
885
1060
  RANGE_CALENDAR_VALUE_ACCESSOR,
886
1061
  RANGE_CALENDAR_RANGE_VALIDATORS,
@@ -928,6 +1103,7 @@ MultiViewCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0
928
1103
  </kendo-calendar-header>
929
1104
  <kendo-calendar-horizontal
930
1105
  [showOtherMonthDays]="showOtherMonthDays"
1106
+ [allowReverse]="allowReverse"
931
1107
  [id]="calendarHeaderIdLabel"
932
1108
  [attr.aria-labelledby]="multiViewCalendarHeaderIdLabel"
933
1109
  [activeView]="activeViewEnum"
@@ -952,7 +1128,7 @@ MultiViewCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0
952
1128
  [disabled]="disabled"
953
1129
  (cellClick)="handleCellClick($event)"
954
1130
  (weekNumberCellClick)="handleWeekNumberClick($event)"
955
- (cellEnter)="emitCellEvent(cellEnter, $event)"
1131
+ (cellEnter)="onCellEnter(cellEnter, $event)"
956
1132
  (cellLeave)="emitCellEvent(cellLeave, $event)"
957
1133
  (activeDateChange)="setActiveDate($event)"
958
1134
  (focusCalendar)="handleFocus()"
@@ -965,7 +1141,7 @@ MultiViewCalendarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0
965
1141
  [activeViewValue]="activeView"
966
1142
  [currentDate]="activeDate">
967
1143
  </kendo-calendar-footer>
968
- `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i6.HeaderComponent, selector: "kendo-calendar-header", inputs: ["activeView", "currentDate", "min", "max", "rangeLength", "titleTemplateRef", "headerTemplateRef", "isPrevDisabled", "isNextDisabled", "showNavigationButtons", "orientation", "id"], outputs: ["todayButtonClick", "prevButtonClick", "nextButtonClick"] }, { kind: "component", type: i7.FooterComponent, selector: "kendo-calendar-footer", inputs: ["footerTemplateRef", "activeViewValue", "currentDate"] }, { kind: "component", type: i8.HorizontalViewListComponent, selector: "kendo-calendar-horizontal", inputs: ["showOtherMonthDays", "cellTemplateRef", "weekNumberTemplateRef", "activeRangeEnd", "activeView", "cellUID", "focusedDate", "isActive", "min", "max", "selectionRange", "selectedDates", "views", "showViewHeader", "animateNavigation", "orientation", "activeDescendant", "tabIndex", "disabled", "id", "weekDaysFormat", "weekNumber"], outputs: ["cellClick", "weekNumberCellClick", "cellEnter", "cellLeave", "activeDateChange", "focusCalendar", "blurCalendar", "focusedCellChange"] }, { kind: "directive", type: i9.MultiViewCalendarLocalizedMessagesDirective, selector: "[kendoMultiViewCalendarLocalizedMessages]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1144
+ `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i6.HeaderComponent, selector: "kendo-calendar-header", inputs: ["activeView", "currentDate", "min", "max", "rangeLength", "titleTemplateRef", "headerTemplateRef", "isPrevDisabled", "isNextDisabled", "showNavigationButtons", "orientation", "id"], outputs: ["todayButtonClick", "prevButtonClick", "nextButtonClick"] }, { kind: "component", type: i7.FooterComponent, selector: "kendo-calendar-footer", inputs: ["footerTemplateRef", "activeViewValue", "currentDate"] }, { kind: "component", type: i8.HorizontalViewListComponent, selector: "kendo-calendar-horizontal", inputs: ["showOtherMonthDays", "cellTemplateRef", "weekNumberTemplateRef", "allowReverse", "activeRangeEnd", "activeView", "cellUID", "focusedDate", "isActive", "min", "max", "selectionRange", "selectedDates", "views", "showViewHeader", "animateNavigation", "orientation", "activeDescendant", "tabIndex", "disabled", "id", "weekDaysFormat", "weekNumber"], outputs: ["cellClick", "weekNumberCellClick", "cellEnter", "cellLeave", "activeDateChange", "focusCalendar", "blurCalendar", "focusedCellChange"] }, { kind: "directive", type: i9.MultiViewCalendarLocalizedMessagesDirective, selector: "[kendoMultiViewCalendarLocalizedMessages]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
969
1145
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: MultiViewCalendarComponent, decorators: [{
970
1146
  type: Component,
971
1147
  args: [{
@@ -1021,6 +1197,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImpor
1021
1197
  </kendo-calendar-header>
1022
1198
  <kendo-calendar-horizontal
1023
1199
  [showOtherMonthDays]="showOtherMonthDays"
1200
+ [allowReverse]="allowReverse"
1024
1201
  [id]="calendarHeaderIdLabel"
1025
1202
  [attr.aria-labelledby]="multiViewCalendarHeaderIdLabel"
1026
1203
  [activeView]="activeViewEnum"
@@ -1045,7 +1222,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImpor
1045
1222
  [disabled]="disabled"
1046
1223
  (cellClick)="handleCellClick($event)"
1047
1224
  (weekNumberCellClick)="handleWeekNumberClick($event)"
1048
- (cellEnter)="emitCellEvent(cellEnter, $event)"
1225
+ (cellEnter)="onCellEnter(cellEnter, $event)"
1049
1226
  (cellLeave)="emitCellEvent(cellLeave, $event)"
1050
1227
  (activeDateChange)="setActiveDate($event)"
1051
1228
  (focusCalendar)="handleFocus()"
@@ -1080,6 +1257,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImpor
1080
1257
  type: Input
1081
1258
  }], selection: [{
1082
1259
  type: Input
1260
+ }], allowReverse: [{
1261
+ type: Input
1083
1262
  }], value: [{
1084
1263
  type: Input
1085
1264
  }], disabled: [{
@@ -1124,6 +1303,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImpor
1124
1303
  type: Output
1125
1304
  }], valueChange: [{
1126
1305
  type: Output
1306
+ }], rangeSelectionChange: [{
1307
+ type: Output
1127
1308
  }], blurEvent: [{
1128
1309
  type: Output,
1129
1310
  args: ['blur']
@@ -67,7 +67,7 @@ export class CenturyViewService {
67
67
  return range(0, count).map(i => addCenturies(start, i));
68
68
  }
69
69
  data(options) {
70
- const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate } = options;
70
+ const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate, allowReverse } = options;
71
71
  if (!viewDate) {
72
72
  return EMPTY_DATA;
73
73
  }
@@ -83,10 +83,30 @@ export class CenturyViewService {
83
83
  if (!this.isInRange(cellDate, min, max) || nextCentury) {
84
84
  return null;
85
85
  }
86
- const isRangeStart = this.isEqual(cellDate, selectionRange.start);
87
- const isRangeEnd = this.isEqual(cellDate, selectionRange.end);
86
+ let isRangeStart = false;
87
+ let isRangeEnd = false;
88
+ if (allowReverse) {
89
+ if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start <= selectionRange.end) ||
90
+ (this.isEqual(cellDate, selectionRange.end) && selectionRange.end <= selectionRange.start)) {
91
+ isRangeStart = true;
92
+ }
93
+ if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start >= selectionRange.end) ||
94
+ (this.isEqual(cellDate, selectionRange.end) && selectionRange.end >= selectionRange.start)) {
95
+ isRangeEnd = true;
96
+ }
97
+ }
98
+ else {
99
+ isRangeStart = this.isEqual(cellDate, selectionRange.start);
100
+ isRangeEnd = this.isEqual(cellDate, selectionRange.end);
101
+ }
88
102
  const isInMiddle = !isRangeStart && !isRangeEnd;
89
- const isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
103
+ let isRangeMid;
104
+ if (allowReverse) {
105
+ isRangeMid = isInMiddle && (isInSelectionRange(cellDate, selectionRange) || isInSelectionRange(cellDate, { start: selectionRange.end, end: selectionRange.start }));
106
+ }
107
+ else {
108
+ isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
109
+ }
90
110
  return {
91
111
  formattedValue: this.value(cellDate),
92
112
  id: `${cellUID}${cellDate.getTime()}`,
@@ -100,7 +120,8 @@ export class CenturyViewService {
100
120
  isRangeSplitStart: isRangeMid && this.isEqual(cellDate, firstDate),
101
121
  isToday: this.isEqual(cellDate, today),
102
122
  title: this.cellTitle(cellDate),
103
- value: cellDate
123
+ value: cellDate,
124
+ allowReverse: allowReverse
104
125
  };
105
126
  });
106
127
  });
@@ -67,7 +67,7 @@ export class DecadeViewService {
67
67
  return range(0, count).map(i => addDecades(start, i));
68
68
  }
69
69
  data(options) {
70
- const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate } = options;
70
+ const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate, allowReverse } = options;
71
71
  if (!viewDate) {
72
72
  return EMPTY_DATA;
73
73
  }
@@ -83,10 +83,30 @@ export class DecadeViewService {
83
83
  if (!this.isInRange(cellDate, min, max) || nextDecade) {
84
84
  return null;
85
85
  }
86
- const isRangeStart = this.isEqual(cellDate, selectionRange.start);
87
- const isRangeEnd = this.isEqual(cellDate, selectionRange.end);
86
+ let isRangeStart = false;
87
+ let isRangeEnd = false;
88
+ if (allowReverse) {
89
+ if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start <= selectionRange.end) ||
90
+ (this.isEqual(cellDate, selectionRange.end) && selectionRange.end <= selectionRange.start)) {
91
+ isRangeStart = true;
92
+ }
93
+ if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start >= selectionRange.end) ||
94
+ (this.isEqual(cellDate, selectionRange.end) && selectionRange.end >= selectionRange.start)) {
95
+ isRangeEnd = true;
96
+ }
97
+ }
98
+ else {
99
+ isRangeStart = this.isEqual(cellDate, selectionRange.start);
100
+ isRangeEnd = this.isEqual(cellDate, selectionRange.end);
101
+ }
88
102
  const isInMiddle = !isRangeStart && !isRangeEnd;
89
- const isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
103
+ let isRangeMid;
104
+ if (allowReverse) {
105
+ isRangeMid = isInMiddle && (isInSelectionRange(cellDate, selectionRange) || isInSelectionRange(cellDate, { start: selectionRange.end, end: selectionRange.start }));
106
+ }
107
+ else {
108
+ isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
109
+ }
90
110
  return {
91
111
  formattedValue: this.value(cellDate),
92
112
  id: `${cellUID}${cellDate.getTime()}`,
@@ -100,7 +120,8 @@ export class DecadeViewService {
100
120
  isRangeSplitStart: isRangeMid && this.isEqual(cellDate, firstDate),
101
121
  isToday: this.isEqual(cellDate, today),
102
122
  title: this.cellTitle(cellDate),
103
- value: cellDate
123
+ value: cellDate,
124
+ allowReverse: allowReverse
104
125
  };
105
126
  });
106
127
  });
@@ -50,7 +50,7 @@ export class MonthViewService {
50
50
  return range(0, count).map(i => addMonths(start, i));
51
51
  }
52
52
  data(options) {
53
- const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate, isDateDisabled = () => false } = options;
53
+ const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate, isDateDisabled = () => false, allowReverse } = options;
54
54
  if (!viewDate) {
55
55
  return EMPTY_DATA;
56
56
  }
@@ -72,10 +72,30 @@ export class MonthViewService {
72
72
  if (outOfRange) {
73
73
  return null;
74
74
  }
75
- const isRangeStart = this.isEqual(cellDate, selectionRange.start);
76
- const isRangeEnd = this.isEqual(cellDate, selectionRange.end);
75
+ let isRangeStart = false;
76
+ let isRangeEnd = false;
77
+ if (allowReverse) {
78
+ if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start <= selectionRange.end) ||
79
+ (this.isEqual(cellDate, selectionRange.end) && selectionRange.end <= selectionRange.start)) {
80
+ isRangeStart = true;
81
+ }
82
+ if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start >= selectionRange.end) ||
83
+ (this.isEqual(cellDate, selectionRange.end) && selectionRange.end >= selectionRange.start)) {
84
+ isRangeEnd = true;
85
+ }
86
+ }
87
+ else {
88
+ isRangeStart = this.isEqual(cellDate, selectionRange.start);
89
+ isRangeEnd = this.isEqual(cellDate, selectionRange.end);
90
+ }
77
91
  const isInMiddle = !isRangeStart && !isRangeEnd;
78
- const isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
92
+ let isRangeMid;
93
+ if (allowReverse) {
94
+ isRangeMid = isInMiddle && (isInSelectionRange(cellDate, selectionRange) || isInSelectionRange(cellDate, { start: selectionRange.end, end: selectionRange.start }));
95
+ }
96
+ else {
97
+ isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
98
+ }
79
99
  return {
80
100
  formattedValue: this.value(cellDate),
81
101
  id: `${cellUID}${otherMonth ? cellDate.getTime() + '1' : cellDate.getTime()}`,
@@ -91,7 +111,8 @@ export class MonthViewService {
91
111
  title: this.cellTitle(cellDate),
92
112
  value: cellDate,
93
113
  isDisabled: isDateDisabled(cellDate),
94
- isOtherMonth: otherMonth
114
+ isOtherMonth: otherMonth,
115
+ allowReverse: allowReverse
95
116
  };
96
117
  });
97
118
  });