@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.
@@ -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
- if (mask.partMap[i].pattern.length > MONTH_PART_WITH_WORDS_THRESHOLD) {
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 month = parseToInt(this.getInvalidDatePartValue(symbol) + JS_MONTH_OFFSET).toString();
157
- const formattedMonth = padZero(Math.abs(mask.partMap[i].pattern.length - month.length)) + month;
158
- partiallyInvalidText += formattedMonth;
159
- i += Math.max(0, formattedMonth.length - 1);
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
- partiallyInvalidText += this.getInvalidDatePartValue(symbol);
169
- i += Math.max(0, this.getInvalidDatePartValue(symbol).toString().length - 1);
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
- let currentInvalidDatePartValue = 0;
283
- if (!this.autoCorrectParts) {
284
- const isMonth = symbol === "M";
285
- const isDay = symbol === "d" || symbol === "E";
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 invalidDatePart = invalidDateParts[symbol];
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
- hour += offset;
309
- break;
310
- case 'm':
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) && this.getExisting(symbol)) {
324
- // do not cycle months
325
- this.setExisting(symbol, false);
326
- return;
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
- literal: x.pattern
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 = rawTextValue.startsWith(literal);
595
- const rawValueEndsWithLiteral = rawTextValue.endsWith(literal);
596
- const rawValueHasConsecutiveLiterals = rawTextValue.indexOf(literal + literal) >= 0;
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 datePartIndex = 0;
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
- const rawInputChar = rawTextValue[i];
632
- if (rawInputChar !== baseDate[i] && rawInputChar === datePartsLiterals[datePartIndex].literal) {
633
- outOfDatePartBounds = true;
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 ? currentChar : (current.substring(i) + currentChar);
705
- if (!tryParse && isInCaretMode) {
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 (this.date && parsedDate.getDate() !== this.value.getDate()) {
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 patternSatisfied = (leadingZero + (unpadZero(middle) || currentChar).length) >= patternLength;
738
- const switchToNext = peekDate === null || patternSatisfied;
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
- resultText = text[formatSymbolIndex] + resultText;
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
- while (formatSymbolIndex >= 0 && symbol === format[formatSymbolIndex]) {
955
- formatSymbolIndex--;
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
- const segmentText = text.substr(formatSymbolIndex, mask.partMap[formatSymbolIndex].pattern.length);
964
- resultText = segmentText + resultText;
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 isDate = (value) => isPresent(value) && value.getTime && isNumber(value.getTime());
117
+ export const isValidDate = (value) => isPresent(value) && value.getTime && isNumber(value.getTime());