@progress/kendo-dateinputs-common 0.3.3-dev.202404291104 → 0.3.4-dev.202406251149

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.
@@ -3,6 +3,8 @@ import { Mask } from './mask';
3
3
  import { dateSymbolMap, padZero, unpadZero } from '../dateinput/utils';
4
4
  import { extend, isPresent, cropTwoDigitYear, setYears, parseToInt, clamp, areDatePartsEqualTo, isNumber, isValidDate } from './utils';
5
5
  import { Constants } from './constants';
6
+ const MONTH_INDEX_FEBRUARY = 1;
7
+ const DEFAULT_LEAP_YEAR = 2000;
6
8
  const PREVIOUS_CENTURY_BASE = 1900;
7
9
  const CURRENT_CENTURY_BASE = 2000;
8
10
  const SHORT_PATTERN_LENGTH_REGEXP = /d|M|H|h|m|s/;
@@ -35,7 +37,7 @@ export class DateObject {
35
37
  'y': 'y',
36
38
  'S': 'S'
37
39
  };
38
- this._value = getDate(new Date());
40
+ this._value = this.getDefaultDate();
39
41
  this.cycleTime = false;
40
42
  this._partiallyInvalidDate = {
41
43
  startDate: null,
@@ -62,7 +64,7 @@ export class DateObject {
62
64
  autoCorrectParts
63
65
  });
64
66
  if (!value) {
65
- this._value = getDate(new Date());
67
+ this._value = this.getDefaultDate();
66
68
  const sampleFormat = this.dateFormatString(this.value, this.format).symbols;
67
69
  for (let i = 0; i < sampleFormat.length; i++) {
68
70
  this.setExisting(sampleFormat[i], false);
@@ -112,7 +114,7 @@ export class DateObject {
112
114
  }
113
115
  setValue(value) {
114
116
  if (!value) {
115
- this._value = getDate(new Date());
117
+ this._value = this.getDefaultDate();
116
118
  this.modifyExisting(false);
117
119
  }
118
120
  else if (!isEqual(value, this._value)) {
@@ -139,6 +141,23 @@ export class DateObject {
139
141
  }
140
142
  return cloneDate(this.value);
141
143
  }
144
+ /**
145
+ * @hidden
146
+ */
147
+ createDefaultDate() {
148
+ // use the leap year 2000 that has 29th February
149
+ // and a month that has 31 days
150
+ // so that the default date can accommodate maximum date values
151
+ // it is better to use a fixed date instead of new Date()
152
+ // as otherwise the
153
+ return createDate(DEFAULT_LEAP_YEAR, 0, 31);
154
+ }
155
+ /**
156
+ * @hidden
157
+ */
158
+ getDefaultDate() {
159
+ return getDate(this.createDefaultDate());
160
+ }
142
161
  /**
143
162
  * @hidden
144
163
  */
@@ -261,7 +280,7 @@ export class DateObject {
261
280
  // allow 2/29 dates
262
281
  this.year = value;
263
282
  if (value === false) {
264
- this._value.setFullYear(2000);
283
+ this._value.setFullYear(DEFAULT_LEAP_YEAR);
265
284
  }
266
285
  break;
267
286
  case 'M':
@@ -808,17 +827,19 @@ export class DateObject {
808
827
  if ((isInCaretMode && isValidDate(parsedDate)) || (!isInCaretMode && parsedDate)) {
809
828
  // move to next segment if the part will overflow with next char
810
829
  // when start from empty date (01, then 010), padded zeros should be trimmed
811
- const peekedValue = this.peek(middle, patternValue);
812
- const peekedDateString = autoCorrectedPrefixAndSuffix ?
813
- `${basePrefix}${peekedValue}${baseSuffix}` :
814
- `${prefix}${peekedValue}${suffix}`;
815
- const peekedDate = this.intl.parseDate(peekedDateString, this.format, this.localeId);
816
- const leadingZeroOffset = (this.leadingZero || {})[symbol] || 0;
817
- const patternSatisfied = (leadingZeroOffset + unpadZero(middle).length) >= patternLength;
818
- let switchToNext = peekedDate === null ||
819
- (leadingZero[symbol] ?
820
- patternValue.length <= middle.length :
821
- patternSatisfied);
830
+ const peekResult = this.isPeekDateOverflowingDatePart({
831
+ useBasePrefixAndSuffix: autoCorrectedPrefixAndSuffix,
832
+ middle,
833
+ patternValue,
834
+ basePrefix,
835
+ baseSuffix,
836
+ prefix,
837
+ suffix,
838
+ symbol,
839
+ patternLength,
840
+ leadingZero
841
+ });
842
+ let switchToNext = peekResult.switchToNext;
822
843
  if (this.shouldNormalizeCentury()) {
823
844
  parsedDate = this.normalizeCentury(parsedDate);
824
845
  }
@@ -842,6 +863,21 @@ export class DateObject {
842
863
  }
843
864
  if (!this.hasInvalidDatePart()) {
844
865
  this.markDatePartsAsExisting();
866
+ if (!peekResult.peekedDate && peekResult.switchToNext && !this.autoCorrectParts) {
867
+ if (symbol === "M") {
868
+ // skip processing the month
869
+ }
870
+ else if (symbol === "d") {
871
+ if (peekResult.parsedPeekedValue === 30 &&
872
+ this.value.getMonth() === MONTH_INDEX_FEBRUARY) {
873
+ // the peekValue cannot be constructed
874
+ // as there cannot be more than 29 days in February
875
+ // still the segment should not be switched as autoCorrectParts="false"
876
+ // should allow typing "30"
877
+ switchToNext = false;
878
+ }
879
+ }
880
+ }
845
881
  }
846
882
  }
847
883
  return extend(parseResult, { value: this.value, switchToNext: switchToNext });
@@ -869,12 +905,25 @@ export class DateObject {
869
905
  }
870
906
  if (!this.autoCorrectParts) {
871
907
  let datePartValue;
872
- const textToParse = isInCaretMode ? datePartText : middle;
873
- const parsedValue = parseToInt(textToParse);
908
+ let textToParse = isInCaretMode ? datePartText : middle;
909
+ let parsedValue = parseToInt(textToParse);
874
910
  if (isNumber(parsedValue)) {
875
911
  if ((symbol === "d" && (parsedValue <= 0 || parsedValue > 31)) ||
876
912
  (symbol === "M" && (parsedValue < 0 || parsedValue > 11))) {
877
- return extend(parseResult, { value: null, switchToNext: false });
913
+ if (isInCaretMode) {
914
+ return extend(parseResult, {
915
+ value: null,
916
+ switchToNext: false
917
+ });
918
+ }
919
+ else {
920
+ // the value overflows the possible value range
921
+ // thus reset the segment value regardless of the "resetSegmentValue" flag
922
+ // otherwise the input is ignored and you cannot change the value,
923
+ // e.g. "03->(press 2)->02" will not work and the user will be blocked on "03"
924
+ textToParse = currentChar;
925
+ parsedValue = parseToInt(textToParse);
926
+ }
878
927
  }
879
928
  datePartValue = symbol === "M" ?
880
929
  parsedValue - JS_MONTH_OFFSET :
@@ -1005,9 +1054,24 @@ export class DateObject {
1005
1054
  }
1006
1055
  }
1007
1056
  else {
1008
- switchToNext = hasFixedFormat ?
1009
- textToParse.length === segmentLength :
1010
- textToParse.length > segmentLength;
1057
+ if (hasFixedFormat) {
1058
+ const peekDateSwitchToNext = this.isPeekDateOverflowingDatePart({
1059
+ useBasePrefixAndSuffix: !this.autoCorrectParts,
1060
+ middle,
1061
+ patternValue,
1062
+ basePrefix,
1063
+ baseSuffix,
1064
+ prefix,
1065
+ suffix,
1066
+ symbol,
1067
+ patternLength,
1068
+ leadingZero
1069
+ }).switchToNext;
1070
+ switchToNext = peekDateSwitchToNext;
1071
+ }
1072
+ else {
1073
+ switchToNext = textToParse.length > segmentLength;
1074
+ }
1011
1075
  }
1012
1076
  return extend(parseResult, {
1013
1077
  value: null,
@@ -1459,4 +1523,34 @@ export class DateObject {
1459
1523
  }
1460
1524
  return partsForSegment;
1461
1525
  }
1526
+ /**
1527
+ * @hidden
1528
+ */
1529
+ isPeekDateOverflowingDatePart({ useBasePrefixAndSuffix, middle, patternValue, basePrefix, baseSuffix, prefix, suffix, symbol, patternLength, leadingZero }) {
1530
+ // move to next segment if the part will overflow with next char
1531
+ // when start from empty date (01, then 010), padded zeros should be trimmed
1532
+ const peekedValue = this.peek(middle, patternValue);
1533
+ const peekedDateString = useBasePrefixAndSuffix ?
1534
+ `${basePrefix}${peekedValue}${baseSuffix}` :
1535
+ `${prefix}${peekedValue}${suffix}`;
1536
+ const peekedDate = this.intl.parseDate(peekedDateString, this.format, this.localeId);
1537
+ const leadingZeroOffset = (this.leadingZero || {})[symbol] || 0;
1538
+ const patternSatisfied = (leadingZeroOffset + unpadZero(middle).length) >= patternLength;
1539
+ let parsedPeekedValue = parseToInt(peekedValue);
1540
+ if (symbol === "M") {
1541
+ }
1542
+ else if (symbol === "d") {
1543
+ }
1544
+ const switchToNext = peekedDate === null ||
1545
+ (leadingZero[symbol] ?
1546
+ patternValue.length <= middle.length :
1547
+ patternSatisfied);
1548
+ return {
1549
+ peekedDate,
1550
+ peekedDateString,
1551
+ peekedValue,
1552
+ parsedPeekedValue,
1553
+ switchToNext
1554
+ };
1555
+ }
1462
1556
  }
@@ -46,6 +46,14 @@ export declare class DateObject {
46
46
  * @hidden
47
47
  */
48
48
  getValue(): Date;
49
+ /**
50
+ * @hidden
51
+ */
52
+ createDefaultDate(): Date;
53
+ /**
54
+ * @hidden
55
+ */
56
+ getDefaultDate(): Date;
49
57
  /**
50
58
  * @hidden
51
59
  */
@@ -187,4 +195,25 @@ export declare class DateObject {
187
195
  * @hidden
188
196
  */
189
197
  getPartsForSegment(mask: any, partIndex: any): any[];
198
+ /**
199
+ * @hidden
200
+ */
201
+ isPeekDateOverflowingDatePart({ useBasePrefixAndSuffix, middle, patternValue, basePrefix, baseSuffix, prefix, suffix, symbol, patternLength, leadingZero }: {
202
+ useBasePrefixAndSuffix: any;
203
+ middle: any;
204
+ patternValue: any;
205
+ basePrefix: any;
206
+ baseSuffix: any;
207
+ prefix: any;
208
+ suffix: any;
209
+ symbol: any;
210
+ patternLength: any;
211
+ leadingZero: any;
212
+ }): {
213
+ peekedDate: any;
214
+ peekedDateString: string;
215
+ peekedValue: string;
216
+ parsedPeekedValue: number;
217
+ switchToNext: boolean;
218
+ };
190
219
  }
@@ -5,6 +5,8 @@ var mask_1 = require("./mask");
5
5
  var utils_1 = require("../dateinput/utils");
6
6
  var utils_2 = require("./utils");
7
7
  var constants_1 = require("./constants");
8
+ var MONTH_INDEX_FEBRUARY = 1;
9
+ var DEFAULT_LEAP_YEAR = 2000;
8
10
  var PREVIOUS_CENTURY_BASE = 1900;
9
11
  var CURRENT_CENTURY_BASE = 2000;
10
12
  var SHORT_PATTERN_LENGTH_REGEXP = /d|M|H|h|m|s/;
@@ -38,7 +40,7 @@ var DateObject = /** @class */ (function () {
38
40
  'y': 'y',
39
41
  'S': 'S'
40
42
  };
41
- this._value = kendo_date_math_1.getDate(new Date());
43
+ this._value = this.getDefaultDate();
42
44
  this.cycleTime = false;
43
45
  this._partiallyInvalidDate = {
44
46
  startDate: null,
@@ -65,7 +67,7 @@ var DateObject = /** @class */ (function () {
65
67
  autoCorrectParts: autoCorrectParts
66
68
  });
67
69
  if (!value) {
68
- this._value = kendo_date_math_1.getDate(new Date());
70
+ this._value = this.getDefaultDate();
69
71
  var sampleFormat = this.dateFormatString(this.value, this.format).symbols;
70
72
  for (var i = 0; i < sampleFormat.length; i++) {
71
73
  this.setExisting(sampleFormat[i], false);
@@ -123,7 +125,7 @@ var DateObject = /** @class */ (function () {
123
125
  };
124
126
  DateObject.prototype.setValue = function (value) {
125
127
  if (!value) {
126
- this._value = kendo_date_math_1.getDate(new Date());
128
+ this._value = this.getDefaultDate();
127
129
  this.modifyExisting(false);
128
130
  }
129
131
  else if (!kendo_date_math_1.isEqual(value, this._value)) {
@@ -151,6 +153,23 @@ var DateObject = /** @class */ (function () {
151
153
  }
152
154
  return kendo_date_math_1.cloneDate(this.value);
153
155
  };
156
+ /**
157
+ * @hidden
158
+ */
159
+ DateObject.prototype.createDefaultDate = function () {
160
+ // use the leap year 2000 that has 29th February
161
+ // and a month that has 31 days
162
+ // so that the default date can accommodate maximum date values
163
+ // it is better to use a fixed date instead of new Date()
164
+ // as otherwise the
165
+ return kendo_date_math_1.createDate(DEFAULT_LEAP_YEAR, 0, 31);
166
+ };
167
+ /**
168
+ * @hidden
169
+ */
170
+ DateObject.prototype.getDefaultDate = function () {
171
+ return kendo_date_math_1.getDate(this.createDefaultDate());
172
+ };
154
173
  /**
155
174
  * @hidden
156
175
  */
@@ -276,7 +295,7 @@ var DateObject = /** @class */ (function () {
276
295
  // allow 2/29 dates
277
296
  this.year = value;
278
297
  if (value === false) {
279
- this._value.setFullYear(2000);
298
+ this._value.setFullYear(DEFAULT_LEAP_YEAR);
280
299
  }
281
300
  break;
282
301
  case 'M':
@@ -824,17 +843,19 @@ var DateObject = /** @class */ (function () {
824
843
  if ((isInCaretMode && utils_2.isValidDate(parsedDate)) || (!isInCaretMode && parsedDate)) {
825
844
  // move to next segment if the part will overflow with next char
826
845
  // when start from empty date (01, then 010), padded zeros should be trimmed
827
- var peekedValue = this.peek(middle, patternValue);
828
- var peekedDateString = autoCorrectedPrefixAndSuffix ?
829
- "" + basePrefix + peekedValue + baseSuffix :
830
- "" + prefix + peekedValue + suffix;
831
- var peekedDate = this.intl.parseDate(peekedDateString, this.format, this.localeId);
832
- var leadingZeroOffset = (this.leadingZero || {})[symbol] || 0;
833
- var patternSatisfied = (leadingZeroOffset + utils_1.unpadZero(middle).length) >= patternLength;
834
- var switchToNext = peekedDate === null ||
835
- (leadingZero[symbol] ?
836
- patternValue.length <= middle.length :
837
- patternSatisfied);
846
+ var peekResult = this.isPeekDateOverflowingDatePart({
847
+ useBasePrefixAndSuffix: autoCorrectedPrefixAndSuffix,
848
+ middle: middle,
849
+ patternValue: patternValue,
850
+ basePrefix: basePrefix,
851
+ baseSuffix: baseSuffix,
852
+ prefix: prefix,
853
+ suffix: suffix,
854
+ symbol: symbol,
855
+ patternLength: patternLength,
856
+ leadingZero: leadingZero
857
+ });
858
+ var switchToNext = peekResult.switchToNext;
838
859
  if (this.shouldNormalizeCentury()) {
839
860
  parsedDate = this.normalizeCentury(parsedDate);
840
861
  }
@@ -858,6 +879,21 @@ var DateObject = /** @class */ (function () {
858
879
  }
859
880
  if (!this.hasInvalidDatePart()) {
860
881
  this.markDatePartsAsExisting();
882
+ if (!peekResult.peekedDate && peekResult.switchToNext && !this.autoCorrectParts) {
883
+ if (symbol === "M") {
884
+ // skip processing the month
885
+ }
886
+ else if (symbol === "d") {
887
+ if (peekResult.parsedPeekedValue === 30 &&
888
+ this.value.getMonth() === MONTH_INDEX_FEBRUARY) {
889
+ // the peekValue cannot be constructed
890
+ // as there cannot be more than 29 days in February
891
+ // still the segment should not be switched as autoCorrectParts="false"
892
+ // should allow typing "30"
893
+ switchToNext = false;
894
+ }
895
+ }
896
+ }
861
897
  }
862
898
  }
863
899
  return utils_2.extend(parseResult, { value: this.value, switchToNext: switchToNext });
@@ -890,7 +926,20 @@ var DateObject = /** @class */ (function () {
890
926
  if (utils_2.isNumber(parsedValue)) {
891
927
  if ((symbol === "d" && (parsedValue <= 0 || parsedValue > 31)) ||
892
928
  (symbol === "M" && (parsedValue < 0 || parsedValue > 11))) {
893
- return utils_2.extend(parseResult, { value: null, switchToNext: false });
929
+ if (isInCaretMode) {
930
+ return utils_2.extend(parseResult, {
931
+ value: null,
932
+ switchToNext: false
933
+ });
934
+ }
935
+ else {
936
+ // the value overflows the possible value range
937
+ // thus reset the segment value regardless of the "resetSegmentValue" flag
938
+ // otherwise the input is ignored and you cannot change the value,
939
+ // e.g. "03->(press 2)->02" will not work and the user will be blocked on "03"
940
+ textToParse = currentChar;
941
+ parsedValue = utils_2.parseToInt(textToParse);
942
+ }
894
943
  }
895
944
  datePartValue = symbol === "M" ?
896
945
  parsedValue - JS_MONTH_OFFSET :
@@ -1021,9 +1070,24 @@ var DateObject = /** @class */ (function () {
1021
1070
  }
1022
1071
  }
1023
1072
  else {
1024
- switchToNext = hasFixedFormat ?
1025
- textToParse.length === segmentLength :
1026
- textToParse.length > segmentLength;
1073
+ if (hasFixedFormat) {
1074
+ var peekDateSwitchToNext = this.isPeekDateOverflowingDatePart({
1075
+ useBasePrefixAndSuffix: !this.autoCorrectParts,
1076
+ middle: middle,
1077
+ patternValue: patternValue,
1078
+ basePrefix: basePrefix,
1079
+ baseSuffix: baseSuffix,
1080
+ prefix: prefix,
1081
+ suffix: suffix,
1082
+ symbol: symbol,
1083
+ patternLength: patternLength,
1084
+ leadingZero: leadingZero
1085
+ }).switchToNext;
1086
+ switchToNext = peekDateSwitchToNext;
1087
+ }
1088
+ else {
1089
+ switchToNext = textToParse.length > segmentLength;
1090
+ }
1027
1091
  }
1028
1092
  return utils_2.extend(parseResult, {
1029
1093
  value: null,
@@ -1481,6 +1545,37 @@ var DateObject = /** @class */ (function () {
1481
1545
  }
1482
1546
  return partsForSegment;
1483
1547
  };
1548
+ /**
1549
+ * @hidden
1550
+ */
1551
+ DateObject.prototype.isPeekDateOverflowingDatePart = function (_a) {
1552
+ var useBasePrefixAndSuffix = _a.useBasePrefixAndSuffix, middle = _a.middle, patternValue = _a.patternValue, basePrefix = _a.basePrefix, baseSuffix = _a.baseSuffix, prefix = _a.prefix, suffix = _a.suffix, symbol = _a.symbol, patternLength = _a.patternLength, leadingZero = _a.leadingZero;
1553
+ // move to next segment if the part will overflow with next char
1554
+ // when start from empty date (01, then 010), padded zeros should be trimmed
1555
+ var peekedValue = this.peek(middle, patternValue);
1556
+ var peekedDateString = useBasePrefixAndSuffix ?
1557
+ "" + basePrefix + peekedValue + baseSuffix :
1558
+ "" + prefix + peekedValue + suffix;
1559
+ var peekedDate = this.intl.parseDate(peekedDateString, this.format, this.localeId);
1560
+ var leadingZeroOffset = (this.leadingZero || {})[symbol] || 0;
1561
+ var patternSatisfied = (leadingZeroOffset + utils_1.unpadZero(middle).length) >= patternLength;
1562
+ var parsedPeekedValue = utils_2.parseToInt(peekedValue);
1563
+ if (symbol === "M") {
1564
+ }
1565
+ else if (symbol === "d") {
1566
+ }
1567
+ var switchToNext = peekedDate === null ||
1568
+ (leadingZero[symbol] ?
1569
+ patternValue.length <= middle.length :
1570
+ patternSatisfied);
1571
+ return {
1572
+ peekedDate: peekedDate,
1573
+ peekedDateString: peekedDateString,
1574
+ peekedValue: peekedValue,
1575
+ parsedPeekedValue: parsedPeekedValue,
1576
+ switchToNext: switchToNext
1577
+ };
1578
+ };
1484
1579
  return DateObject;
1485
1580
  }());
1486
1581
  exports.DateObject = DateObject;