@progress/kendo-dateinputs-common 0.2.0-dev.202301061353 → 0.2.0-dev.202301130811
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.
- package/CODEOWNERS +2 -0
- package/dist/cdn/js/kendo-dateinputs-common.js +1 -1
- package/dist/cdn/main.js +1 -1
- package/dist/es/common/dateobject.js +280 -161
- package/dist/es/common/utils.js +1 -1
- package/dist/es/dateinput/dateinput.js +115 -46
- package/dist/es/dateinput/utils.js +10 -14
- package/dist/es2015/common/dateobject.js +280 -161
- package/dist/es2015/common/utils.js +1 -1
- package/dist/es2015/dateinput/dateinput.js +114 -45
- package/dist/es2015/dateinput/utils.js +10 -14
- package/dist/npm/common/dateobject.d.ts +6 -1
- package/dist/npm/common/dateobject.js +279 -160
- package/dist/npm/common/utils.d.ts +1 -1
- package/dist/npm/common/utils.js +1 -1
- package/dist/npm/dateinput/dateinput.d.ts +13 -2
- package/dist/npm/dateinput/dateinput.js +114 -45
- package/dist/npm/dateinput/utils.js +10 -14
- package/dist/systemjs/kendo-dateinputs-common.js +1 -1
- package/global-setup.js +4 -0
- package/jest.config.js +9 -0
- package/package.json +4 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { addMonths, cloneDate, createDate, isEqual, getDate, lastDayOfMonth } from '@progress/kendo-date-math';
|
|
2
2
|
import { Mask } from './mask';
|
|
3
3
|
import { dateSymbolMap, padZero, unpadZero } from '../dateinput/utils';
|
|
4
|
-
import { extend, isPresent, cropTwoDigitYear, setYears, parseToInt, clamp, areDatePartsEqualTo, isNumber } from './utils';
|
|
4
|
+
import { extend, isPresent, cropTwoDigitYear, setYears, parseToInt, clamp, areDatePartsEqualTo, isNumber, isValidDate } from './utils';
|
|
5
5
|
import { Constants } from './constants';
|
|
6
6
|
const PREVIOUS_CENTURY_BASE = 1900;
|
|
7
7
|
const CURRENT_CENTURY_BASE = 2000;
|
|
@@ -147,16 +147,18 @@ export class DateObject {
|
|
|
147
147
|
partiallyInvalidText += text[i];
|
|
148
148
|
}
|
|
149
149
|
else if (this.getInvalidDatePartValue(symbol)) {
|
|
150
|
+
const partsForSegment = this.getPartsForSegment(mask, i);
|
|
150
151
|
if (symbol === "M") {
|
|
151
|
-
|
|
152
|
+
const datePartText = (parseToInt(this.getInvalidDatePartValue(symbol)) + JS_MONTH_OFFSET).toString();
|
|
153
|
+
if (partsForSegment.length > MONTH_PART_WITH_WORDS_THRESHOLD) {
|
|
152
154
|
partiallyInvalidText += formattedDates[symbol][i];
|
|
153
155
|
}
|
|
154
156
|
else {
|
|
155
157
|
if (this.getInvalidDatePartValue(symbol)) {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
i +=
|
|
158
|
+
const formattedDatePart = padZero(partsForSegment.length - datePartText.length) + datePartText;
|
|
159
|
+
partiallyInvalidText += formattedDatePart;
|
|
160
|
+
// add -1 as the first character in the segment is at index i
|
|
161
|
+
i += partsForSegment.length - 1;
|
|
160
162
|
}
|
|
161
163
|
else {
|
|
162
164
|
partiallyInvalidText += formattedDates[symbol][i];
|
|
@@ -165,8 +167,11 @@ export class DateObject {
|
|
|
165
167
|
}
|
|
166
168
|
else {
|
|
167
169
|
if (this.getInvalidDatePartValue(symbol)) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
const datePartText = this.getInvalidDatePartValue(symbol).toString();
|
|
171
|
+
const formattedDatePart = padZero(partsForSegment.length - datePartText.length) + datePartText;
|
|
172
|
+
partiallyInvalidText += formattedDatePart;
|
|
173
|
+
// add -1 as the first character in the segment is at index i
|
|
174
|
+
i += partsForSegment.length - 1;
|
|
170
175
|
}
|
|
171
176
|
else {
|
|
172
177
|
partiallyInvalidText += formattedDates[symbol][i];
|
|
@@ -275,16 +280,18 @@ export class DateObject {
|
|
|
275
280
|
}
|
|
276
281
|
}
|
|
277
282
|
modifyPart(symbol, offset) {
|
|
283
|
+
if (!isPresent(symbol) || !isPresent(offset) || offset === 0) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
278
286
|
let newValue = cloneDate(this.value);
|
|
279
|
-
let originalValue = cloneDate(this.value);
|
|
280
287
|
let timeModified = false;
|
|
281
288
|
let invalidDateFound;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
289
|
+
const isMonth = symbol === "M";
|
|
290
|
+
const isDay = symbol === "d" || symbol === "E";
|
|
291
|
+
const symbolExists = this.getExisting(symbol);
|
|
292
|
+
if (!this.autoCorrectParts && (isDay || isMonth)) {
|
|
286
293
|
const invalidDateParts = this._partiallyInvalidDate.invalidDateParts || {};
|
|
287
|
-
const
|
|
294
|
+
const invalidDatePartValue = this.getInvalidDatePartValue(symbol);
|
|
288
295
|
let year = invalidDateParts.y.value || newValue.getFullYear();
|
|
289
296
|
let month = invalidDateParts.M.value || newValue.getMonth();
|
|
290
297
|
let day = invalidDateParts.d.value || invalidDateParts.E.value || newValue.getDate();
|
|
@@ -303,33 +310,61 @@ export class DateObject {
|
|
|
303
310
|
case 'E':
|
|
304
311
|
day += offset;
|
|
305
312
|
break;
|
|
306
|
-
case 'h':
|
|
307
|
-
case 'H':
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
case '
|
|
311
|
-
minutes += offset;
|
|
312
|
-
break;
|
|
313
|
-
case 's':
|
|
314
|
-
seconds += offset;
|
|
315
|
-
break;
|
|
316
|
-
case 'S':
|
|
317
|
-
milliseconds += offset;
|
|
318
|
-
break;
|
|
319
|
-
// case 'a': newValue.setHours(newValue.getHours() + (12 * offset)); timeModified = true; break;
|
|
313
|
+
// case 'h':
|
|
314
|
+
// case 'H': hour += offset; break;
|
|
315
|
+
// case 'm': minutes += offset; break;
|
|
316
|
+
// case 's': seconds += offset; break;
|
|
317
|
+
// case 'S': milliseconds += offset; break;
|
|
320
318
|
default: break;
|
|
321
319
|
}
|
|
322
320
|
if (symbol === "M") {
|
|
323
|
-
if ((month < 0 || month > 11)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
321
|
+
if ((month < 0 || month > 11)) {
|
|
322
|
+
if (symbolExists) {
|
|
323
|
+
this.setExisting(symbol, false);
|
|
324
|
+
this.resetInvalidDateSymbol(symbol);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (!symbolExists) {
|
|
329
|
+
if (month < 0) {
|
|
330
|
+
month = clamp(11 + ((month % 11) + 1), 0, 11);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
const monthValue = isPresent(invalidDatePartValue) ?
|
|
334
|
+
month :
|
|
335
|
+
((offset - JS_MONTH_OFFSET) % 12);
|
|
336
|
+
month = clamp(monthValue, 0, 11);
|
|
337
|
+
}
|
|
338
|
+
month = clamp(month, 0, 11);
|
|
339
|
+
}
|
|
340
|
+
month = clamp(month, 0, 11);
|
|
341
|
+
}
|
|
342
|
+
else if (symbol === "d") {
|
|
343
|
+
if (symbolExists) {
|
|
344
|
+
if (day <= 0 || day > 31) {
|
|
345
|
+
this.setExisting(symbol, false);
|
|
346
|
+
this.resetInvalidDateSymbol(symbol);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
else if (!symbolExists) {
|
|
351
|
+
if (isPresent(invalidDatePartValue)) {
|
|
352
|
+
if (day <= 0 || day > 31) {
|
|
353
|
+
this.setExisting(symbol, false);
|
|
354
|
+
this.resetInvalidDateSymbol(symbol);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (offset < 0) {
|
|
359
|
+
const dayValue = isPresent(invalidDatePartValue) ? day : 1 + (31 - Math.abs(offset % 31));
|
|
360
|
+
day = clamp(dayValue, 1, 31);
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
const dayValue = isPresent(invalidDatePartValue) ? day : offset % 31;
|
|
364
|
+
day = clamp(dayValue, 1, 31);
|
|
365
|
+
}
|
|
366
|
+
day = clamp(day, 1, 31);
|
|
327
367
|
}
|
|
328
|
-
// const mask = this.dateFormatString(this.value, this.format);
|
|
329
|
-
// const monthPart = mask.partMap.filter(x => x.type === "month");
|
|
330
|
-
// if (monthPart && monthPart[0] && monthPart[0].pattern.length > MONTH_PART_WITH_WORDS_THRESHOLD) {
|
|
331
|
-
month = (12 + month) % 12;
|
|
332
|
-
// }
|
|
333
368
|
}
|
|
334
369
|
const dateCandidate = createDate(year, month, day, hour, minutes, seconds, milliseconds);
|
|
335
370
|
const newValueCandidate = isMonth || isDay ?
|
|
@@ -426,92 +461,6 @@ export class DateObject {
|
|
|
426
461
|
this.setExisting(symbol, false);
|
|
427
462
|
}
|
|
428
463
|
}
|
|
429
|
-
else {
|
|
430
|
-
// this.modifyDateSymbol()
|
|
431
|
-
switch (symbol) {
|
|
432
|
-
case 'y':
|
|
433
|
-
newValue.setFullYear(newValue.getFullYear() + offset);
|
|
434
|
-
break;
|
|
435
|
-
case 'M':
|
|
436
|
-
newValue = addMonths(this.value, offset);
|
|
437
|
-
break;
|
|
438
|
-
case 'd':
|
|
439
|
-
case 'E':
|
|
440
|
-
newValue.setDate(newValue.getDate() + offset);
|
|
441
|
-
break;
|
|
442
|
-
case 'h':
|
|
443
|
-
case 'H':
|
|
444
|
-
newValue.setHours(newValue.getHours() + offset);
|
|
445
|
-
timeModified = true;
|
|
446
|
-
break;
|
|
447
|
-
case 'm':
|
|
448
|
-
newValue.setMinutes(newValue.getMinutes() + offset);
|
|
449
|
-
timeModified = true;
|
|
450
|
-
break;
|
|
451
|
-
case 's':
|
|
452
|
-
newValue.setSeconds(newValue.getSeconds() + offset);
|
|
453
|
-
timeModified = true;
|
|
454
|
-
break;
|
|
455
|
-
case "S":
|
|
456
|
-
newValue.setMilliseconds(newValue.getMilliseconds() + offset);
|
|
457
|
-
break;
|
|
458
|
-
case 'a':
|
|
459
|
-
newValue.setHours(newValue.getHours() + (12 * offset));
|
|
460
|
-
timeModified = true;
|
|
461
|
-
break;
|
|
462
|
-
default: break;
|
|
463
|
-
}
|
|
464
|
-
invalidDateFound = true;
|
|
465
|
-
if (invalidDatePart && invalidDatePart.value) {
|
|
466
|
-
currentInvalidDatePartValue = parseToInt(invalidDatePart.value);
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
if (!isPresent(invalidDatePart.value)) {
|
|
470
|
-
newValue = cloneDate(originalValue);
|
|
471
|
-
// this.modifyDateSymbol()
|
|
472
|
-
switch (symbol) {
|
|
473
|
-
case 'y':
|
|
474
|
-
currentInvalidDatePartValue = originalValue.getFullYear();
|
|
475
|
-
break;
|
|
476
|
-
case 'M':
|
|
477
|
-
currentInvalidDatePartValue = originalValue.getMonth();
|
|
478
|
-
break;
|
|
479
|
-
case 'd':
|
|
480
|
-
case 'E':
|
|
481
|
-
currentInvalidDatePartValue = originalValue.getDate();
|
|
482
|
-
break;
|
|
483
|
-
case 'h':
|
|
484
|
-
case 'H':
|
|
485
|
-
currentInvalidDatePartValue = originalValue.getHours();
|
|
486
|
-
break;
|
|
487
|
-
case 'm':
|
|
488
|
-
currentInvalidDatePartValue = originalValue.getMinutes();
|
|
489
|
-
break;
|
|
490
|
-
case 's':
|
|
491
|
-
currentInvalidDatePartValue = originalValue.getSeconds();
|
|
492
|
-
break;
|
|
493
|
-
case 'S':
|
|
494
|
-
currentInvalidDatePartValue = originalValue.getMilliseconds();
|
|
495
|
-
break;
|
|
496
|
-
// case 'a': newValue.setHours(newValue.getHours() + (12 * offset)); timeModified = true; break;
|
|
497
|
-
default: break;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
else {
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
let invalidDatePartValue = Math.max(0, currentInvalidDatePartValue + offset);
|
|
504
|
-
if (symbol !== "y") {
|
|
505
|
-
invalidDatePartValue = clamp(currentInvalidDatePartValue + offset, 0, 99);
|
|
506
|
-
}
|
|
507
|
-
this.setInvalidDatePart(symbol, {
|
|
508
|
-
value: invalidDatePartValue,
|
|
509
|
-
date: cloneDate(newValue),
|
|
510
|
-
startDateOffset: (this.getInvalidDatePart(symbol).startDateOffset || 0) + offset,
|
|
511
|
-
startDate: cloneDate(this.value)
|
|
512
|
-
});
|
|
513
|
-
this.setExisting(symbol, false);
|
|
514
|
-
}
|
|
515
464
|
}
|
|
516
465
|
else {
|
|
517
466
|
switch (symbol) {
|
|
@@ -568,7 +517,7 @@ export class DateObject {
|
|
|
568
517
|
/**
|
|
569
518
|
* @hidden
|
|
570
519
|
*/
|
|
571
|
-
parsePart({ symbol, currentChar, resetSegmentValue, cycleSegmentValue, rawTextValue, isDeleting }) {
|
|
520
|
+
parsePart({ symbol, currentChar, resetSegmentValue, cycleSegmentValue, rawTextValue: rawInputValue, isDeleting, originalFormat }) {
|
|
572
521
|
const isInCaretMode = !cycleSegmentValue;
|
|
573
522
|
const dateParts = this.dateFormatString(this.value, this.format);
|
|
574
523
|
const datePartsLiterals = dateParts.partMap
|
|
@@ -576,9 +525,20 @@ export class DateObject {
|
|
|
576
525
|
.map((x, index) => {
|
|
577
526
|
return {
|
|
578
527
|
datePartIndex: index,
|
|
579
|
-
|
|
528
|
+
type: x.type,
|
|
529
|
+
pattern: x.pattern,
|
|
530
|
+
literal: ""
|
|
580
531
|
};
|
|
581
532
|
});
|
|
533
|
+
for (let i = 0; i < datePartsLiterals.length; i++) {
|
|
534
|
+
const datePart = datePartsLiterals[i];
|
|
535
|
+
for (let j = 0; j < datePart.pattern.length; j++) {
|
|
536
|
+
if (datePartsLiterals[i + j]) {
|
|
537
|
+
datePartsLiterals[i + j].literal = datePart.pattern[j];
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
i += datePart.pattern.length - 1;
|
|
541
|
+
}
|
|
582
542
|
let shouldResetPart = isInCaretMode && symbol === "M" && dateParts.partMap
|
|
583
543
|
.filter(x => x.type === "month")
|
|
584
544
|
.some(x => x.pattern.length > MONTH_PART_WITH_WORDS_THRESHOLD);
|
|
@@ -591,9 +551,9 @@ export class DateObject {
|
|
|
591
551
|
if (isInCaretMode) {
|
|
592
552
|
for (let i = 0; i < datePartsLiterals.length; i++) {
|
|
593
553
|
const literal = datePartsLiterals[i].literal;
|
|
594
|
-
const rawValueStartsWithLiteral =
|
|
595
|
-
const rawValueEndsWithLiteral =
|
|
596
|
-
const rawValueHasConsecutiveLiterals =
|
|
554
|
+
const rawValueStartsWithLiteral = rawInputValue.startsWith(literal);
|
|
555
|
+
const rawValueEndsWithLiteral = rawInputValue.endsWith(literal);
|
|
556
|
+
const rawValueHasConsecutiveLiterals = rawInputValue.indexOf(literal + literal) >= 0;
|
|
597
557
|
if (rawValueStartsWithLiteral || rawValueEndsWithLiteral || rawValueHasConsecutiveLiterals) {
|
|
598
558
|
this.resetLeadingZero();
|
|
599
559
|
this.setExisting(symbol, false);
|
|
@@ -616,38 +576,82 @@ export class DateObject {
|
|
|
616
576
|
let prefix = '';
|
|
617
577
|
let current = '';
|
|
618
578
|
let datePartText = '';
|
|
579
|
+
let basePrefix = '';
|
|
580
|
+
let baseSuffix = '';
|
|
619
581
|
let suffix = '';
|
|
582
|
+
const datePartStartIndex = originalFormat.indexOf(symbol);
|
|
583
|
+
const datePartEndIndex = originalFormat.lastIndexOf(symbol);
|
|
584
|
+
const segmentLength = datePartEndIndex - datePartStartIndex + 1;
|
|
585
|
+
const hasFixedFormat = (this.format === baseFormat) ||
|
|
586
|
+
(this.format === originalFormat) ||
|
|
587
|
+
(this.format.length === originalFormat.length);
|
|
620
588
|
if (isInCaretMode) {
|
|
621
|
-
let
|
|
622
|
-
let outOfDatePartBounds = false;
|
|
589
|
+
let processedSegmentCharsCount = 0;
|
|
623
590
|
for (let i = 0; i < baseDate.length; i++) {
|
|
624
|
-
const datePartLiteral = datePartsLiterals[datePartIndex];
|
|
625
|
-
if (datePartLiteral && datePartLiteral === baseDate[i]) {
|
|
626
|
-
datePartIndex++;
|
|
627
|
-
}
|
|
628
591
|
if (baseFormat[i] === symbol) {
|
|
629
592
|
const existing = this.getExisting(symbol);
|
|
630
593
|
current += existing ? baseDate[i] : '0';
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
else if (!outOfDatePartBounds) {
|
|
636
|
-
if (rawInputChar === undefined) {
|
|
637
|
-
const formatOffset = Math.abs(this.format.length - baseFormat.length);
|
|
638
|
-
datePartText += rawTextValue[i - formatOffset] || '';
|
|
639
|
-
}
|
|
640
|
-
else {
|
|
641
|
-
datePartText += rawInputChar || '';
|
|
594
|
+
if (isDeleting) {
|
|
595
|
+
// when deleting, process (segmentLength - 1) chars
|
|
596
|
+
if (processedSegmentCharsCount < segmentLength - 1) {
|
|
597
|
+
datePartText += rawInputValue[i] || "";
|
|
642
598
|
}
|
|
599
|
+
processedSegmentCharsCount++;
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
datePartText += rawInputValue[i] || "";
|
|
643
603
|
}
|
|
644
604
|
replaced = true;
|
|
645
605
|
}
|
|
646
606
|
else if (!replaced) {
|
|
647
607
|
prefix += baseDate[i];
|
|
608
|
+
basePrefix += baseDate[i];
|
|
648
609
|
}
|
|
649
610
|
else {
|
|
650
611
|
suffix += baseDate[i];
|
|
612
|
+
baseSuffix += baseDate[i];
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (hasFixedFormat) {
|
|
616
|
+
if (originalFormat.length < rawInputValue.length) {
|
|
617
|
+
datePartText += currentChar;
|
|
618
|
+
}
|
|
619
|
+
if (datePartText.length > segmentLength) {
|
|
620
|
+
return extend(parseResult, { value: null, switchToNext: false });
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
processedSegmentCharsCount = 0;
|
|
625
|
+
current = "";
|
|
626
|
+
datePartText = "";
|
|
627
|
+
prefix = "";
|
|
628
|
+
suffix = "";
|
|
629
|
+
replaced = false;
|
|
630
|
+
for (let i = 0; i < originalFormat.length; i++) {
|
|
631
|
+
if (originalFormat[i] === symbol) {
|
|
632
|
+
const existing = this.getExisting(symbol);
|
|
633
|
+
current += existing ? baseDate[i] || "" : '0';
|
|
634
|
+
if (isDeleting) {
|
|
635
|
+
// when deleting, process (segmentLength - 1) chars
|
|
636
|
+
if (processedSegmentCharsCount < segmentLength - 1) {
|
|
637
|
+
datePartText += rawInputValue[i] || "";
|
|
638
|
+
}
|
|
639
|
+
processedSegmentCharsCount++;
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
datePartText += rawInputValue[i] || "";
|
|
643
|
+
}
|
|
644
|
+
replaced = true;
|
|
645
|
+
}
|
|
646
|
+
else if (!replaced) {
|
|
647
|
+
prefix += rawInputValue[i] || "";
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
suffix += rawInputValue[i] || "";
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (originalFormat.length < rawInputValue.length) {
|
|
654
|
+
datePartText += currentChar;
|
|
651
655
|
}
|
|
652
656
|
}
|
|
653
657
|
}
|
|
@@ -682,10 +686,6 @@ export class DateObject {
|
|
|
682
686
|
}
|
|
683
687
|
const partPattern = this.partPattern(dateParts.partMap, symbol);
|
|
684
688
|
const patternValue = partPattern ? partPattern.pattern : null;
|
|
685
|
-
if (isInCaretMode && isDeleting) {
|
|
686
|
-
const padPrefix = padZero(Math.abs(current.length - datePartText.length));
|
|
687
|
-
current = padPrefix + datePartText;
|
|
688
|
-
}
|
|
689
689
|
if (isInCaretMode) {
|
|
690
690
|
if (isDeleting && !datePartText) {
|
|
691
691
|
this.setExisting(symbol, false);
|
|
@@ -701,14 +701,30 @@ export class DateObject {
|
|
|
701
701
|
if (!this.autoCorrectParts) {
|
|
702
702
|
tryParse = false;
|
|
703
703
|
}
|
|
704
|
-
let middle = resetSegmentValue ?
|
|
705
|
-
|
|
704
|
+
let middle = resetSegmentValue ?
|
|
705
|
+
currentChar :
|
|
706
|
+
isInCaretMode ?
|
|
707
|
+
datePartText :
|
|
708
|
+
(current.substring(i) + currentChar);
|
|
709
|
+
if (isInCaretMode) {
|
|
706
710
|
// try to make an exact match as there will be only 1 attempt
|
|
711
|
+
tryParse = false;
|
|
707
712
|
middle = unpadZero(middle);
|
|
708
713
|
}
|
|
709
714
|
let middleNumber = parseInt(middle, 10);
|
|
710
715
|
const candidateDateString = prefix + middle + suffix;
|
|
711
716
|
parsedDate = this.intl.parseDate(candidateDateString, this.format, this.localeId);
|
|
717
|
+
if (isInCaretMode && !hasFixedFormat && !isValidDate(parsedDate)) {
|
|
718
|
+
// if part of the date is not available, e.g. "d"
|
|
719
|
+
// but an expanded format like "F" is used
|
|
720
|
+
// the element value can be "EEEE, February 1, 2022 3:04:05 AM"
|
|
721
|
+
// which is not parsable by intl
|
|
722
|
+
// use the base prefix and suffix, e.g. convert the candidate date string
|
|
723
|
+
// to "Thursday, February 1, 2022 3:04:05 AM"
|
|
724
|
+
// as "EEEE, February..." is not parsable
|
|
725
|
+
parsedDate = this.intl.parseDate(basePrefix + middle + baseSuffix, this.format, this.localeId);
|
|
726
|
+
datePartText = middle;
|
|
727
|
+
}
|
|
712
728
|
const isCurrentCharParsable = !isNaN(parseInt(currentChar, 10)) || (isInCaretMode && isDeleting && currentChar === "");
|
|
713
729
|
if (!parsedDate && !isNaN(middleNumber) && isCurrentCharParsable) {
|
|
714
730
|
if (symbol === MONTH_SYMBOL && !month) {
|
|
@@ -724,23 +740,47 @@ export class DateObject {
|
|
|
724
740
|
}
|
|
725
741
|
if (symbol === 'y') {
|
|
726
742
|
parsedDate = createDate(parseInt(middle, 10), this.month ? this.value.getMonth() : 0, this.date ? this.value.getDate() : 1, this.hours ? this.value.getHours() : 0, this.minutes ? this.value.getMinutes() : 0, this.seconds ? this.value.getSeconds() : 0, this.milliseconds ? this.value.getMilliseconds() : 0);
|
|
727
|
-
if (
|
|
743
|
+
if (((isInCaretMode && isValidDate(parsedDate)) ||
|
|
744
|
+
(!isInCaretMode && parsedDate)) && this.date && parsedDate.getDate() !== this.value.getDate()) {
|
|
728
745
|
parsedDate = lastDayOfMonth(addMonths(parsedDate, -1));
|
|
729
746
|
}
|
|
730
747
|
}
|
|
731
748
|
}
|
|
732
|
-
if (parsedDate) {
|
|
749
|
+
if ((isInCaretMode && isValidDate(parsedDate)) || (!isInCaretMode && parsedDate)) {
|
|
733
750
|
// move to next segment if the part will overflow with next char
|
|
734
751
|
// when start from empty date (01, then 010), padded zeros should be trimmed
|
|
735
752
|
const peekDate = this.intl.parseDate(`${prefix}${this.peek(middle, patternValue)}${suffix}`, this.format, this.localeId);
|
|
736
753
|
const patternLength = this.patternLength(patternValue) || patternValue.length;
|
|
737
|
-
const
|
|
738
|
-
const
|
|
754
|
+
const leadingZeroOffset = (this.leadingZero || {})[symbol] || 0;
|
|
755
|
+
const patternSatisfied = (leadingZeroOffset + (unpadZero(middle) || currentChar).length) >= patternLength;
|
|
756
|
+
let switchToNext = peekDate === null ||
|
|
757
|
+
(leadingZero[symbol] && patternValue.length <= middle.length) ||
|
|
758
|
+
patternSatisfied;
|
|
739
759
|
if (this.shouldNormalizeCentury()) {
|
|
740
760
|
parsedDate = this.normalizeCentury(parsedDate);
|
|
741
761
|
}
|
|
742
762
|
this._value = parsedDate;
|
|
743
763
|
this.setExisting(symbol, true);
|
|
764
|
+
if (isInCaretMode && switchToNext) {
|
|
765
|
+
if (symbol === "M") {
|
|
766
|
+
if (segmentLength <= MONTH_PART_WITH_WORDS_THRESHOLD) {
|
|
767
|
+
const datePartValue = parseToInt(datePartText);
|
|
768
|
+
if (datePartValue >= 2) {
|
|
769
|
+
switchToNext = true;
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
switchToNext = false;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
switchToNext = switchToNext ?
|
|
778
|
+
hasFixedFormat ?
|
|
779
|
+
datePartText.length === segmentLength :
|
|
780
|
+
datePartText.length > segmentLength :
|
|
781
|
+
switchToNext;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
744
784
|
return extend(parseResult, { value: this.value, switchToNext: switchToNext });
|
|
745
785
|
}
|
|
746
786
|
}
|
|
@@ -763,6 +803,9 @@ export class DateObject {
|
|
|
763
803
|
this.leadingZero = !this.isAbbrMonth(dateParts.partMap, symbol) ? { [symbol]: true } : null;
|
|
764
804
|
this.setExisting(symbol, false);
|
|
765
805
|
}
|
|
806
|
+
if (isInCaretMode && datePartText.length > segmentLength) {
|
|
807
|
+
return extend(parseResult, { value: null, switchToNext: false });
|
|
808
|
+
}
|
|
766
809
|
if (!this.autoCorrectParts) {
|
|
767
810
|
this.setExisting(symbol, false);
|
|
768
811
|
// todo check if string is better
|
|
@@ -778,11 +821,14 @@ export class DateObject {
|
|
|
778
821
|
}
|
|
779
822
|
if (isNumber(datePartValue)) {
|
|
780
823
|
const newDate = this.modifyDateSymbolWithValue(this.value, symbol, datePartValue);
|
|
824
|
+
// if (!isEqual(newDate, this.value)) {
|
|
825
|
+
this.setExisting(symbol, false);
|
|
781
826
|
this.setInvalidDatePart(symbol, {
|
|
782
827
|
value: datePartValue,
|
|
783
828
|
date: cloneDate(newDate),
|
|
784
829
|
startDate: this._partiallyInvalidDate.startDate || cloneDate(this.value)
|
|
785
830
|
});
|
|
831
|
+
// }
|
|
786
832
|
}
|
|
787
833
|
}
|
|
788
834
|
return extend(parseResult, { value: null, switchToNext: false });
|
|
@@ -944,24 +990,68 @@ export class DateObject {
|
|
|
944
990
|
let resultText = '';
|
|
945
991
|
let resultFormat = '';
|
|
946
992
|
let format = mask.symbols;
|
|
993
|
+
let processTextSymbolsEnded = false;
|
|
994
|
+
let ignoreFormatSymbolsCount = 0;
|
|
995
|
+
const formattedDates = this.getFormattedInvalidDates(format);
|
|
947
996
|
for (let formatSymbolIndex = format.length - 1; formatSymbolIndex >= 0; formatSymbolIndex--) {
|
|
997
|
+
const partsForSegment = this.getPartsForSegment(mask, formatSymbolIndex);
|
|
948
998
|
if (this.knownParts.indexOf(format[formatSymbolIndex]) === -1 || this.getExisting(format[formatSymbolIndex])) {
|
|
949
|
-
|
|
999
|
+
if (this.autoCorrectParts) {
|
|
1000
|
+
resultText = text[formatSymbolIndex] + resultText;
|
|
1001
|
+
}
|
|
1002
|
+
else {
|
|
1003
|
+
if (text.length !== format.length) {
|
|
1004
|
+
if (processTextSymbolsEnded) {
|
|
1005
|
+
resultText = text[formatSymbolIndex] + resultText;
|
|
1006
|
+
}
|
|
1007
|
+
else if (ignoreFormatSymbolsCount > 0) {
|
|
1008
|
+
resultText = text[formatSymbolIndex] + resultText;
|
|
1009
|
+
ignoreFormatSymbolsCount--;
|
|
1010
|
+
if (ignoreFormatSymbolsCount <= 0) {
|
|
1011
|
+
processTextSymbolsEnded = true;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
else {
|
|
1015
|
+
resultText = (text[formatSymbolIndex + text.length - format.length] || "") + resultText;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
resultText = text[formatSymbolIndex] + resultText;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
950
1022
|
resultFormat = format[formatSymbolIndex] + resultFormat;
|
|
951
1023
|
}
|
|
952
1024
|
else {
|
|
953
1025
|
const symbol = format[formatSymbolIndex];
|
|
954
|
-
|
|
955
|
-
|
|
1026
|
+
let formatSymbolIndexModifier = 0;
|
|
1027
|
+
if (this.autoCorrectParts || (!this.autoCorrectParts && !this.getInvalidDatePartValue(symbol))) {
|
|
1028
|
+
while (formatSymbolIndex >= 0 && symbol === format[formatSymbolIndex]) {
|
|
1029
|
+
formatSymbolIndex--;
|
|
1030
|
+
}
|
|
1031
|
+
formatSymbolIndex++;
|
|
956
1032
|
}
|
|
957
|
-
formatSymbolIndex++;
|
|
958
1033
|
if (this.leadingZero && this.leadingZero[symbol]) {
|
|
959
1034
|
resultText = '0' + resultText;
|
|
960
1035
|
}
|
|
961
1036
|
else {
|
|
962
1037
|
if (!this.autoCorrectParts && this.getInvalidDatePartValue(symbol)) {
|
|
963
|
-
|
|
964
|
-
|
|
1038
|
+
let datePartText = this.getInvalidDatePartValue(symbol).toString();
|
|
1039
|
+
if (symbol === "M") {
|
|
1040
|
+
datePartText = (parseToInt(this.getInvalidDatePartValue(symbol)) + JS_MONTH_OFFSET).toString();
|
|
1041
|
+
if (partsForSegment.length > MONTH_PART_WITH_WORDS_THRESHOLD) {
|
|
1042
|
+
resultText = formattedDates[symbol][formatSymbolIndex] + resultText;
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
datePartText = (parseToInt(this.getInvalidDatePartValue(symbol)) + JS_MONTH_OFFSET).toString();
|
|
1046
|
+
resultText = datePartText + resultText;
|
|
1047
|
+
ignoreFormatSymbolsCount = datePartText.length - partsForSegment.length;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
else {
|
|
1051
|
+
resultText = datePartText + resultText;
|
|
1052
|
+
formatSymbolIndexModifier = datePartText.length - 1;
|
|
1053
|
+
ignoreFormatSymbolsCount = datePartText.length - partsForSegment.length;
|
|
1054
|
+
}
|
|
965
1055
|
}
|
|
966
1056
|
else {
|
|
967
1057
|
resultText = this.dateFieldName(mask.partMap[formatSymbolIndex]) + resultText;
|
|
@@ -970,6 +1060,9 @@ export class DateObject {
|
|
|
970
1060
|
while (resultFormat.length < resultText.length) {
|
|
971
1061
|
resultFormat = format[formatSymbolIndex] + resultFormat;
|
|
972
1062
|
}
|
|
1063
|
+
if (formatSymbolIndexModifier !== 0) {
|
|
1064
|
+
formatSymbolIndex = (formatSymbolIndex - formatSymbolIndexModifier) + (text.length - format.length);
|
|
1065
|
+
}
|
|
973
1066
|
}
|
|
974
1067
|
}
|
|
975
1068
|
return { text: resultText, format: resultFormat };
|
|
@@ -1134,4 +1227,30 @@ export class DateObject {
|
|
|
1134
1227
|
markDatePartsAsExisting() {
|
|
1135
1228
|
this.modifyExisting(true);
|
|
1136
1229
|
}
|
|
1230
|
+
/**
|
|
1231
|
+
* @hidden
|
|
1232
|
+
*/
|
|
1233
|
+
getPartsForSegment(mask, partIndex) {
|
|
1234
|
+
const segmentPart = mask.partMap[partIndex];
|
|
1235
|
+
const partsForSegment = [];
|
|
1236
|
+
for (let maskPartIndex = partIndex; maskPartIndex < mask.partMap.length; maskPartIndex++) {
|
|
1237
|
+
const part = mask.partMap[maskPartIndex];
|
|
1238
|
+
if (segmentPart.type === part.type && segmentPart.pattern === part.pattern) {
|
|
1239
|
+
partsForSegment.push(part);
|
|
1240
|
+
}
|
|
1241
|
+
else {
|
|
1242
|
+
break;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
for (let maskPartIndex = partIndex - 1; maskPartIndex >= 0; maskPartIndex--) {
|
|
1246
|
+
const part = mask.partMap[maskPartIndex];
|
|
1247
|
+
if (segmentPart.type === part.type && segmentPart.pattern === part.pattern) {
|
|
1248
|
+
partsForSegment.unshift(part);
|
|
1249
|
+
}
|
|
1250
|
+
else {
|
|
1251
|
+
break;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
return partsForSegment;
|
|
1255
|
+
}
|
|
1137
1256
|
}
|
|
@@ -114,4 +114,4 @@ export const areDatePartsEqualTo = (date, year, month, day, hour, minutes, secon
|
|
|
114
114
|
/**
|
|
115
115
|
* @hidden
|
|
116
116
|
*/
|
|
117
|
-
export const
|
|
117
|
+
export const isValidDate = (value) => isPresent(value) && value.getTime && isNumber(value.getTime());
|