@progress/kendo-dateinputs-common 0.2.0-dev.202301061341 → 0.2.0-dev.202301101148
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 +124 -39
- package/dist/es/common/utils.js +1 -1
- package/dist/es/dateinput/dateinput.js +86 -34
- package/dist/es/dateinput/utils.js +10 -14
- package/dist/es2015/common/dateobject.js +113 -34
- package/dist/es2015/common/utils.js +1 -1
- package/dist/es2015/dateinput/dateinput.js +85 -33
- package/dist/es2015/dateinput/utils.js +10 -14
- package/dist/npm/common/dateobject.d.ts +2 -1
- package/dist/npm/common/dateobject.js +123 -38
- 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 +85 -33
- 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 +5 -5
|
@@ -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;
|
|
@@ -568,7 +568,7 @@ export class DateObject {
|
|
|
568
568
|
/**
|
|
569
569
|
* @hidden
|
|
570
570
|
*/
|
|
571
|
-
parsePart({ symbol, currentChar, resetSegmentValue, cycleSegmentValue, rawTextValue, isDeleting }) {
|
|
571
|
+
parsePart({ symbol, currentChar, resetSegmentValue, cycleSegmentValue, rawTextValue: rawInputValue, isDeleting, originalFormat }) {
|
|
572
572
|
const isInCaretMode = !cycleSegmentValue;
|
|
573
573
|
const dateParts = this.dateFormatString(this.value, this.format);
|
|
574
574
|
const datePartsLiterals = dateParts.partMap
|
|
@@ -576,9 +576,20 @@ export class DateObject {
|
|
|
576
576
|
.map((x, index) => {
|
|
577
577
|
return {
|
|
578
578
|
datePartIndex: index,
|
|
579
|
-
|
|
579
|
+
type: x.type,
|
|
580
|
+
pattern: x.pattern,
|
|
581
|
+
literal: ""
|
|
580
582
|
};
|
|
581
583
|
});
|
|
584
|
+
for (let i = 0; i < datePartsLiterals.length; i++) {
|
|
585
|
+
const datePart = datePartsLiterals[i];
|
|
586
|
+
for (let j = 0; j < datePart.pattern.length; j++) {
|
|
587
|
+
if (datePartsLiterals[i + j]) {
|
|
588
|
+
datePartsLiterals[i + j].literal = datePart.pattern[j];
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
i += datePart.pattern.length - 1;
|
|
592
|
+
}
|
|
582
593
|
let shouldResetPart = isInCaretMode && symbol === "M" && dateParts.partMap
|
|
583
594
|
.filter(x => x.type === "month")
|
|
584
595
|
.some(x => x.pattern.length > MONTH_PART_WITH_WORDS_THRESHOLD);
|
|
@@ -591,9 +602,9 @@ export class DateObject {
|
|
|
591
602
|
if (isInCaretMode) {
|
|
592
603
|
for (let i = 0; i < datePartsLiterals.length; i++) {
|
|
593
604
|
const literal = datePartsLiterals[i].literal;
|
|
594
|
-
const rawValueStartsWithLiteral =
|
|
595
|
-
const rawValueEndsWithLiteral =
|
|
596
|
-
const rawValueHasConsecutiveLiterals =
|
|
605
|
+
const rawValueStartsWithLiteral = rawInputValue.startsWith(literal);
|
|
606
|
+
const rawValueEndsWithLiteral = rawInputValue.endsWith(literal);
|
|
607
|
+
const rawValueHasConsecutiveLiterals = rawInputValue.indexOf(literal + literal) >= 0;
|
|
597
608
|
if (rawValueStartsWithLiteral || rawValueEndsWithLiteral || rawValueHasConsecutiveLiterals) {
|
|
598
609
|
this.resetLeadingZero();
|
|
599
610
|
this.setExisting(symbol, false);
|
|
@@ -616,38 +627,82 @@ export class DateObject {
|
|
|
616
627
|
let prefix = '';
|
|
617
628
|
let current = '';
|
|
618
629
|
let datePartText = '';
|
|
630
|
+
let basePrefix = '';
|
|
631
|
+
let baseSuffix = '';
|
|
619
632
|
let suffix = '';
|
|
633
|
+
const datePartStartIndex = originalFormat.indexOf(symbol);
|
|
634
|
+
const datePartEndIndex = originalFormat.lastIndexOf(symbol);
|
|
635
|
+
const segmentLength = datePartEndIndex - datePartStartIndex + 1;
|
|
636
|
+
const hasFixedFormat = (this.format === baseFormat) ||
|
|
637
|
+
(this.format === originalFormat) ||
|
|
638
|
+
(this.format.length === originalFormat.length);
|
|
620
639
|
if (isInCaretMode) {
|
|
621
|
-
let
|
|
622
|
-
let outOfDatePartBounds = false;
|
|
640
|
+
let processedSegmentCharsCount = 0;
|
|
623
641
|
for (let i = 0; i < baseDate.length; i++) {
|
|
624
|
-
const datePartLiteral = datePartsLiterals[datePartIndex];
|
|
625
|
-
if (datePartLiteral && datePartLiteral === baseDate[i]) {
|
|
626
|
-
datePartIndex++;
|
|
627
|
-
}
|
|
628
642
|
if (baseFormat[i] === symbol) {
|
|
629
643
|
const existing = this.getExisting(symbol);
|
|
630
644
|
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 || '';
|
|
645
|
+
if (isDeleting) {
|
|
646
|
+
// when deleting, process (segmentLength - 1) chars
|
|
647
|
+
if (processedSegmentCharsCount < segmentLength - 1) {
|
|
648
|
+
datePartText += rawInputValue[i] || "";
|
|
642
649
|
}
|
|
650
|
+
processedSegmentCharsCount++;
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
datePartText += rawInputValue[i] || "";
|
|
643
654
|
}
|
|
644
655
|
replaced = true;
|
|
645
656
|
}
|
|
646
657
|
else if (!replaced) {
|
|
647
658
|
prefix += baseDate[i];
|
|
659
|
+
basePrefix += baseDate[i];
|
|
648
660
|
}
|
|
649
661
|
else {
|
|
650
662
|
suffix += baseDate[i];
|
|
663
|
+
baseSuffix += baseDate[i];
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
if (hasFixedFormat) {
|
|
667
|
+
if (originalFormat.length < rawInputValue.length) {
|
|
668
|
+
datePartText += currentChar;
|
|
669
|
+
}
|
|
670
|
+
if (datePartText.length > segmentLength) {
|
|
671
|
+
return extend(parseResult, { value: null, switchToNext: false });
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
processedSegmentCharsCount = 0;
|
|
676
|
+
current = "";
|
|
677
|
+
datePartText = "";
|
|
678
|
+
prefix = "";
|
|
679
|
+
suffix = "";
|
|
680
|
+
replaced = false;
|
|
681
|
+
for (let i = 0; i < originalFormat.length; i++) {
|
|
682
|
+
if (originalFormat[i] === symbol) {
|
|
683
|
+
const existing = this.getExisting(symbol);
|
|
684
|
+
current += existing ? baseDate[i] || "" : '0';
|
|
685
|
+
if (isDeleting) {
|
|
686
|
+
// when deleting, process (segmentLength - 1) chars
|
|
687
|
+
if (processedSegmentCharsCount < segmentLength - 1) {
|
|
688
|
+
datePartText += rawInputValue[i] || "";
|
|
689
|
+
}
|
|
690
|
+
processedSegmentCharsCount++;
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
datePartText += rawInputValue[i] || "";
|
|
694
|
+
}
|
|
695
|
+
replaced = true;
|
|
696
|
+
}
|
|
697
|
+
else if (!replaced) {
|
|
698
|
+
prefix += rawInputValue[i] || "";
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
suffix += rawInputValue[i] || "";
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (originalFormat.length < rawInputValue.length) {
|
|
705
|
+
datePartText += currentChar;
|
|
651
706
|
}
|
|
652
707
|
}
|
|
653
708
|
}
|
|
@@ -682,10 +737,6 @@ export class DateObject {
|
|
|
682
737
|
}
|
|
683
738
|
const partPattern = this.partPattern(dateParts.partMap, symbol);
|
|
684
739
|
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
740
|
if (isInCaretMode) {
|
|
690
741
|
if (isDeleting && !datePartText) {
|
|
691
742
|
this.setExisting(symbol, false);
|
|
@@ -701,14 +752,29 @@ export class DateObject {
|
|
|
701
752
|
if (!this.autoCorrectParts) {
|
|
702
753
|
tryParse = false;
|
|
703
754
|
}
|
|
704
|
-
let middle = resetSegmentValue ?
|
|
705
|
-
|
|
755
|
+
let middle = resetSegmentValue ?
|
|
756
|
+
currentChar :
|
|
757
|
+
isInCaretMode ?
|
|
758
|
+
datePartText :
|
|
759
|
+
(current.substring(i) + currentChar);
|
|
760
|
+
if (isInCaretMode) {
|
|
706
761
|
// try to make an exact match as there will be only 1 attempt
|
|
762
|
+
tryParse = false;
|
|
707
763
|
middle = unpadZero(middle);
|
|
708
764
|
}
|
|
709
765
|
let middleNumber = parseInt(middle, 10);
|
|
710
766
|
const candidateDateString = prefix + middle + suffix;
|
|
711
767
|
parsedDate = this.intl.parseDate(candidateDateString, this.format, this.localeId);
|
|
768
|
+
if (isInCaretMode && !hasFixedFormat && !isValidDate(parsedDate)) {
|
|
769
|
+
// if part of the date is not available, e.g. "d"
|
|
770
|
+
// but an expanded format like "F" is used
|
|
771
|
+
// the element value can be "EEEE, February 1, 2022 3:04:05 AM"
|
|
772
|
+
// which is not parsable by intl
|
|
773
|
+
// use the base prefix and suffix, e.g. convert the candidate date string
|
|
774
|
+
// to "Thursday, February 1, 2022 3:04:05 AM"
|
|
775
|
+
// as "EEEE, February..." is not parsable
|
|
776
|
+
parsedDate = this.intl.parseDate(basePrefix + middle + baseSuffix, this.format, this.localeId);
|
|
777
|
+
}
|
|
712
778
|
const isCurrentCharParsable = !isNaN(parseInt(currentChar, 10)) || (isInCaretMode && isDeleting && currentChar === "");
|
|
713
779
|
if (!parsedDate && !isNaN(middleNumber) && isCurrentCharParsable) {
|
|
714
780
|
if (symbol === MONTH_SYMBOL && !month) {
|
|
@@ -724,18 +790,22 @@ export class DateObject {
|
|
|
724
790
|
}
|
|
725
791
|
if (symbol === 'y') {
|
|
726
792
|
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 (
|
|
793
|
+
if (((isInCaretMode && isValidDate(parsedDate)) ||
|
|
794
|
+
(!isInCaretMode && parsedDate)) && this.date && parsedDate.getDate() !== this.value.getDate()) {
|
|
728
795
|
parsedDate = lastDayOfMonth(addMonths(parsedDate, -1));
|
|
729
796
|
}
|
|
730
797
|
}
|
|
731
798
|
}
|
|
732
|
-
if (parsedDate) {
|
|
799
|
+
if ((isInCaretMode && isValidDate(parsedDate)) || (!isInCaretMode && parsedDate)) {
|
|
733
800
|
// move to next segment if the part will overflow with next char
|
|
734
801
|
// when start from empty date (01, then 010), padded zeros should be trimmed
|
|
735
802
|
const peekDate = this.intl.parseDate(`${prefix}${this.peek(middle, patternValue)}${suffix}`, this.format, this.localeId);
|
|
736
803
|
const patternLength = this.patternLength(patternValue) || patternValue.length;
|
|
737
|
-
const
|
|
738
|
-
const
|
|
804
|
+
const leadingZeroOffset = (this.leadingZero || {})[symbol] || 0;
|
|
805
|
+
const patternSatisfied = (leadingZeroOffset + (unpadZero(middle) || currentChar).length) >= patternLength;
|
|
806
|
+
const switchToNext = peekDate === null ||
|
|
807
|
+
(leadingZero[symbol] && patternValue.length <= middle.length) ||
|
|
808
|
+
patternSatisfied;
|
|
739
809
|
if (this.shouldNormalizeCentury()) {
|
|
740
810
|
parsedDate = this.normalizeCentury(parsedDate);
|
|
741
811
|
}
|
|
@@ -763,6 +833,9 @@ export class DateObject {
|
|
|
763
833
|
this.leadingZero = !this.isAbbrMonth(dateParts.partMap, symbol) ? { [symbol]: true } : null;
|
|
764
834
|
this.setExisting(symbol, false);
|
|
765
835
|
}
|
|
836
|
+
if (isInCaretMode && datePartText.length > segmentLength) {
|
|
837
|
+
return extend(parseResult, { value: null, switchToNext: false });
|
|
838
|
+
}
|
|
766
839
|
if (!this.autoCorrectParts) {
|
|
767
840
|
this.setExisting(symbol, false);
|
|
768
841
|
// todo check if string is better
|
|
@@ -778,11 +851,14 @@ export class DateObject {
|
|
|
778
851
|
}
|
|
779
852
|
if (isNumber(datePartValue)) {
|
|
780
853
|
const newDate = this.modifyDateSymbolWithValue(this.value, symbol, datePartValue);
|
|
854
|
+
// if (!isEqual(newDate, this.value)) {
|
|
855
|
+
this.setExisting(symbol, false);
|
|
781
856
|
this.setInvalidDatePart(symbol, {
|
|
782
857
|
value: datePartValue,
|
|
783
858
|
date: cloneDate(newDate),
|
|
784
859
|
startDate: this._partiallyInvalidDate.startDate || cloneDate(this.value)
|
|
785
860
|
});
|
|
861
|
+
// }
|
|
786
862
|
}
|
|
787
863
|
}
|
|
788
864
|
return extend(parseResult, { value: null, switchToNext: false });
|
|
@@ -960,7 +1036,10 @@ export class DateObject {
|
|
|
960
1036
|
}
|
|
961
1037
|
else {
|
|
962
1038
|
if (!this.autoCorrectParts && this.getInvalidDatePartValue(symbol)) {
|
|
963
|
-
|
|
1039
|
+
// use mask.symbols instead of mask.partMap
|
|
1040
|
+
const part = mask.partMap[formatSymbolIndex];
|
|
1041
|
+
const pattern = mask.partMap.filter(x => x.type === part.type && x.pattern === part.pattern);
|
|
1042
|
+
const segmentText = text.substr(formatSymbolIndex, pattern.length);
|
|
964
1043
|
resultText = segmentText + resultText;
|
|
965
1044
|
}
|
|
966
1045
|
else {
|
|
@@ -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());
|
|
@@ -2,7 +2,7 @@ import { DateObject } from '../common/dateobject';
|
|
|
2
2
|
import { approximateStringMatching } from './utils';
|
|
3
3
|
import { KeyCode } from '../common/keycode';
|
|
4
4
|
import { Key } from '../common/key';
|
|
5
|
-
import { extend, isPresent, isDocumentAvailable, millisecondDigitsInFormat, millisecondStepFor,
|
|
5
|
+
import { extend, isPresent, isDocumentAvailable, millisecondDigitsInFormat, millisecondStepFor, isValidDate } from '../common/utils';
|
|
6
6
|
import { Observable } from '../common/observable';
|
|
7
7
|
import { DateInputInteractionMode } from './interaction-mode';
|
|
8
8
|
import { isEqual, cloneDate } from '@progress/kendo-date-math';
|
|
@@ -71,19 +71,19 @@ export class DateInput extends Observable {
|
|
|
71
71
|
this.currentText = '';
|
|
72
72
|
this.currentFormat = '';
|
|
73
73
|
this.interactionMode = DateInputInteractionMode.None;
|
|
74
|
-
this.
|
|
74
|
+
this.previousElementSelection = { start: 0, end: 0 };
|
|
75
75
|
this.init(element, options);
|
|
76
76
|
}
|
|
77
77
|
get value() {
|
|
78
78
|
return this.dateObject && this.dateObject.getValue();
|
|
79
79
|
}
|
|
80
80
|
init(element, options) {
|
|
81
|
-
let dateValue =
|
|
82
|
-
if (!
|
|
81
|
+
let dateValue = isValidDate(this.options.value) ? cloneDate(this.options.value) : new Date(options.formattedValue);
|
|
82
|
+
if (!isValidDate(dateValue)) {
|
|
83
83
|
dateValue = null;
|
|
84
84
|
}
|
|
85
85
|
this.element = element;
|
|
86
|
-
|
|
86
|
+
this.element._kendoWidget = this;
|
|
87
87
|
this.options = extend({}, defaultDateInputOptions, options);
|
|
88
88
|
this.intl = this.options.intlService;
|
|
89
89
|
this.formatPlaceholder = this.options.formatPlaceholder ? this.options.formatPlaceholder : 'formatPattern';
|
|
@@ -263,33 +263,48 @@ export class DateInput extends Observable {
|
|
|
263
263
|
const hasCaret = this.isInCaretMode();
|
|
264
264
|
if (hasCaret && this.keyDownEvent.key === Key.SPACE) {
|
|
265
265
|
// do not allow custom "holes" in the date segments
|
|
266
|
-
this.
|
|
266
|
+
this.restorePreviousInputEventState();
|
|
267
267
|
return;
|
|
268
268
|
}
|
|
269
269
|
const oldDateObjectValue = this.dateObject && this.dateObject.getValue();
|
|
270
270
|
const { text: currentText, format: currentFormat } = this.dateObject.getTextAndFormat();
|
|
271
271
|
this.currentFormat = currentFormat;
|
|
272
|
-
|
|
272
|
+
let text = "";
|
|
273
|
+
if (hasCaret) {
|
|
274
|
+
if (isBackspaceKey || isDeleteKey) {
|
|
275
|
+
text = this.previousElementValue;
|
|
276
|
+
}
|
|
277
|
+
else if (originalInteractionMode === DateInputInteractionMode.Caret) {
|
|
278
|
+
text = this.previousElementValue;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
text = currentText;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
text = currentText;
|
|
286
|
+
}
|
|
287
|
+
const newText = this.elementValue;
|
|
273
288
|
const diff = approximateStringMatching({
|
|
274
289
|
oldText: text,
|
|
275
|
-
newText:
|
|
290
|
+
newText: newText,
|
|
276
291
|
formatPattern: this.currentFormat,
|
|
277
292
|
selectionStart: this.selection.start,
|
|
278
293
|
isInCaretMode: hasCaret,
|
|
279
294
|
keyEvent: this.keyDownEvent
|
|
280
295
|
});
|
|
281
296
|
if (hasCaret && (!diff || diff.length === 0)) {
|
|
282
|
-
this.
|
|
297
|
+
this.restorePreviousInputEventState();
|
|
283
298
|
return;
|
|
284
299
|
}
|
|
285
300
|
else if (hasCaret && diff.length === 1) {
|
|
286
301
|
if (!diff[0] || !diff[0][0]) {
|
|
287
|
-
this.
|
|
302
|
+
this.restorePreviousInputEventState();
|
|
288
303
|
return;
|
|
289
304
|
}
|
|
290
305
|
else if (hasCaret && diff[0] &&
|
|
291
306
|
(diff[0][0] === Constants.formatSeparator || diff[0][1] === Constants.formatSeparator)) {
|
|
292
|
-
this.
|
|
307
|
+
this.restorePreviousInputEventState();
|
|
293
308
|
return;
|
|
294
309
|
}
|
|
295
310
|
}
|
|
@@ -304,7 +319,8 @@ export class DateInput extends Observable {
|
|
|
304
319
|
resetSegmentValue: this.resetSegmentValue,
|
|
305
320
|
cycleSegmentValue: !this.isInCaretMode(),
|
|
306
321
|
rawTextValue: this.element.value,
|
|
307
|
-
isDeleting: isBackspaceKey || isDeleteKey
|
|
322
|
+
isDeleting: isBackspaceKey || isDeleteKey,
|
|
323
|
+
originalFormat: this.currentFormat
|
|
308
324
|
});
|
|
309
325
|
parsePartsResults.push(parsePartResult);
|
|
310
326
|
switchPart = parsePartResult.switchToNext;
|
|
@@ -342,6 +358,29 @@ export class DateInput extends Observable {
|
|
|
342
358
|
}
|
|
343
359
|
}
|
|
344
360
|
}
|
|
361
|
+
else if (hasCaret) {
|
|
362
|
+
if (this.options.format.length !== this.currentFormat.length) {
|
|
363
|
+
if (hasDateValueChanged && isPresent(this.dateObject.value)) {
|
|
364
|
+
const elementValueLength = this.elementValue.length;
|
|
365
|
+
this.forceUpdate();
|
|
366
|
+
const selectionOffset = this.elementValue.length - elementValueLength;
|
|
367
|
+
this.setSelection({
|
|
368
|
+
start: currentSelection.start + selectionOffset,
|
|
369
|
+
end: currentSelection.start + selectionOffset
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
if (hasDateValueChanged) {
|
|
375
|
+
if (lastParseResultHasNoValue) {
|
|
376
|
+
this.restorePreviousInputEventState();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
this.restorePreviousInputEventState();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
345
384
|
}
|
|
346
385
|
if (!switchPart && hasCaret && !isBackspaceKey && !isDeleteKey && !resetPart && lastParseResultHasNoValue) {
|
|
347
386
|
if (hasDateValueChanged) {
|
|
@@ -358,10 +397,13 @@ export class DateInput extends Observable {
|
|
|
358
397
|
this.setSelection(this.selectionBySymbol(symbolForSelection));
|
|
359
398
|
}
|
|
360
399
|
else {
|
|
361
|
-
this.
|
|
400
|
+
this.restorePreviousInputEventState();
|
|
362
401
|
}
|
|
363
402
|
}
|
|
364
403
|
}
|
|
404
|
+
else {
|
|
405
|
+
this.restorePreviousInputEventState();
|
|
406
|
+
}
|
|
365
407
|
}
|
|
366
408
|
else if (this.options.autoSwitchParts && (switchPart || navigationOnly)) {
|
|
367
409
|
if (!hasCaret) {
|
|
@@ -373,6 +415,12 @@ export class DateInput extends Observable {
|
|
|
373
415
|
event: e
|
|
374
416
|
});
|
|
375
417
|
this.triggerInputEnd({ event: e });
|
|
418
|
+
if (hasCaret) {
|
|
419
|
+
// a format like "F" can dynamically change the resolved format pattern based on the value, e.g.
|
|
420
|
+
// "Tuesday, February 1, 2022 3:04:05 AM" becomes
|
|
421
|
+
// "Wednesday, February 2, 2022 3:04:05 AM" giving a diff of 2 ("Tuesday".length - "Wednesday".length)
|
|
422
|
+
this.setTextAndFormat();
|
|
423
|
+
}
|
|
376
424
|
}
|
|
377
425
|
/**
|
|
378
426
|
* @hidden
|
|
@@ -418,6 +466,8 @@ export class DateInput extends Observable {
|
|
|
418
466
|
}
|
|
419
467
|
this.keyDownEvent = e;
|
|
420
468
|
this.previousElementValue = this.element.value;
|
|
469
|
+
const { start, end } = this.selection;
|
|
470
|
+
this.previousElementSelection = { start, end };
|
|
421
471
|
const autoSwitchKeys = (this.options.autoSwitchKeys || [])
|
|
422
472
|
.map(x => x.toString().toLowerCase().trim());
|
|
423
473
|
if (autoSwitchKeys.indexOf(e.keyCode.toString()) >= 0 ||
|
|
@@ -800,7 +850,6 @@ export class DateInput extends Observable {
|
|
|
800
850
|
* @hidden
|
|
801
851
|
*/
|
|
802
852
|
setElementValue(value) {
|
|
803
|
-
this.previousElementValue = this.element.value;
|
|
804
853
|
this.element.value = value;
|
|
805
854
|
}
|
|
806
855
|
/**
|
|
@@ -836,23 +885,25 @@ export class DateInput extends Observable {
|
|
|
836
885
|
}
|
|
837
886
|
/* eslint-enable no-fallthrough */
|
|
838
887
|
}
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
}
|
|
851
|
-
else {
|
|
852
|
-
selectionOffset = -1;
|
|
853
|
-
}
|
|
888
|
+
/**
|
|
889
|
+
* @hidden
|
|
890
|
+
*/
|
|
891
|
+
restorePreviousInputEventState() {
|
|
892
|
+
this.restorePreviousElementValue();
|
|
893
|
+
this.restorePreviousElementSelection();
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* @hidden
|
|
897
|
+
*/
|
|
898
|
+
restorePreviousElementValue() {
|
|
854
899
|
this.setElementValue(this.previousElementValue || '');
|
|
855
|
-
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* @hidden
|
|
903
|
+
*/
|
|
904
|
+
restorePreviousElementSelection() {
|
|
905
|
+
const { start, end } = this.previousElementSelection;
|
|
906
|
+
this.setSelection({ start: start || 0, end: end || 0 });
|
|
856
907
|
}
|
|
857
908
|
writeValue(value) {
|
|
858
909
|
this.verifyValue(value);
|
|
@@ -860,7 +911,7 @@ export class DateInput extends Observable {
|
|
|
860
911
|
this.refreshElementValue();
|
|
861
912
|
}
|
|
862
913
|
verifyValue(value) {
|
|
863
|
-
if (value && !
|
|
914
|
+
if (value && !isValidDate(value)) {
|
|
864
915
|
throw new Error("The 'value' should be a valid JavaScript Date instance.");
|
|
865
916
|
}
|
|
866
917
|
}
|
|
@@ -878,6 +929,7 @@ export class DateInput extends Observable {
|
|
|
878
929
|
element.placeholder = this.options.placeholder;
|
|
879
930
|
}
|
|
880
931
|
const newElementValue = !showPlaceholder ? currentText : "";
|
|
932
|
+
this.previousElementValue = this.elementValue;
|
|
881
933
|
this.setElementValue(newElementValue);
|
|
882
934
|
if (this.isActive && !this.options.allowCaretMode && this.options.selectNearestSegmentOnFocus) {
|
|
883
935
|
this.selectNearestSegment(start);
|
|
@@ -959,10 +1011,10 @@ export class DateInput extends Observable {
|
|
|
959
1011
|
intlService: this.intl,
|
|
960
1012
|
formatPlaceholder: this.formatPlaceholder,
|
|
961
1013
|
format: this.inputFormat,
|
|
962
|
-
localeId: this.localeId,
|
|
963
1014
|
cycleTime: this.options.cycleTime,
|
|
964
1015
|
twoDigitYearMax: this.options.twoDigitYearMax,
|
|
965
|
-
autoCorrectParts: this.options.autoCorrectParts
|
|
1016
|
+
autoCorrectParts: this.options.autoCorrectParts,
|
|
1017
|
+
value: this.options.value
|
|
966
1018
|
}, options));
|
|
967
1019
|
return dateObject;
|
|
968
1020
|
}
|
|
@@ -52,27 +52,23 @@ export const approximateStringMatching = ({ oldText, newText, formatPattern, sel
|
|
|
52
52
|
Handle the typing over a literal as well.
|
|
53
53
|
*/
|
|
54
54
|
if ((isInCaretMode &&
|
|
55
|
-
newSegmentText.indexOf(oldSegmentText) === 0
|
|
55
|
+
(newSegmentText.indexOf(oldSegmentText) === 0 ||
|
|
56
|
+
formatPattern[selectionStart - 1] === Constants.formatSeparator)) ||
|
|
56
57
|
(!isInCaretMode &&
|
|
57
58
|
(newSegmentText.indexOf(oldSegmentText) === 0 ||
|
|
58
59
|
formatPattern[selectionStart - 1] === Constants.formatSeparator))) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
let symbol = formatPattern[0];
|
|
65
|
-
for (let i = Math.max(0, oldSegmentText.length - 1); i < formatPattern.length; i++) {
|
|
66
|
-
if (formatPattern[i] !== Constants.formatSeparator) {
|
|
67
|
-
symbol = formatPattern[i];
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
60
|
+
let symbol = formatPattern[0];
|
|
61
|
+
for (let i = Math.max(0, oldSegmentText.length - 1); i < formatPattern.length; i++) {
|
|
62
|
+
if (formatPattern[i] !== Constants.formatSeparator) {
|
|
63
|
+
symbol = formatPattern[i];
|
|
64
|
+
break;
|
|
70
65
|
}
|
|
71
|
-
return [[symbol, newSegmentText[selectionStart - 1]]];
|
|
72
66
|
}
|
|
67
|
+
return [[symbol, newSegmentText[selectionStart - 1]]];
|
|
73
68
|
}
|
|
74
69
|
/* Handle the entering of a space or a separator for navigating to the next item. */
|
|
75
|
-
if (newSegmentText[newSegmentText.length - 1] === ' ' ||
|
|
70
|
+
if ((!isInCaretMode && newSegmentText[newSegmentText.length - 1] === ' ') ||
|
|
71
|
+
(!isInCaretMode && newSegmentText[newSegmentText.length - 1] === oldTextSeparator)) {
|
|
76
72
|
return [[formatPattern[selectionStart - 1], Constants.formatSeparator]];
|
|
77
73
|
}
|
|
78
74
|
/* Handle typing over a correctly selected part. */
|
|
@@ -63,13 +63,14 @@ export declare class DateObject {
|
|
|
63
63
|
/**
|
|
64
64
|
* @hidden
|
|
65
65
|
*/
|
|
66
|
-
parsePart({ symbol, currentChar, resetSegmentValue, cycleSegmentValue, rawTextValue, isDeleting }: {
|
|
66
|
+
parsePart({ symbol, currentChar, resetSegmentValue, cycleSegmentValue, rawTextValue: rawInputValue, isDeleting, originalFormat }: {
|
|
67
67
|
symbol: any;
|
|
68
68
|
currentChar: any;
|
|
69
69
|
resetSegmentValue: any;
|
|
70
70
|
cycleSegmentValue: any;
|
|
71
71
|
rawTextValue: any;
|
|
72
72
|
isDeleting: any;
|
|
73
|
+
originalFormat: any;
|
|
73
74
|
}): any;
|
|
74
75
|
/**
|
|
75
76
|
* @hidden
|