@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.
@@ -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, isDate } from '../common/utils';
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,15 +71,15 @@ export class DateInput extends Observable {
71
71
  this.currentText = '';
72
72
  this.currentFormat = '';
73
73
  this.interactionMode = DateInputInteractionMode.None;
74
- this.localeId = Constants.defaultLocaleId;
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 = isDate(this.options.value) ? cloneDate(this.options.value) : new Date(options.formattedValue);
82
- if (!isDate(dateValue)) {
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;
@@ -92,6 +92,7 @@ export class DateInput extends Observable {
92
92
  this.setTextAndFormat();
93
93
  this.bindEvents();
94
94
  this.resetSegmentValue = true;
95
+ this.interactionMode = DateInputInteractionMode.None;
95
96
  this.forceUpdate();
96
97
  }
97
98
  destroy() {
@@ -146,8 +147,8 @@ export class DateInput extends Observable {
146
147
  setOptions(options, refresh = false) {
147
148
  this.options = extend(this.options, options);
148
149
  if (refresh) {
149
- this.destroy();
150
- this.init(this.element, options);
150
+ this.unbindEvents();
151
+ this.init(this.element, this.options);
151
152
  }
152
153
  }
153
154
  /**
@@ -263,33 +264,48 @@ export class DateInput extends Observable {
263
264
  const hasCaret = this.isInCaretMode();
264
265
  if (hasCaret && this.keyDownEvent.key === Key.SPACE) {
265
266
  // do not allow custom "holes" in the date segments
266
- this.setPreviousInputEventState(this.keyDownEvent);
267
+ this.restorePreviousInputEventState();
267
268
  return;
268
269
  }
269
270
  const oldDateObjectValue = this.dateObject && this.dateObject.getValue();
270
271
  const { text: currentText, format: currentFormat } = this.dateObject.getTextAndFormat();
271
272
  this.currentFormat = currentFormat;
272
- const text = hasCaret && (isBackspaceKey || isDeleteKey) ? this.previousElementValue : currentText;
273
+ let text = "";
274
+ if (hasCaret) {
275
+ if (isBackspaceKey || isDeleteKey) {
276
+ text = this.previousElementValue;
277
+ }
278
+ else if (originalInteractionMode === DateInputInteractionMode.Caret) {
279
+ text = this.previousElementValue;
280
+ }
281
+ else {
282
+ text = currentText;
283
+ }
284
+ }
285
+ else {
286
+ text = currentText;
287
+ }
288
+ const newText = this.elementValue;
273
289
  const diff = approximateStringMatching({
274
290
  oldText: text,
275
- newText: this.element.value,
291
+ newText: newText,
276
292
  formatPattern: this.currentFormat,
277
293
  selectionStart: this.selection.start,
278
294
  isInCaretMode: hasCaret,
279
295
  keyEvent: this.keyDownEvent
280
296
  });
281
297
  if (hasCaret && (!diff || diff.length === 0)) {
282
- this.setPreviousInputEventState(this.keyDownEvent);
298
+ this.restorePreviousInputEventState();
283
299
  return;
284
300
  }
285
301
  else if (hasCaret && diff.length === 1) {
286
302
  if (!diff[0] || !diff[0][0]) {
287
- this.setPreviousInputEventState(this.keyDownEvent);
303
+ this.restorePreviousInputEventState();
288
304
  return;
289
305
  }
290
306
  else if (hasCaret && diff[0] &&
291
307
  (diff[0][0] === Constants.formatSeparator || diff[0][1] === Constants.formatSeparator)) {
292
- this.setPreviousInputEventState(this.keyDownEvent);
308
+ this.restorePreviousInputEventState();
293
309
  return;
294
310
  }
295
311
  }
@@ -304,7 +320,8 @@ export class DateInput extends Observable {
304
320
  resetSegmentValue: this.resetSegmentValue,
305
321
  cycleSegmentValue: !this.isInCaretMode(),
306
322
  rawTextValue: this.element.value,
307
- isDeleting: isBackspaceKey || isDeleteKey
323
+ isDeleting: isBackspaceKey || isDeleteKey,
324
+ originalFormat: this.currentFormat
308
325
  });
309
326
  parsePartsResults.push(parsePartResult);
310
327
  switchPart = parsePartResult.switchToNext;
@@ -342,6 +359,25 @@ export class DateInput extends Observable {
342
359
  }
343
360
  }
344
361
  }
362
+ else if (hasCaret) {
363
+ if (this.options.format.length !== this.currentFormat.length) {
364
+ if (hasDateValueChanged && isPresent(this.dateObject.getValue())) {
365
+ if (switchPart) {
366
+ this.switchDateSegment(1);
367
+ }
368
+ }
369
+ }
370
+ else {
371
+ if (hasDateValueChanged) {
372
+ if (lastParseResultHasNoValue) {
373
+ this.restorePreviousInputEventState();
374
+ }
375
+ }
376
+ else {
377
+ this.restorePreviousInputEventState();
378
+ }
379
+ }
380
+ }
345
381
  }
346
382
  if (!switchPart && hasCaret && !isBackspaceKey && !isDeleteKey && !resetPart && lastParseResultHasNoValue) {
347
383
  if (hasDateValueChanged) {
@@ -358,10 +394,13 @@ export class DateInput extends Observable {
358
394
  this.setSelection(this.selectionBySymbol(symbolForSelection));
359
395
  }
360
396
  else {
361
- this.setPreviousInputEventState(this.keyDownEvent);
397
+ this.restorePreviousInputEventState();
362
398
  }
363
399
  }
364
400
  }
401
+ else {
402
+ this.restorePreviousInputEventState();
403
+ }
365
404
  }
366
405
  else if (this.options.autoSwitchParts && (switchPart || navigationOnly)) {
367
406
  if (!hasCaret) {
@@ -373,6 +412,12 @@ export class DateInput extends Observable {
373
412
  event: e
374
413
  });
375
414
  this.triggerInputEnd({ event: e });
415
+ if (hasCaret) {
416
+ // a format like "F" can dynamically change the resolved format pattern based on the value, e.g.
417
+ // "Tuesday, February 1, 2022 3:04:05 AM" becomes
418
+ // "Wednesday, February 2, 2022 3:04:05 AM" giving a diff of 2 ("Tuesday".length - "Wednesday".length)
419
+ this.setTextAndFormat();
420
+ }
376
421
  }
377
422
  /**
378
423
  * @hidden
@@ -418,6 +463,8 @@ export class DateInput extends Observable {
418
463
  }
419
464
  this.keyDownEvent = e;
420
465
  this.previousElementValue = this.element.value;
466
+ const { start, end } = this.selection;
467
+ this.previousElementSelection = { start, end };
421
468
  const autoSwitchKeys = (this.options.autoSwitchKeys || [])
422
469
  .map(x => x.toString().toLowerCase().trim());
423
470
  if (autoSwitchKeys.indexOf(e.keyCode.toString()) >= 0 ||
@@ -606,6 +653,14 @@ export class DateInput extends Observable {
606
653
  if (start < 0) {
607
654
  start = 0;
608
655
  }
656
+ if (!this.options.autoCorrectParts && this.currentFormat.length !== this.currentText.length) {
657
+ if (this.currentFormat.length < this.currentText.length) {
658
+ end += this.currentText.length - this.currentFormat.length;
659
+ }
660
+ else {
661
+ end = Math.max(0, end - (this.currentFormat.length - this.currentText.length));
662
+ }
663
+ }
609
664
  return { start, end };
610
665
  }
611
666
  /**
@@ -629,24 +684,36 @@ export class DateInput extends Observable {
629
684
  const selection = this.selection;
630
685
  if (this.isInCaretMode()) {
631
686
  let start = selection.start;
632
- let closestNonSeparatorSymbol = this.currentFormat[start];
633
- for (let i = start; i >= 0; i--) {
634
- closestNonSeparatorSymbol = this.currentFormat[i];
635
- if (closestNonSeparatorSymbol !== Constants.formatSeparator) {
636
- start = i;
637
- break;
687
+ const currentSymbol = this.currentFormat[start - (this.elementValue.length - this.currentFormat.length)];
688
+ let symbol = "";
689
+ let symbolCandidate = "";
690
+ if (offset < 0) {
691
+ for (let i = 0; i < start + offset; i++) {
692
+ symbolCandidate = this.currentFormat[i];
693
+ if (symbolCandidate !== Constants.formatSeparator &&
694
+ symbolCandidate !== currentSymbol) {
695
+ start = i;
696
+ symbol = symbolCandidate;
697
+ break;
698
+ }
638
699
  }
639
700
  }
640
- let symbol;
641
- for (let i = start; i < this.currentFormat.length; i++) {
642
- symbol = this.currentFormat[i];
643
- if (symbol !== Constants.formatSeparator) {
644
- break;
701
+ else {
702
+ for (let i = start + offset; i < this.currentFormat.length; i++) {
703
+ symbolCandidate = this.currentFormat[i];
704
+ if (symbolCandidate !== Constants.formatSeparator &&
705
+ symbolCandidate !== currentSymbol) {
706
+ start = i;
707
+ symbol = symbolCandidate;
708
+ break;
709
+ }
645
710
  }
646
711
  }
647
712
  if (symbol) {
648
713
  this.forceUpdate();
649
714
  this.setSelection(this.selectionBySymbol(symbol));
715
+ this.interactionMode = DateInputInteractionMode.Selection;
716
+ return;
650
717
  }
651
718
  }
652
719
  let { start: selectionStart, end: selectionEnd } = this.selection;
@@ -800,7 +867,6 @@ export class DateInput extends Observable {
800
867
  * @hidden
801
868
  */
802
869
  setElementValue(value) {
803
- this.previousElementValue = this.element.value;
804
870
  this.element.value = value;
805
871
  }
806
872
  /**
@@ -836,23 +902,25 @@ export class DateInput extends Observable {
836
902
  }
837
903
  /* eslint-enable no-fallthrough */
838
904
  }
839
- setPreviousInputEventState(keyDownEvent) {
840
- const { start: selectionStart, end: selectionEnd } = this.selection;
841
- let selectionOffset = -1;
842
- if (keyDownEvent.keyCode === KeyCode.BACKSPACE) {
843
- selectionOffset = 1;
844
- }
845
- else if (keyDownEvent.keyCode === KeyCode.DELETE) {
846
- selectionOffset = 0;
847
- }
848
- else if (keyDownEvent.keyCode === KeyCode.SPACE) {
849
- selectionOffset = -1;
850
- }
851
- else {
852
- selectionOffset = -1;
853
- }
905
+ /**
906
+ * @hidden
907
+ */
908
+ restorePreviousInputEventState() {
909
+ this.restorePreviousElementValue();
910
+ this.restorePreviousElementSelection();
911
+ }
912
+ /**
913
+ * @hidden
914
+ */
915
+ restorePreviousElementValue() {
854
916
  this.setElementValue(this.previousElementValue || '');
855
- this.setSelection({ start: selectionStart + selectionOffset, end: selectionEnd + selectionOffset });
917
+ }
918
+ /**
919
+ * @hidden
920
+ */
921
+ restorePreviousElementSelection() {
922
+ const { start, end } = this.previousElementSelection;
923
+ this.setSelection({ start: start || 0, end: end || 0 });
856
924
  }
857
925
  writeValue(value) {
858
926
  this.verifyValue(value);
@@ -860,7 +928,7 @@ export class DateInput extends Observable {
860
928
  this.refreshElementValue();
861
929
  }
862
930
  verifyValue(value) {
863
- if (value && !isDate(value)) {
931
+ if (value && !isValidDate(value)) {
864
932
  throw new Error("The 'value' should be a valid JavaScript Date instance.");
865
933
  }
866
934
  }
@@ -878,6 +946,7 @@ export class DateInput extends Observable {
878
946
  element.placeholder = this.options.placeholder;
879
947
  }
880
948
  const newElementValue = !showPlaceholder ? currentText : "";
949
+ this.previousElementValue = this.elementValue;
881
950
  this.setElementValue(newElementValue);
882
951
  if (this.isActive && !this.options.allowCaretMode && this.options.selectNearestSegmentOnFocus) {
883
952
  this.selectNearestSegment(start);
@@ -959,10 +1028,10 @@ export class DateInput extends Observable {
959
1028
  intlService: this.intl,
960
1029
  formatPlaceholder: this.formatPlaceholder,
961
1030
  format: this.inputFormat,
962
- localeId: this.localeId,
963
1031
  cycleTime: this.options.cycleTime,
964
1032
  twoDigitYearMax: this.options.twoDigitYearMax,
965
- autoCorrectParts: this.options.autoCorrectParts
1033
+ autoCorrectParts: this.options.autoCorrectParts,
1034
+ value: this.options.value
966
1035
  }, options));
967
1036
  return dateObject;
968
1037
  }
@@ -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 && formatPattern[selectionStart - 1]) ||
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
- if (isInCaretMode) {
60
- let symbol = formatPattern[selectionStart - 1];
61
- return [[symbol, newSegmentText[selectionStart - 1]]];
62
- }
63
- else {
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] === ' ' || newSegmentText[newSegmentText.length - 1] === oldTextSeparator) {
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
@@ -169,4 +170,8 @@ export declare class DateObject {
169
170
  */
170
171
  modifyDateSymbolWithValue(date: any, symbol: any, value: any): Date;
171
172
  markDatePartsAsExisting(): void;
173
+ /**
174
+ * @hidden
175
+ */
176
+ getPartsForSegment(mask: any, partIndex: any): any[];
172
177
  }