@progress/kendo-angular-dateinputs 13.6.0-develop.9 → 14.0.0-develop.10
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/dateinput/dateinput.component.d.ts +93 -57
- package/datepicker/datepicker.component.d.ts +38 -1
- package/datetimepicker/datetimepicker.component.d.ts +38 -1
- package/esm2020/dateinput/dateinput.component.mjs +240 -821
- package/esm2020/datepicker/datepicker.component.mjs +63 -2
- package/esm2020/datetimepicker/datetimepicker.component.mjs +71 -3
- package/esm2020/package-metadata.mjs +2 -2
- package/esm2020/timepicker/timepicker.component.mjs +53 -2
- package/fesm2015/progress-kendo-angular-dateinputs.mjs +425 -827
- package/fesm2020/progress-kendo-angular-dateinputs.mjs +426 -827
- package/package.json +13 -12
- package/timepicker/timepicker.component.d.ts +32 -1
|
@@ -8,18 +8,19 @@ import { maxValidator } from '../validators/max.validator';
|
|
|
8
8
|
import { incompleteDateValidator } from '../validators/incomplete-date.validator';
|
|
9
9
|
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, NgControl } from '@angular/forms';
|
|
10
10
|
import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n';
|
|
11
|
-
import { IntlService } from '@progress/kendo-angular-intl';
|
|
11
|
+
import { IntlService, localeData } from '@progress/kendo-angular-intl';
|
|
12
12
|
import { validatePackage } from '@progress/kendo-licensing';
|
|
13
13
|
import { packageMetadata } from '../package-metadata';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { cloneDate, isEqual } from '@progress/kendo-date-math';
|
|
15
|
+
import { hasObservers, KendoInput } from '@progress/kendo-angular-common';
|
|
16
16
|
import { Arrow } from './arrow.enum';
|
|
17
|
-
import {
|
|
17
|
+
import { noop, isValidRange, getSizeClass, getRoundedClass, getFillModeClass, DEFAULT_FILL_MODE, DEFAULT_ROUNDED, DEFAULT_SIZE } from '../util';
|
|
18
18
|
import { PickerService } from '../common/picker.service';
|
|
19
19
|
import { closest } from '../common/dom-queries';
|
|
20
20
|
import { requiresZoneOnBlur, isPresent, attributeNames } from '../common/utils';
|
|
21
21
|
import { Subscription } from 'rxjs';
|
|
22
22
|
import { caretAltDownIcon, caretAltUpIcon } from '@progress/kendo-svg-icons';
|
|
23
|
+
import { DateInput } from '@progress/kendo-dateinputs-common';
|
|
23
24
|
import * as i0 from "@angular/core";
|
|
24
25
|
import * as i1 from "@progress/kendo-angular-intl";
|
|
25
26
|
import * as i2 from "@progress/kendo-angular-l10n";
|
|
@@ -32,424 +33,37 @@ let nextId = 0;
|
|
|
32
33
|
const MIN_DOC_LINK = 'http://www.telerik.com/kendo-angular-ui/components/dateinputs/api/DateInputComponent/#toc-min';
|
|
33
34
|
const MAX_DOC_LINK = 'http://www.telerik.com/kendo-angular-ui/components/dateinputs/api/DateInputComponent/#toc-max';
|
|
34
35
|
const VALUE_DOC_LINK = 'http://www.telerik.com/kendo-angular-ui/components/dateinputs/dateinput/#toc-using-with-json';
|
|
35
|
-
const DATE_PART_REGEXP = /year|month|<day>/;
|
|
36
|
-
const TIME_PART_REGEXP = /hour|minute|second|millisecond/;
|
|
37
|
-
const SHORT_PATTERN_LENGTH_REGEXP = /d|M|H|h|m|s/;
|
|
38
36
|
const TWO_DIGIT_YEAR_MAX = 68;
|
|
39
|
-
const PREVIOUS_CENTURY_BASE = 1900;
|
|
40
|
-
const CURRENT_CENTURY_BASE = 2000;
|
|
41
37
|
const DEFAULT_FORMAT = 'd';
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.
|
|
53
|
-
this.
|
|
54
|
-
this.
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
this.
|
|
59
|
-
this.
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
65
|
-
this.
|
|
66
|
-
this.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"a": "a",
|
|
72
|
-
"d": "d",
|
|
73
|
-
"h": "h",
|
|
74
|
-
"m": "m",
|
|
75
|
-
"s": "s",
|
|
76
|
-
"S": "S",
|
|
77
|
-
"y": "y"
|
|
78
|
-
};
|
|
79
|
-
validatePackage(packageMetadata);
|
|
80
|
-
this.monthNames = this.allFormatedMonths();
|
|
81
|
-
this.dayPeriods = this.allDayPeriods();
|
|
82
|
-
if (!value) {
|
|
83
|
-
this.value = getDate(new Date());
|
|
84
|
-
const sampleFormat = this.dateFormatString(this.value, this.format).symbols;
|
|
85
|
-
for (let i = 0; i < sampleFormat.length; i++) {
|
|
86
|
-
this.setExisting(sampleFormat[i], false);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
this.value = cloneDate(value);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
hasValue() {
|
|
94
|
-
const pred = (a, p) => a || p.type !== 'literal' && p.type !== 'dayperiod' && this.getExisting(p.pattern[0]);
|
|
95
|
-
return this.intl.splitDateFormat(this.format).reduce(pred, false);
|
|
96
|
-
}
|
|
97
|
-
shouldNormalizeCentury() {
|
|
98
|
-
return this.intl.splitDateFormat(this.format).some(part => part.pattern === 'yy');
|
|
99
|
-
}
|
|
100
|
-
getDateObject() {
|
|
101
|
-
for (let i = 0; i < this.knownParts.length; i++) {
|
|
102
|
-
if (!this.getExisting(this.knownParts[i])) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return cloneDate(this.value);
|
|
107
|
-
}
|
|
108
|
-
getTextAndFormat(format) {
|
|
109
|
-
return this.merge(this.intl.formatDate(this.value, format), this.dateFormatString(this.value, format));
|
|
110
|
-
}
|
|
111
|
-
getExisting(symbol) {
|
|
112
|
-
switch (symbol) {
|
|
113
|
-
case "y": return this.year;
|
|
114
|
-
case "M":
|
|
115
|
-
case "L": return this.month;
|
|
116
|
-
case "d": return this.date;
|
|
117
|
-
case "E": return this.date && this.month && this.year;
|
|
118
|
-
case "h":
|
|
119
|
-
case "H": return this.hours;
|
|
120
|
-
case "m": return this.minutes;
|
|
121
|
-
case "s": return this.seconds;
|
|
122
|
-
case "S": return this.milliseconds;
|
|
123
|
-
default: return true;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
setExisting(symbol, value) {
|
|
127
|
-
switch (symbol) {
|
|
128
|
-
case "y":
|
|
129
|
-
this.year = value;
|
|
130
|
-
if (value === false) {
|
|
131
|
-
this.value.setFullYear(2000);
|
|
132
|
-
}
|
|
133
|
-
break; //allow 2/29 dates
|
|
134
|
-
case "M":
|
|
135
|
-
this.month = value;
|
|
136
|
-
if (value === false) {
|
|
137
|
-
this.value.setMonth(0);
|
|
138
|
-
}
|
|
139
|
-
break; //make sure you can type 31 at day part
|
|
140
|
-
case "d":
|
|
141
|
-
this.date = value;
|
|
142
|
-
break;
|
|
143
|
-
case "h":
|
|
144
|
-
case "H":
|
|
145
|
-
this.hours = value;
|
|
146
|
-
break;
|
|
147
|
-
case "m":
|
|
148
|
-
this.minutes = value;
|
|
149
|
-
break;
|
|
150
|
-
case "s":
|
|
151
|
-
this.seconds = value;
|
|
152
|
-
break;
|
|
153
|
-
case "S":
|
|
154
|
-
this.milliseconds = value;
|
|
155
|
-
break;
|
|
156
|
-
default: return;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
modifyPart(symbol, offset) {
|
|
160
|
-
let newValue = cloneDate(this.value);
|
|
161
|
-
switch (symbol) {
|
|
162
|
-
case "y":
|
|
163
|
-
newValue.setFullYear(newValue.getFullYear() + offset);
|
|
164
|
-
break;
|
|
165
|
-
case "M":
|
|
166
|
-
newValue = addMonths(this.value, offset);
|
|
167
|
-
break;
|
|
168
|
-
case "d":
|
|
169
|
-
case "E":
|
|
170
|
-
newValue.setDate(newValue.getDate() + offset);
|
|
171
|
-
break;
|
|
172
|
-
case "h":
|
|
173
|
-
case "H":
|
|
174
|
-
newValue.setHours(newValue.getHours() + offset);
|
|
175
|
-
break;
|
|
176
|
-
case "m":
|
|
177
|
-
newValue.setMinutes(newValue.getMinutes() + offset);
|
|
178
|
-
break;
|
|
179
|
-
case "s":
|
|
180
|
-
newValue.setSeconds(newValue.getSeconds() + offset);
|
|
181
|
-
break;
|
|
182
|
-
case "S":
|
|
183
|
-
newValue.setMilliseconds(newValue.getMilliseconds() + offset);
|
|
184
|
-
break;
|
|
185
|
-
case "a":
|
|
186
|
-
newValue.setHours(newValue.getHours() + (12 * offset));
|
|
187
|
-
break;
|
|
188
|
-
default: break;
|
|
189
|
-
}
|
|
190
|
-
if (this.shouldNormalizeCentury()) {
|
|
191
|
-
newValue = this.normalizeCentury(newValue);
|
|
192
|
-
}
|
|
193
|
-
if (newValue.getFullYear() > 0) {
|
|
194
|
-
this.setExisting(symbol, true);
|
|
195
|
-
this.value = newValue;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
parsePart(symbol, currentChar, resetSegmentValue) {
|
|
199
|
-
if (!currentChar) {
|
|
200
|
-
this.resetLeadingZero();
|
|
201
|
-
this.setExisting(symbol, false);
|
|
202
|
-
return { value: null, switchToNext: false };
|
|
203
|
-
}
|
|
204
|
-
const baseDate = this.intl.formatDate(this.value, this.format);
|
|
205
|
-
const dateParts = this.dateFormatString(this.value, this.format);
|
|
206
|
-
const baseFormat = dateParts.symbols;
|
|
207
|
-
let replaced = false;
|
|
208
|
-
let prefix = "";
|
|
209
|
-
let current = "";
|
|
210
|
-
let suffix = "";
|
|
211
|
-
for (let i = 0; i < baseDate.length; i++) {
|
|
212
|
-
if (baseFormat[i] === symbol) {
|
|
213
|
-
current += this.getExisting(symbol) ? baseDate[i] : "0";
|
|
214
|
-
replaced = true;
|
|
215
|
-
}
|
|
216
|
-
else if (!replaced) {
|
|
217
|
-
prefix += baseDate[i];
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
suffix += baseDate[i];
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
const currentMaxLength = current.length - 3;
|
|
224
|
-
let parsedDate = null;
|
|
225
|
-
const month = this.matchMonth(currentChar);
|
|
226
|
-
const dayPeriod = this.matchDayPeriod(currentChar, symbol);
|
|
227
|
-
const isZeroCurrentChar = currentChar === '0';
|
|
228
|
-
const leadingZero = (this.leadingZero || {})[symbol] || 0;
|
|
229
|
-
if (isZeroCurrentChar) {
|
|
230
|
-
const valueNumber = parseInt(resetSegmentValue ? currentChar : current + currentChar, 10);
|
|
231
|
-
if (valueNumber === 0 && !this.isAbbrMonth(dateParts.partMap, symbol)) {
|
|
232
|
-
this.incrementLeadingZero(symbol);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
this.resetLeadingZero();
|
|
237
|
-
}
|
|
238
|
-
for (let i = Math.max(0, currentMaxLength); i <= current.length; i++) {
|
|
239
|
-
let middle = resetSegmentValue ? currentChar : (current.substring(i) + currentChar);
|
|
240
|
-
if (symbol === "S" && resetSegmentValue) {
|
|
241
|
-
// The "S" parser in intl parses "1" as 100ms in order to handle ISOString dates correctly, so to get 1ms, we need to pass "001"
|
|
242
|
-
const padding = msPaddingFromFormat(baseFormat);
|
|
243
|
-
middle = padding + middle;
|
|
244
|
-
}
|
|
245
|
-
const middleNumber = parseInt(middle, 10);
|
|
246
|
-
parsedDate = this.intl.parseDate(prefix + middle + suffix, this.format);
|
|
247
|
-
if (!parsedDate && !isNaN(middleNumber) && !isNaN(parseInt(currentChar, 10))) {
|
|
248
|
-
if (symbol === 'M' && !month) {
|
|
249
|
-
const monthNumber = middleNumber - 1;
|
|
250
|
-
if (monthNumber > -1 && monthNumber < 12) {
|
|
251
|
-
parsedDate = cloneDate(this.value);
|
|
252
|
-
parsedDate.setMonth(monthNumber);
|
|
253
|
-
if (parsedDate.getMonth() !== monthNumber) {
|
|
254
|
-
parsedDate = lastDayOfMonth(addMonths(parsedDate, -1));
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
if (symbol === 'y') {
|
|
259
|
-
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);
|
|
260
|
-
if (this.date && parsedDate.getDate() !== this.value.getDate()) {
|
|
261
|
-
parsedDate = lastDayOfMonth(addMonths(parsedDate, -1));
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (parsedDate) {
|
|
266
|
-
//move to next segment if the part will overflow with next char
|
|
267
|
-
//when start from empty date (01, then 010), padded zeros should be trimmed
|
|
268
|
-
const patternValue = this.partPattern(dateParts.partMap, symbol).pattern;
|
|
269
|
-
const peekDate = this.intl.parseDate(`${prefix}${this.peek(middle, patternValue)}${suffix}`, this.format);
|
|
270
|
-
const patternLength = this.patternLength(patternValue) || patternValue.length;
|
|
271
|
-
const patternSatisfied = (leadingZero + (unpadZero(middle) || currentChar).length) >= patternLength;
|
|
272
|
-
const switchToNext = peekDate === null || patternSatisfied;
|
|
273
|
-
if (this.shouldNormalizeCentury()) {
|
|
274
|
-
parsedDate = this.normalizeCentury(parsedDate);
|
|
275
|
-
}
|
|
276
|
-
this.value = parsedDate;
|
|
277
|
-
this.setExisting(symbol, true);
|
|
278
|
-
return { value: this.value, switchToNext: switchToNext };
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
if (month) {
|
|
282
|
-
parsedDate = this.intl.parseDate(prefix + month + suffix, this.format);
|
|
283
|
-
if (parsedDate) {
|
|
284
|
-
this.value = parsedDate;
|
|
285
|
-
this.setExisting(symbol, true);
|
|
286
|
-
return { value: this.value, switchToNext: false };
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
if (dayPeriod) {
|
|
290
|
-
parsedDate = this.intl.parseDate(prefix + dayPeriod + suffix, this.format);
|
|
291
|
-
if (parsedDate) {
|
|
292
|
-
this.value = parsedDate;
|
|
293
|
-
return { value: this.value, switchToNext: true };
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
if (isZeroCurrentChar) {
|
|
297
|
-
this.setExisting(symbol, false);
|
|
298
|
-
}
|
|
299
|
-
return { value: null, switchToNext: false };
|
|
300
|
-
}
|
|
301
|
-
resetLeadingZero() {
|
|
302
|
-
const hasLeadingZero = this.leadingZero !== null;
|
|
303
|
-
this.setLeadingZero(null);
|
|
304
|
-
return hasLeadingZero;
|
|
305
|
-
}
|
|
306
|
-
setLeadingZero(leadingZero) {
|
|
307
|
-
this.leadingZero = leadingZero;
|
|
308
|
-
}
|
|
309
|
-
normalizeCentury(date) {
|
|
310
|
-
if (!isPresent(date)) {
|
|
311
|
-
return date;
|
|
312
|
-
}
|
|
313
|
-
const twoDigitYear = cropTwoDigitYear(date);
|
|
314
|
-
const centuryBase = this.getNormalizedCenturyBase(twoDigitYear);
|
|
315
|
-
const normalizedDate = setYears(date, centuryBase + twoDigitYear);
|
|
316
|
-
return normalizedDate;
|
|
317
|
-
}
|
|
318
|
-
incrementLeadingZero(symbol) {
|
|
319
|
-
const leadingZero = this.leadingZero || {};
|
|
320
|
-
leadingZero[symbol] = (leadingZero[symbol] || 0) + 1;
|
|
321
|
-
this.leadingZero = leadingZero;
|
|
322
|
-
}
|
|
323
|
-
isAbbrMonth(parts, symbol) {
|
|
324
|
-
const pattern = this.partPattern(parts, symbol);
|
|
325
|
-
return pattern.type === 'month' && pattern.names;
|
|
326
|
-
}
|
|
327
|
-
partPattern(parts, symbol) {
|
|
328
|
-
return parts.filter((part) => part.pattern.indexOf(symbol) !== -1)[0];
|
|
329
|
-
}
|
|
330
|
-
peek(value, pattern) {
|
|
331
|
-
const peekValue = unpadZero(value) + '0';
|
|
332
|
-
return padZero(pattern.length - peekValue.length) + peekValue;
|
|
333
|
-
}
|
|
334
|
-
matchMonth(typedChar) {
|
|
335
|
-
this.typedMonthPart += typedChar.toLowerCase();
|
|
336
|
-
if (!this.monthNames) {
|
|
337
|
-
return "";
|
|
338
|
-
}
|
|
339
|
-
while (this.typedMonthPart.length > 0) {
|
|
340
|
-
for (let i = 0; i < this.monthNames.length; i++) {
|
|
341
|
-
if (this.monthNames[i].toLowerCase().indexOf(this.typedMonthPart) === 0) {
|
|
342
|
-
return this.monthNames[i];
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
const monthAsNum = parseInt(this.typedMonthPart, 10);
|
|
346
|
-
if (monthAsNum >= 1 && monthAsNum <= 12 && monthAsNum.toString() === this.typedMonthPart /*ensure they exact match*/) {
|
|
347
|
-
return this.monthNames[monthAsNum - 1];
|
|
348
|
-
}
|
|
349
|
-
this.typedMonthPart = this.typedMonthPart.substring(1, this.typedMonthPart.length);
|
|
350
|
-
}
|
|
351
|
-
return "";
|
|
352
|
-
}
|
|
353
|
-
matchDayPeriod(typedChar, symbol) {
|
|
354
|
-
const lowerChart = String(typedChar).toLowerCase();
|
|
355
|
-
if (symbol === 'a' && this.dayPeriods) {
|
|
356
|
-
if (this.dayPeriods.am.toLowerCase().startsWith(lowerChart)) {
|
|
357
|
-
return this.dayPeriods.am;
|
|
358
|
-
}
|
|
359
|
-
else if (this.dayPeriods.pm.toLowerCase().startsWith(lowerChart)) {
|
|
360
|
-
return this.dayPeriods.pm;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
return '';
|
|
364
|
-
}
|
|
365
|
-
allFormatedMonths() {
|
|
366
|
-
const dateFormatParts = this.intl.splitDateFormat(this.format);
|
|
367
|
-
for (let i = 0; i < dateFormatParts.length; i++) {
|
|
368
|
-
if (dateFormatParts[i].type === "month" && dateFormatParts[i].names) {
|
|
369
|
-
return this.intl.dateFormatNames(dateFormatParts[i].names);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
|
-
allDayPeriods() {
|
|
375
|
-
const dateFormatParts = this.intl.splitDateFormat(this.format);
|
|
376
|
-
for (let i = 0; i < dateFormatParts.length; i++) {
|
|
377
|
-
if (dateFormatParts[i].type === "dayperiod" && dateFormatParts[i].names) {
|
|
378
|
-
return this.intl.dateFormatNames(dateFormatParts[i].names);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
return null;
|
|
382
|
-
}
|
|
383
|
-
patternLength(pattern) {
|
|
384
|
-
if (pattern[0] === 'y') {
|
|
385
|
-
return 4;
|
|
386
|
-
}
|
|
387
|
-
if (SHORT_PATTERN_LENGTH_REGEXP.test(pattern)) {
|
|
388
|
-
return 2;
|
|
389
|
-
}
|
|
390
|
-
return 0;
|
|
391
|
-
}
|
|
392
|
-
//TODO: REMOVE!
|
|
393
|
-
dateFormatString(date, format) {
|
|
394
|
-
const dateFormatParts = this.intl.splitDateFormat(format);
|
|
395
|
-
const parts = [];
|
|
396
|
-
const partMap = [];
|
|
397
|
-
for (let i = 0; i < dateFormatParts.length; i++) {
|
|
398
|
-
let partLength = this.intl.formatDate(date, { pattern: dateFormatParts[i].pattern }).length;
|
|
399
|
-
while (partLength > 0) {
|
|
400
|
-
parts.push(this.symbols[dateFormatParts[i].pattern[0]] || "_");
|
|
401
|
-
partMap.push(dateFormatParts[i]);
|
|
402
|
-
partLength--;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
const returnValue = new Mask();
|
|
406
|
-
returnValue.symbols = parts.join("");
|
|
407
|
-
returnValue.partMap = partMap;
|
|
408
|
-
return returnValue;
|
|
409
|
-
}
|
|
410
|
-
merge(text, mask) {
|
|
411
|
-
// Important: right to left.
|
|
412
|
-
let resultText = "";
|
|
413
|
-
let resultFormat = "";
|
|
414
|
-
const format = mask.symbols;
|
|
415
|
-
for (let r = format.length - 1; r >= 0; r--) {
|
|
416
|
-
if (this.knownParts.indexOf(format[r]) === -1 || this.getExisting(format[r])) {
|
|
417
|
-
resultText = text[r] + resultText;
|
|
418
|
-
resultFormat = format[r] + resultFormat;
|
|
419
|
-
}
|
|
420
|
-
else {
|
|
421
|
-
const currentSymbol = format[r];
|
|
422
|
-
while (r >= 0 && currentSymbol === format[r]) {
|
|
423
|
-
r--;
|
|
424
|
-
}
|
|
425
|
-
r++;
|
|
426
|
-
if (this.leadingZero && this.leadingZero[currentSymbol]) {
|
|
427
|
-
resultText = '0' + resultText;
|
|
428
|
-
}
|
|
429
|
-
else {
|
|
430
|
-
resultText = this.dateFieldName(mask.partMap[r]) + resultText;
|
|
431
|
-
}
|
|
432
|
-
while (resultFormat.length < resultText.length) {
|
|
433
|
-
resultFormat = format[r] + resultFormat;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
return [resultText, resultFormat];
|
|
438
|
-
}
|
|
439
|
-
dateFieldName(part) {
|
|
440
|
-
const formatPlaceholder = this.formatPlaceholder || 'wide';
|
|
441
|
-
if (formatPlaceholder[part.type]) {
|
|
442
|
-
return formatPlaceholder[part.type];
|
|
443
|
-
}
|
|
444
|
-
if (formatPlaceholder === 'formatPattern') {
|
|
445
|
-
return part.pattern;
|
|
446
|
-
}
|
|
447
|
-
return this.intl.dateFieldName(Object.assign(part, { nameType: formatPlaceholder }));
|
|
448
|
-
}
|
|
449
|
-
getNormalizedCenturyBase(twoDigitYear) {
|
|
450
|
-
return twoDigitYear > this.twoDigitYearMax ?
|
|
451
|
-
PREVIOUS_CENTURY_BASE :
|
|
452
|
-
CURRENT_CENTURY_BASE;
|
|
38
|
+
const DEFAULT_FORMAT_PLACEHOLDER = 'wide';
|
|
39
|
+
const DATE_PART_REGEXP = /year|month|<day>/;
|
|
40
|
+
const TIME_PART_REGEXP = /hour|minute|second|millisecond/;
|
|
41
|
+
/**
|
|
42
|
+
* @hidden
|
|
43
|
+
* Need to overrite `dateFormatNames` parameters order and provide `cldr` object
|
|
44
|
+
* required by the kendo-dateinputs-common package
|
|
45
|
+
*/
|
|
46
|
+
export class DateInputIntl {
|
|
47
|
+
constructor(service) {
|
|
48
|
+
this.service = service;
|
|
49
|
+
this.cldr = {};
|
|
50
|
+
this.localeId = service['localeId'];
|
|
51
|
+
this.format = service.format;
|
|
52
|
+
this.toString = service.toString;
|
|
53
|
+
this.formatDate = service.formatDate;
|
|
54
|
+
this.parseDate = service.parseDate;
|
|
55
|
+
this.parseNumber = service.parseNumber;
|
|
56
|
+
this.formatNumber = service.formatNumber;
|
|
57
|
+
this.splitDateFormat = service.splitDateFormat;
|
|
58
|
+
this.numberSymbols = service.numberSymbols;
|
|
59
|
+
this.firstDay = service.firstDay;
|
|
60
|
+
this.weekendRange = service.weekendRange;
|
|
61
|
+
this.dateFieldName = service.dateFieldName;
|
|
62
|
+
this.dateFormatNames = (localeId, options) => this.service.dateFormatNames(options, localeId || this.localeId);
|
|
63
|
+
const _localeData = localeData(this.localeId);
|
|
64
|
+
// Setting the `cldr` object from here could be avoided if the logic in the common package is revisited to
|
|
65
|
+
// directly relies on the `localeId` being set as part of the options => TBD and validated for all suites
|
|
66
|
+
this.cldr[_localeData.name] = _localeData;
|
|
453
67
|
}
|
|
454
68
|
}
|
|
455
69
|
/**
|
|
@@ -545,16 +159,50 @@ export class DateInputComponent {
|
|
|
545
159
|
* }
|
|
546
160
|
* ```
|
|
547
161
|
*/
|
|
548
|
-
this.steps = {
|
|
162
|
+
this.steps = {
|
|
163
|
+
// Default values are needed until fix in common package: https://github.com/telerik/kendo-dateinputs-common/issues/26
|
|
164
|
+
second: 1,
|
|
165
|
+
minute: 1,
|
|
166
|
+
hour: 1,
|
|
167
|
+
day: 1,
|
|
168
|
+
month: 1,
|
|
169
|
+
year: 1
|
|
170
|
+
};
|
|
549
171
|
/**
|
|
550
172
|
* Determines whether the built-in min or max validators are to be enforced when a form is being validated.
|
|
551
173
|
*/
|
|
552
174
|
this.rangeValidation = true;
|
|
553
175
|
/**
|
|
554
176
|
* @hidden
|
|
555
|
-
*
|
|
177
|
+
*
|
|
178
|
+
* Determines whether to auto correct invalid segments automatically.
|
|
179
|
+
* TODO: To be fixed in common package before enabling: https://github.com/telerik/kendo-dateinputs-common/issues/24
|
|
180
|
+
*
|
|
181
|
+
* @default true
|
|
182
|
+
*/
|
|
183
|
+
this.autoCorrectParts = true;
|
|
184
|
+
/**
|
|
185
|
+
* Determines whether to automatically move to the next segment after the user completes the current one.
|
|
186
|
+
*
|
|
187
|
+
* @default true
|
|
188
|
+
*/
|
|
189
|
+
this.autoSwitchParts = true;
|
|
190
|
+
/**
|
|
191
|
+
* A string array representing custom keys, which will move the focus to the next date format segment.
|
|
192
|
+
*/
|
|
193
|
+
this.autoSwitchKeys = [];
|
|
194
|
+
/**
|
|
195
|
+
* Determines if the users should see a blinking caret inside the Date Input when possible.
|
|
196
|
+
*
|
|
197
|
+
* @default false
|
|
198
|
+
*/
|
|
199
|
+
this.allowCaretMode = false;
|
|
200
|
+
/**
|
|
201
|
+
* When enabled, the DateInput will autofill the rest of the date to the current date when the component loses focus.
|
|
202
|
+
*
|
|
203
|
+
* @default false
|
|
556
204
|
*/
|
|
557
|
-
this.
|
|
205
|
+
this.autoFill = false;
|
|
558
206
|
/**
|
|
559
207
|
* Determines whether the built-in validation for incomplete dates is to be enforced when a form is being validated.
|
|
560
208
|
*/
|
|
@@ -567,6 +215,12 @@ export class DateInputComponent {
|
|
|
567
215
|
* will be assumed to be 20xx, while 69 and larger will be assumed to be 19xx.
|
|
568
216
|
*/
|
|
569
217
|
this.twoDigitYearMax = TWO_DIGIT_YEAR_MAX;
|
|
218
|
+
/**
|
|
219
|
+
* Indicates whether the mouse scroll can be used to increase/decrease the time segments values.
|
|
220
|
+
*
|
|
221
|
+
* @default true
|
|
222
|
+
*/
|
|
223
|
+
this.enableMouseWheel = true;
|
|
570
224
|
/**
|
|
571
225
|
* Specifies whether the **Up** and **Down** spin buttons will be rendered.
|
|
572
226
|
* For more information, refer to the article on
|
|
@@ -643,18 +297,16 @@ export class DateInputComponent {
|
|
|
643
297
|
* @hidden
|
|
644
298
|
*/
|
|
645
299
|
this.isDateIncomplete = false;
|
|
646
|
-
this.currentValue = "";
|
|
647
300
|
this.currentFormat = "";
|
|
648
|
-
this.backspace = false;
|
|
649
|
-
this.resetSegmentValue = true;
|
|
650
301
|
this.minValidator = noop;
|
|
651
302
|
this.maxValidator = noop;
|
|
652
303
|
this.incompleteValidator = noop;
|
|
653
304
|
this._value = null;
|
|
654
305
|
this._active = false;
|
|
655
306
|
this._focusableId = `dateinput-${nextId++}`;
|
|
307
|
+
this._formatPlaceholder = DEFAULT_FORMAT_PLACEHOLDER;
|
|
656
308
|
this.kendoDate = null;
|
|
657
|
-
this.
|
|
309
|
+
this.kendoDateObject = null;
|
|
658
310
|
this.domEvents = [];
|
|
659
311
|
this.onControlChange = noop;
|
|
660
312
|
this.onControlTouched = noop;
|
|
@@ -663,8 +315,7 @@ export class DateInputComponent {
|
|
|
663
315
|
this._rounded = DEFAULT_ROUNDED;
|
|
664
316
|
this._fillMode = DEFAULT_FILL_MODE;
|
|
665
317
|
this.subs = new Subscription();
|
|
666
|
-
|
|
667
|
-
this.updateFormatSections();
|
|
318
|
+
validatePackage(packageMetadata);
|
|
668
319
|
if (this.pickerService) {
|
|
669
320
|
this.pickerService.input = this;
|
|
670
321
|
}
|
|
@@ -701,6 +352,58 @@ export class DateInputComponent {
|
|
|
701
352
|
get tabIndex() {
|
|
702
353
|
return this.tabindex;
|
|
703
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Defines the descriptions of the format sections in the input field.
|
|
357
|
+
* For more information, refer to the article on
|
|
358
|
+
* [placeholders]({% slug placeholders_dateinput %}).
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```ts
|
|
362
|
+
* _@Component({
|
|
363
|
+
* selector: 'my-app',
|
|
364
|
+
* template: `
|
|
365
|
+
* <div class="row example-wrapper" [style.min-height.px]="450">
|
|
366
|
+
* <div class="col-xs-12 col-md-6 example-col">
|
|
367
|
+
* <p>Full-length format description:</p>
|
|
368
|
+
* <kendo-dateinput formatPlaceholder="wide"></kendo-dateinput>
|
|
369
|
+
* </div>
|
|
370
|
+
*
|
|
371
|
+
* <div class="col-xs-12 col-md-6 example-col">
|
|
372
|
+
* <p>Narrow-length format description:</p>
|
|
373
|
+
* <kendo-dateinput formatPlaceholder="narrow"></kendo-dateinput>
|
|
374
|
+
* </div>
|
|
375
|
+
*
|
|
376
|
+
* <div class="col-xs-12 col-md-6 example-col">
|
|
377
|
+
* <p>Short-length format description:</p>
|
|
378
|
+
* <kendo-dateinput formatPlaceholder="short"></kendo-dateinput>
|
|
379
|
+
* </div>
|
|
380
|
+
*
|
|
381
|
+
* <div class="col-xs-12 col-md-6 example-col">
|
|
382
|
+
* <p>Display defined format:</p>
|
|
383
|
+
* <kendo-dateinput format="MM/dd/yyyy" formatPlaceholder="formatPattern"></kendo-dateinput>
|
|
384
|
+
* </div>
|
|
385
|
+
*
|
|
386
|
+
* <div class="col-xs-12 col-md-6 example-col">
|
|
387
|
+
* <p>Custom defined format descriptions</p>
|
|
388
|
+
* <kendo-dateinput format="G"
|
|
389
|
+
* [formatPlaceholder]="{
|
|
390
|
+
* year: 'y', month: 'M', day: 'd',
|
|
391
|
+
* hour: 'h', minute: 'm', second: 's'
|
|
392
|
+
* }"
|
|
393
|
+
* ></kendo-dateinput>
|
|
394
|
+
* </div>
|
|
395
|
+
* </div>
|
|
396
|
+
* `
|
|
397
|
+
* })
|
|
398
|
+
* export class AppComponent { }
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
set formatPlaceholder(format) {
|
|
402
|
+
this._formatPlaceholder = format ? format : DEFAULT_FORMAT_PLACEHOLDER;
|
|
403
|
+
}
|
|
404
|
+
get formatPlaceholder() {
|
|
405
|
+
return this._formatPlaceholder;
|
|
406
|
+
}
|
|
704
407
|
/**
|
|
705
408
|
* Specifies the value of the DateInput component.
|
|
706
409
|
*
|
|
@@ -708,9 +411,6 @@ export class DateInputComponent {
|
|
|
708
411
|
*/
|
|
709
412
|
set value(value) {
|
|
710
413
|
this.verifyValue(value);
|
|
711
|
-
if (this.autoCorrect && !isInRange(value, this.min, this.max)) {
|
|
712
|
-
return;
|
|
713
|
-
}
|
|
714
414
|
this._value = cloneDate(value);
|
|
715
415
|
this.valueUpdate.emit(cloneDate(value));
|
|
716
416
|
}
|
|
@@ -822,34 +522,39 @@ export class DateInputComponent {
|
|
|
822
522
|
const ngControl = this.injector.get(NgControl, null);
|
|
823
523
|
return ngControl?.control || null;
|
|
824
524
|
}
|
|
825
|
-
get
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
return this.format.displayFormat;
|
|
845
|
-
}
|
|
525
|
+
get options() {
|
|
526
|
+
return {
|
|
527
|
+
format: this.format,
|
|
528
|
+
steps: this.steps,
|
|
529
|
+
readonly: this.readonly,
|
|
530
|
+
formatPlaceholder: this.formatPlaceholder,
|
|
531
|
+
placeholder: this.placeholder,
|
|
532
|
+
autoCorrectParts: this.autoCorrectParts,
|
|
533
|
+
autoSwitchParts: this.autoSwitchParts,
|
|
534
|
+
selectPreviousSegmentOnBackspace: true,
|
|
535
|
+
autoSwitchKeys: this.autoSwitchKeys,
|
|
536
|
+
twoDigitYearMax: this.twoDigitYearMax,
|
|
537
|
+
enableMouseWheel: this.enableMouseWheel,
|
|
538
|
+
selectNearestSegmentOnFocus: false,
|
|
539
|
+
allowCaretMode: this.allowCaretMode,
|
|
540
|
+
autoFill: this.autoFill,
|
|
541
|
+
value: this.value,
|
|
542
|
+
intlService: new DateInputIntl(this.intl)
|
|
543
|
+
};
|
|
846
544
|
}
|
|
847
545
|
/**
|
|
848
546
|
* @hidden
|
|
849
547
|
* Used by the TextBoxContainer to determine if the component is empty
|
|
850
548
|
*/
|
|
851
549
|
isEmpty() {
|
|
852
|
-
|
|
550
|
+
const currentValue = this.dateInput.nativeElement.value;
|
|
551
|
+
return !currentValue || !String(currentValue).trim();
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* @hidden
|
|
555
|
+
*/
|
|
556
|
+
handleDragAndDrop(args) {
|
|
557
|
+
args.preventDefault();
|
|
853
558
|
}
|
|
854
559
|
/**
|
|
855
560
|
* @hidden
|
|
@@ -861,15 +566,16 @@ export class DateInputComponent {
|
|
|
861
566
|
* @hidden
|
|
862
567
|
*/
|
|
863
568
|
ngOnInit() {
|
|
864
|
-
|
|
865
|
-
|
|
569
|
+
if (this.kendoDate) {
|
|
570
|
+
this.kendoDate.destroy();
|
|
571
|
+
}
|
|
572
|
+
this.kendoDate = this.initKendoDate();
|
|
573
|
+
this.kendoDateObject = this.kendoDate.dateObject;
|
|
574
|
+
this.updateFormatSections();
|
|
866
575
|
this.subs.add(this.intl.changes.subscribe(this.intlChange.bind(this)));
|
|
867
576
|
this.ngControl = this.injector.get(NgControl, null);
|
|
868
577
|
if (this.wrapper) {
|
|
869
578
|
this.renderer.removeAttribute(this.wrapper.nativeElement, 'tabindex');
|
|
870
|
-
this.ngZone.runOutsideAngular(() => {
|
|
871
|
-
this.bindEvents();
|
|
872
|
-
});
|
|
873
579
|
}
|
|
874
580
|
}
|
|
875
581
|
/**
|
|
@@ -883,14 +589,37 @@ export class DateInputComponent {
|
|
|
883
589
|
this.incompleteValidator = this.incompleteDateValidation ? incompleteDateValidator() : noop;
|
|
884
590
|
this.onValidatorChange();
|
|
885
591
|
}
|
|
886
|
-
|
|
887
|
-
|
|
592
|
+
const isEqualToKendoDate = this.kendoDate && isEqual(this.value, this.kendoDate.value);
|
|
593
|
+
if (changes['format'] || !isEqualToKendoDate || changes['placeholder']) {
|
|
594
|
+
if (!this.kendoDate) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
;
|
|
598
|
+
this.kendoDate?.setOptions(this.options, true);
|
|
888
599
|
this.updateFormatSections();
|
|
889
600
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
601
|
+
}
|
|
602
|
+
updateFormatSections() {
|
|
603
|
+
this.formatSections = this.intl.splitDateFormat(this.kendoDate.inputFormat)
|
|
604
|
+
.reduce(({ date, time }, p) => {
|
|
605
|
+
return {
|
|
606
|
+
date: date || DATE_PART_REGEXP.test(p.type),
|
|
607
|
+
time: time || TIME_PART_REGEXP.test(p.type)
|
|
608
|
+
};
|
|
609
|
+
}, { date: false, time: false });
|
|
610
|
+
}
|
|
611
|
+
updateIncompleteValidationStatus() {
|
|
612
|
+
const previousValue = this.isDateIncomplete;
|
|
613
|
+
this.isDateIncomplete = this.kendoDateObject.hasValue() && this.value === null;
|
|
614
|
+
if (previousValue === this.isDateIncomplete || !this.incompleteDateValidation) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (isPresent(this.ngControl) && !isPresent(this.pickerService)) {
|
|
618
|
+
this.cdr.markForCheck();
|
|
619
|
+
this.ngZone.run(() => this.onValidatorChange());
|
|
620
|
+
}
|
|
621
|
+
else if (isPresent(this.pickerService)) {
|
|
622
|
+
this.pickerService.dateCompletenessChange.emit();
|
|
894
623
|
}
|
|
895
624
|
}
|
|
896
625
|
ngAfterViewInit() {
|
|
@@ -946,15 +675,16 @@ export class DateInputComponent {
|
|
|
946
675
|
*/
|
|
947
676
|
writeValue(value) {
|
|
948
677
|
this.verifyValue(value);
|
|
949
|
-
this.kendoDate = this.getKendoDate(value);
|
|
950
678
|
this.value = cloneDate(value);
|
|
951
|
-
this.
|
|
679
|
+
this.kendoDate?.setOptions(this.options, true);
|
|
680
|
+
this.kendoDateObject?.setValue(this.value);
|
|
681
|
+
this.kendoDate?.refreshElementValue();
|
|
952
682
|
}
|
|
953
683
|
/**
|
|
954
684
|
* @hidden
|
|
955
685
|
*/
|
|
956
686
|
triggerChange() {
|
|
957
|
-
const value = this.kendoDate.
|
|
687
|
+
const value = this.kendoDate.value;
|
|
958
688
|
if (+value !== +this.value) {
|
|
959
689
|
this.value = cloneDate(value);
|
|
960
690
|
this.notify();
|
|
@@ -997,11 +727,7 @@ export class DateInputComponent {
|
|
|
997
727
|
* ```
|
|
998
728
|
*/
|
|
999
729
|
focus() {
|
|
1000
|
-
|
|
1001
|
-
if (input) {
|
|
1002
|
-
input.focus();
|
|
1003
|
-
this.selectDateSegment(this.currentFormat[0]);
|
|
1004
|
-
}
|
|
730
|
+
this.kendoDate && this.kendoDate.focus();
|
|
1005
731
|
}
|
|
1006
732
|
/**
|
|
1007
733
|
* Blurs the DateInput component.
|
|
@@ -1017,220 +743,53 @@ export class DateInputComponent {
|
|
|
1017
743
|
*/
|
|
1018
744
|
handleButtonClick(offset) {
|
|
1019
745
|
this.arrowDirection = Arrow.None;
|
|
1020
|
-
this.
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
}
|
|
1033
|
-
this.kendoDate.modifyPart(symbol, offset * step);
|
|
1034
|
-
this.putDateInRange();
|
|
1035
|
-
this.updateElementValue(this.isActive);
|
|
1036
|
-
this.triggerChange();
|
|
1037
|
-
this.selectDateSegment(symbol);
|
|
1038
|
-
this.updateIncompleteValidationStatus();
|
|
1039
|
-
}
|
|
1040
|
-
/**
|
|
1041
|
-
* @hidden
|
|
1042
|
-
*/
|
|
1043
|
-
switchDateSegment(offset) {
|
|
1044
|
-
const caret = this.caret();
|
|
1045
|
-
if (this.kendoDate.resetLeadingZero()) {
|
|
1046
|
-
this.updateElementValue(this.isActive);
|
|
1047
|
-
}
|
|
1048
|
-
if (caret[0] < caret[1] && this.currentFormat[caret[0]] !== this.currentFormat[caret[1] - 1]) {
|
|
1049
|
-
this.selectNearestSegment(offset > 0 ? caret[0] : caret[1] - 1);
|
|
1050
|
-
this.resetSegmentValue = true;
|
|
1051
|
-
return true;
|
|
1052
|
-
}
|
|
1053
|
-
const previousFormatSymbol = this.currentFormat[caret[0]];
|
|
1054
|
-
let a = caret[0] + offset;
|
|
1055
|
-
while (a > 0 && a < this.currentFormat.length) {
|
|
1056
|
-
if (this.currentFormat[a] !== previousFormatSymbol &&
|
|
1057
|
-
this.currentFormat[a] !== "_") {
|
|
1058
|
-
break;
|
|
1059
|
-
}
|
|
1060
|
-
a += offset;
|
|
1061
|
-
}
|
|
1062
|
-
if (this.currentFormat[a] === "_") {
|
|
1063
|
-
//there is not known symbol found
|
|
1064
|
-
return false;
|
|
1065
|
-
}
|
|
1066
|
-
let b = a;
|
|
1067
|
-
while (b >= 0 && b < this.currentFormat.length) {
|
|
1068
|
-
if (this.currentFormat[b] !== this.currentFormat[a]) {
|
|
1069
|
-
break;
|
|
1070
|
-
}
|
|
1071
|
-
b += offset;
|
|
1072
|
-
}
|
|
1073
|
-
if (a > b && (b + 1 !== caret[0] || a + 1 !== caret[1])) {
|
|
1074
|
-
this.caret(b + 1, a + 1);
|
|
1075
|
-
this.resetSegmentValue = true;
|
|
1076
|
-
return true;
|
|
1077
|
-
}
|
|
1078
|
-
else if (a < b && (a !== caret[0] || b !== caret[1])) {
|
|
1079
|
-
this.caret(a, b);
|
|
1080
|
-
this.resetSegmentValue = true;
|
|
1081
|
-
return true;
|
|
1082
|
-
}
|
|
1083
|
-
return false;
|
|
1084
|
-
}
|
|
1085
|
-
/**
|
|
1086
|
-
* @hidden
|
|
1087
|
-
*/
|
|
1088
|
-
selectDateSegment(symbol) {
|
|
1089
|
-
let begin = -1;
|
|
1090
|
-
let end = 0;
|
|
1091
|
-
for (let i = 0; i < this.currentFormat.length; i++) {
|
|
1092
|
-
if (this.currentFormat[i] === symbol) {
|
|
1093
|
-
end = i + 1;
|
|
1094
|
-
if (begin === -1) {
|
|
1095
|
-
begin = i;
|
|
1096
|
-
}
|
|
746
|
+
this.kendoDate.focus();
|
|
747
|
+
this.kendoDate.modifyDateSegmentValue(offset);
|
|
748
|
+
}
|
|
749
|
+
initKendoDate() {
|
|
750
|
+
const kendoDate = new DateInput(this.dateInput.nativeElement, {
|
|
751
|
+
...this.options,
|
|
752
|
+
events: {
|
|
753
|
+
valueChange: this.onWidgetValueChange.bind(this),
|
|
754
|
+
inputEnd: this.onWidgetInputEnd.bind(this),
|
|
755
|
+
focusEnd: this.onWidgetFocus.bind(this),
|
|
756
|
+
blurEnd: this.onWidgetBlur.bind(this),
|
|
757
|
+
keydown: this.onWidgetKeyDown.bind(this),
|
|
1097
758
|
}
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
begin = 0;
|
|
1101
|
-
}
|
|
1102
|
-
this.caret(0, 0);
|
|
1103
|
-
this.caret(begin, end);
|
|
759
|
+
});
|
|
760
|
+
return kendoDate;
|
|
1104
761
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
*/
|
|
1108
|
-
handleClick() {
|
|
1109
|
-
this.hasMousedown = false;
|
|
1110
|
-
if (this.isActive) {
|
|
1111
|
-
const selectionPresent = this.inputElement.selectionStart !== this.inputElement.selectionEnd;
|
|
1112
|
-
const placeholderToggled = isPresent(this.placeholder) && !this.kendoDate.hasValue() && !this.focusedPriorToMousedown;
|
|
1113
|
-
// focus first segment if the user hasn't selected something during mousedown and if the placeholder was just toggled
|
|
1114
|
-
const selectFirstSegment = !selectionPresent && placeholderToggled;
|
|
1115
|
-
const index = selectFirstSegment ? 0 : this.caret()[0];
|
|
1116
|
-
this.selectNearestSegment(index);
|
|
1117
|
-
}
|
|
762
|
+
onWidgetValueChange() {
|
|
763
|
+
this.triggerChange();
|
|
1118
764
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
*/
|
|
1122
|
-
handleDragAndDrop(args) {
|
|
1123
|
-
args.preventDefault();
|
|
765
|
+
onWidgetKeyDown() {
|
|
766
|
+
this.kendoDateObject = this.kendoDate.dateObject;
|
|
1124
767
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
*/
|
|
1128
|
-
handleMousedown() {
|
|
1129
|
-
this.hasMousedown = true;
|
|
1130
|
-
this.focusedPriorToMousedown = this.isActive;
|
|
768
|
+
onWidgetInputEnd() {
|
|
769
|
+
this.updateIncompleteValidationStatus();
|
|
1131
770
|
}
|
|
1132
|
-
|
|
1133
|
-
* @hidden
|
|
1134
|
-
*/
|
|
1135
|
-
handleFocus(args) {
|
|
1136
|
-
this.renderer.removeAttribute(this.inputElement, attributeNames.ariaActiveDescendant);
|
|
771
|
+
onWidgetFocus({ event: FocuseEvent }) {
|
|
1137
772
|
this.isActive = true;
|
|
1138
|
-
this.updateElementValue();
|
|
1139
|
-
if (!this.hasMousedown) {
|
|
1140
|
-
this.caret(0, this.inputValue.length);
|
|
1141
|
-
}
|
|
1142
|
-
this.hasMousedown = false;
|
|
1143
773
|
if (hasObservers(this.onFocus)) {
|
|
1144
774
|
this.ngZone.run(() => {
|
|
1145
|
-
this.emitFocus(
|
|
775
|
+
this.emitFocus(event);
|
|
1146
776
|
});
|
|
1147
777
|
}
|
|
1148
778
|
else {
|
|
1149
|
-
this.emitFocus(
|
|
779
|
+
this.emitFocus(event);
|
|
1150
780
|
}
|
|
1151
781
|
}
|
|
1152
|
-
|
|
1153
|
-
* @hidden
|
|
1154
|
-
*/
|
|
1155
|
-
handleBlur(args) {
|
|
782
|
+
onWidgetBlur({ event: FocuseEvent }) {
|
|
1156
783
|
this.isActive = false;
|
|
1157
|
-
this.resetSegmentValue = true;
|
|
1158
|
-
this.kendoDate.resetLeadingZero();
|
|
1159
|
-
this.updateElementValue();
|
|
1160
784
|
if (hasObservers(this.onBlur) || requiresZoneOnBlur(this.ngControl)) {
|
|
1161
785
|
this.ngZone.run(() => {
|
|
1162
786
|
this.onControlTouched();
|
|
1163
|
-
this.emitBlur(
|
|
787
|
+
this.emitBlur(event);
|
|
1164
788
|
this.cdr.markForCheck();
|
|
1165
789
|
});
|
|
1166
790
|
}
|
|
1167
791
|
else {
|
|
1168
|
-
this.emitBlur(
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
getKendoDate(value) {
|
|
1172
|
-
const { leadingZero } = (this.kendoDate || {}) || null;
|
|
1173
|
-
const kendoDate = new KendoDate(this.intl, this.formatPlaceholder, this.inputFormat, value, this.twoDigitYearMax);
|
|
1174
|
-
kendoDate.setLeadingZero(this.isActive ? leadingZero : null);
|
|
1175
|
-
return kendoDate;
|
|
1176
|
-
}
|
|
1177
|
-
dateSymbolMap() {
|
|
1178
|
-
const reducer = (map, part) => {
|
|
1179
|
-
map[part.pattern[0]] = part.type;
|
|
1180
|
-
return map;
|
|
1181
|
-
};
|
|
1182
|
-
return this.intl.splitDateFormat(this.inputFormat).reduce(reducer, {});
|
|
1183
|
-
}
|
|
1184
|
-
updateElementValue(isActive) {
|
|
1185
|
-
const start = this.caret()[0]; //XXX: get caret position before input is updated
|
|
1186
|
-
const format = this.isActive ? this.inputFormat : this.displayFormat;
|
|
1187
|
-
const texts = this.kendoDate.getTextAndFormat(format);
|
|
1188
|
-
const showPlaceholder = !this.isActive && isPresent(this.placeholder) && !this.kendoDate.hasValue();
|
|
1189
|
-
const input = this.inputElement;
|
|
1190
|
-
this.currentFormat = texts[1];
|
|
1191
|
-
this.currentValue = !showPlaceholder ? texts[0] : '';
|
|
1192
|
-
this.renderer.setProperty(input, "value", this.currentValue);
|
|
1193
|
-
if (input.placeholder !== this.placeholder) {
|
|
1194
|
-
this.renderer.setProperty(input, "placeholder", this.placeholder);
|
|
1195
|
-
}
|
|
1196
|
-
if (isActive) {
|
|
1197
|
-
this.selectNearestSegment(start);
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
caret(start, end = start) {
|
|
1201
|
-
const isPosition = start !== undefined;
|
|
1202
|
-
let returnValue = [start, start];
|
|
1203
|
-
const element = this.inputElement;
|
|
1204
|
-
if (isPosition && (this.disabled || this.readonly)) {
|
|
1205
|
-
return undefined;
|
|
1206
|
-
}
|
|
1207
|
-
try {
|
|
1208
|
-
if (element.selectionStart !== undefined) {
|
|
1209
|
-
if (isPosition) {
|
|
1210
|
-
if (isDocumentAvailable() && document.activeElement !== element) {
|
|
1211
|
-
element.focus();
|
|
1212
|
-
}
|
|
1213
|
-
element.setSelectionRange(start, end);
|
|
1214
|
-
}
|
|
1215
|
-
returnValue = [element.selectionStart, element.selectionEnd];
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
catch (e) {
|
|
1219
|
-
returnValue = [];
|
|
1220
|
-
}
|
|
1221
|
-
return returnValue;
|
|
1222
|
-
}
|
|
1223
|
-
selectNearestSegment(index) {
|
|
1224
|
-
// Finds the nearest (in both directions) known part.
|
|
1225
|
-
for (let i = index, j = index - 1; i < this.currentFormat.length || j >= 0; i++, j--) {
|
|
1226
|
-
if (i < this.currentFormat.length && this.currentFormat[i] !== "_") {
|
|
1227
|
-
this.selectDateSegment(this.currentFormat[i]);
|
|
1228
|
-
return;
|
|
1229
|
-
}
|
|
1230
|
-
if (j >= 0 && this.currentFormat[j] !== "_") {
|
|
1231
|
-
this.selectDateSegment(this.currentFormat[j]);
|
|
1232
|
-
return;
|
|
1233
|
-
}
|
|
792
|
+
this.emitBlur(event);
|
|
1234
793
|
}
|
|
1235
794
|
}
|
|
1236
795
|
verifyRange() {
|
|
@@ -1249,135 +808,9 @@ export class DateInputComponent {
|
|
|
1249
808
|
throw new Error(`The 'value' should be a valid JavaScript Date instance. Check ${VALUE_DOC_LINK} for possible resolution.`);
|
|
1250
809
|
}
|
|
1251
810
|
}
|
|
1252
|
-
putDateInRange() {
|
|
1253
|
-
const currentDate = this.kendoDate.getDateObject();
|
|
1254
|
-
const candidate = dateInRange(currentDate, this.min, this.max);
|
|
1255
|
-
if (this.autoCorrect && !isEqual(currentDate, candidate)) {
|
|
1256
|
-
this.kendoDate = this.getKendoDate(candidate);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
updateFormatSections() {
|
|
1260
|
-
this.formatSections = this.intl.splitDateFormat(this.inputFormat)
|
|
1261
|
-
.reduce(({ date, time }, p) => {
|
|
1262
|
-
return {
|
|
1263
|
-
date: date || DATE_PART_REGEXP.test(p.type),
|
|
1264
|
-
time: time || TIME_PART_REGEXP.test(p.type)
|
|
1265
|
-
};
|
|
1266
|
-
}, { date: false, time: false });
|
|
1267
|
-
}
|
|
1268
811
|
intlChange() {
|
|
812
|
+
this.kendoDate.setOptions(this.options, true);
|
|
1269
813
|
this.updateFormatSections();
|
|
1270
|
-
this.kendoDate = this.getKendoDate(this.value);
|
|
1271
|
-
this.updateElementValue(this.isActive);
|
|
1272
|
-
}
|
|
1273
|
-
updateOnPaste() {
|
|
1274
|
-
let value = this.intl.parseDate(this.inputValue, this.inputFormat) || this.value;
|
|
1275
|
-
if (isPresent(value) && this.kendoDate.shouldNormalizeCentury()) {
|
|
1276
|
-
value = this.kendoDate.normalizeCentury(value);
|
|
1277
|
-
}
|
|
1278
|
-
const notify = +value !== +this.value;
|
|
1279
|
-
this.writeValue(value);
|
|
1280
|
-
if (notify) {
|
|
1281
|
-
this.notify();
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1284
|
-
bindEvents() {
|
|
1285
|
-
const element = this.wrapper.nativeElement;
|
|
1286
|
-
const mousewheelHandler = this.handleMouseWheel.bind(this);
|
|
1287
|
-
this.domEvents.push(this.renderer.listen(element, 'DOMMouseScroll', mousewheelHandler), this.renderer.listen(element, 'mousewheel', mousewheelHandler), this.renderer.listen(element, 'keydown', this.handleKeydown.bind(this)), this.renderer.listen(element, 'paste', this.handlePaste.bind(this)), this.renderer.listen(element, 'input', this.handleInput.bind(this)));
|
|
1288
|
-
}
|
|
1289
|
-
handleMouseWheel(event) {
|
|
1290
|
-
if (this.disabled || this.readonly || !this.isActive) {
|
|
1291
|
-
return;
|
|
1292
|
-
}
|
|
1293
|
-
event = window.event || event;
|
|
1294
|
-
if (event.shiftKey) {
|
|
1295
|
-
this.switchDateSegment((event.wheelDelta || -event.detail) > 0 ? -1 : 1);
|
|
1296
|
-
}
|
|
1297
|
-
else {
|
|
1298
|
-
this.modifyDateSegmentValue((event.wheelDelta || -event.detail) > 0 ? 1 : -1);
|
|
1299
|
-
}
|
|
1300
|
-
event.returnValue = false;
|
|
1301
|
-
if (event.preventDefault) {
|
|
1302
|
-
event.preventDefault();
|
|
1303
|
-
}
|
|
1304
|
-
if (event.stopPropagation) {
|
|
1305
|
-
event.stopPropagation();
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
handlePaste() {
|
|
1309
|
-
this.paste = true;
|
|
1310
|
-
}
|
|
1311
|
-
handleKeydown(event) {
|
|
1312
|
-
if (this.disabled || this.readonly || event.altKey || event.ctrlKey || event.metaKey) {
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
|
-
if (event.keyCode === Keys.Backspace) {
|
|
1316
|
-
this.backspace = true;
|
|
1317
|
-
return;
|
|
1318
|
-
}
|
|
1319
|
-
switch (event.keyCode) {
|
|
1320
|
-
case Keys.ArrowDown:
|
|
1321
|
-
this.modifyDateSegmentValue(-1);
|
|
1322
|
-
break;
|
|
1323
|
-
case Keys.ArrowUp:
|
|
1324
|
-
this.modifyDateSegmentValue(1);
|
|
1325
|
-
break;
|
|
1326
|
-
case Keys.ArrowRight:
|
|
1327
|
-
this.switchDateSegment(1);
|
|
1328
|
-
break;
|
|
1329
|
-
case Keys.ArrowLeft:
|
|
1330
|
-
this.switchDateSegment(-1);
|
|
1331
|
-
break;
|
|
1332
|
-
case Keys.Home:
|
|
1333
|
-
this.selectNearestSegment(0);
|
|
1334
|
-
break;
|
|
1335
|
-
case Keys.End:
|
|
1336
|
-
this.selectNearestSegment(this.inputValue.length);
|
|
1337
|
-
break;
|
|
1338
|
-
default:
|
|
1339
|
-
return; //skip the preventDefault if we didn't handled the keyCode
|
|
1340
|
-
}
|
|
1341
|
-
event.preventDefault();
|
|
1342
|
-
}
|
|
1343
|
-
handleInput() {
|
|
1344
|
-
if (this.disabled || this.readonly) {
|
|
1345
|
-
return;
|
|
1346
|
-
}
|
|
1347
|
-
if (this.paste) {
|
|
1348
|
-
this.updateOnPaste();
|
|
1349
|
-
this.paste = false;
|
|
1350
|
-
return;
|
|
1351
|
-
}
|
|
1352
|
-
const diff = approximateStringMatching(this.currentValue, this.currentFormat, this.inputValue, this.caret()[0]);
|
|
1353
|
-
const navigationOnly = (diff.length === 1 && diff[0][1] === "_");
|
|
1354
|
-
let switchPart = false;
|
|
1355
|
-
if (!navigationOnly) {
|
|
1356
|
-
let parsedPart;
|
|
1357
|
-
for (let i = 0; i < diff.length; i++) {
|
|
1358
|
-
parsedPart = this.kendoDate.parsePart(diff[i][0], diff[i][1], this.resetSegmentValue);
|
|
1359
|
-
switchPart = parsedPart.switchToNext;
|
|
1360
|
-
}
|
|
1361
|
-
const candidate = this.kendoDate.getDateObject();
|
|
1362
|
-
if (this.value && candidate && !this.formatSections['date']) {
|
|
1363
|
-
this.kendoDate = this.getKendoDate(setTime(this.value, candidate));
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
this.resetSegmentValue = false;
|
|
1367
|
-
this.putDateInRange();
|
|
1368
|
-
this.updateElementValue(this.isActive);
|
|
1369
|
-
this.triggerChange();
|
|
1370
|
-
this.updateIncompleteValidationStatus();
|
|
1371
|
-
if (diff.length && diff[0][0] !== "_") {
|
|
1372
|
-
this.selectDateSegment(diff[0][0]);
|
|
1373
|
-
}
|
|
1374
|
-
if (switchPart || navigationOnly) {
|
|
1375
|
-
this.switchDateSegment(1);
|
|
1376
|
-
}
|
|
1377
|
-
if (this.backspace) {
|
|
1378
|
-
this.switchDateSegment(-1);
|
|
1379
|
-
}
|
|
1380
|
-
this.backspace = false;
|
|
1381
814
|
}
|
|
1382
815
|
emitFocus(args) {
|
|
1383
816
|
this.onFocus.emit();
|
|
@@ -1391,20 +824,6 @@ export class DateInputComponent {
|
|
|
1391
824
|
this.pickerService.onBlur.emit(args);
|
|
1392
825
|
}
|
|
1393
826
|
}
|
|
1394
|
-
updateIncompleteValidationStatus() {
|
|
1395
|
-
const previousValue = this.isDateIncomplete;
|
|
1396
|
-
this.isDateIncomplete = this.kendoDate.hasValue() && this.value === null;
|
|
1397
|
-
if (previousValue === this.isDateIncomplete || !this.incompleteDateValidation) {
|
|
1398
|
-
return;
|
|
1399
|
-
}
|
|
1400
|
-
if (isPresent(this.ngControl) && !isPresent(this.pickerService)) {
|
|
1401
|
-
this.cdr.markForCheck();
|
|
1402
|
-
this.ngZone.run(() => this.onValidatorChange());
|
|
1403
|
-
}
|
|
1404
|
-
else if (isPresent(this.pickerService)) {
|
|
1405
|
-
this.pickerService.dateCompletenessChange.emit();
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
827
|
setSpinnerFill(spinner, fill, oldFill) {
|
|
1409
828
|
if (oldFill !== 'none') {
|
|
1410
829
|
this.renderer.removeClass(spinner, `k-button-${oldFill}`);
|
|
@@ -1430,7 +849,7 @@ export class DateInputComponent {
|
|
|
1430
849
|
}
|
|
1431
850
|
}
|
|
1432
851
|
DateInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: DateInputComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.IntlService }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.Injector }, { token: i2.LocalizationService }, { token: i3.PickerService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
1433
|
-
DateInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.12", type: DateInputComponent, selector: "kendo-dateinput", inputs: { focusableId: "focusableId", pickerType: "pickerType", disabled: "disabled", readonly: "readonly", title: "title", tabindex: "tabindex", role: "role", ariaReadOnly: "ariaReadOnly", tabIndex: "tabIndex", format: "format", formatPlaceholder: "formatPlaceholder", placeholder: "placeholder", steps: "steps", max: "max", min: "min", rangeValidation: "rangeValidation",
|
|
852
|
+
DateInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.12", type: DateInputComponent, selector: "kendo-dateinput", inputs: { focusableId: "focusableId", pickerType: "pickerType", disabled: "disabled", readonly: "readonly", title: "title", tabindex: "tabindex", role: "role", ariaReadOnly: "ariaReadOnly", tabIndex: "tabIndex", format: "format", formatPlaceholder: "formatPlaceholder", placeholder: "placeholder", steps: "steps", max: "max", min: "min", rangeValidation: "rangeValidation", autoCorrectParts: "autoCorrectParts", autoSwitchParts: "autoSwitchParts", autoSwitchKeys: "autoSwitchKeys", allowCaretMode: "allowCaretMode", autoFill: "autoFill", incompleteDateValidation: "incompleteDateValidation", twoDigitYearMax: "twoDigitYearMax", enableMouseWheel: "enableMouseWheel", value: "value", spinners: "spinners", isPopupOpen: "isPopupOpen", hasPopup: "hasPopup", size: "size", rounded: "rounded", fillMode: "fillMode" }, outputs: { valueChange: "valueChange", valueUpdate: "valueUpdate", onFocus: "focus", onBlur: "blur" }, host: { properties: { "class.k-input": "this.wrapperClass", "class.k-dateinput": "this.wrapperClass", "class.k-disabled": "this.disabledClass" } }, providers: [
|
|
1434
853
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DateInputComponent), multi: true },
|
|
1435
854
|
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => DateInputComponent), multi: true },
|
|
1436
855
|
{ provide: L10N_PREFIX, useValue: 'kendo.dateinput' },
|
|
@@ -1463,13 +882,8 @@ DateInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", ver
|
|
|
1463
882
|
[attr.aria-expanded]="isPopupOpen"
|
|
1464
883
|
[attr.aria-haspopup]="hasPopup"
|
|
1465
884
|
[kendoEventsOutsideAngular]="{
|
|
1466
|
-
click: handleClick,
|
|
1467
|
-
focus: handleFocus,
|
|
1468
|
-
mousedown: handleMousedown,
|
|
1469
|
-
touchstart: handleMousedown,
|
|
1470
885
|
dragstart: handleDragAndDrop,
|
|
1471
|
-
drop: handleDragAndDrop
|
|
1472
|
-
blur: handleBlur
|
|
886
|
+
drop: handleDragAndDrop
|
|
1473
887
|
}"
|
|
1474
888
|
[scope]="this"
|
|
1475
889
|
/>
|
|
@@ -1552,13 +966,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
1552
966
|
[attr.aria-expanded]="isPopupOpen"
|
|
1553
967
|
[attr.aria-haspopup]="hasPopup"
|
|
1554
968
|
[kendoEventsOutsideAngular]="{
|
|
1555
|
-
click: handleClick,
|
|
1556
|
-
focus: handleFocus,
|
|
1557
|
-
mousedown: handleMousedown,
|
|
1558
|
-
touchstart: handleMousedown,
|
|
1559
969
|
dragstart: handleDragAndDrop,
|
|
1560
|
-
drop: handleDragAndDrop
|
|
1561
|
-
blur: handleBlur
|
|
970
|
+
drop: handleDragAndDrop
|
|
1562
971
|
}"
|
|
1563
972
|
[scope]="this"
|
|
1564
973
|
/>
|
|
@@ -1636,12 +1045,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
1636
1045
|
type: Input
|
|
1637
1046
|
}], rangeValidation: [{
|
|
1638
1047
|
type: Input
|
|
1639
|
-
}],
|
|
1048
|
+
}], autoCorrectParts: [{
|
|
1049
|
+
type: Input
|
|
1050
|
+
}], autoSwitchParts: [{
|
|
1051
|
+
type: Input
|
|
1052
|
+
}], autoSwitchKeys: [{
|
|
1053
|
+
type: Input
|
|
1054
|
+
}], allowCaretMode: [{
|
|
1055
|
+
type: Input
|
|
1056
|
+
}], autoFill: [{
|
|
1640
1057
|
type: Input
|
|
1641
1058
|
}], incompleteDateValidation: [{
|
|
1642
1059
|
type: Input
|
|
1643
1060
|
}], twoDigitYearMax: [{
|
|
1644
1061
|
type: Input
|
|
1062
|
+
}], enableMouseWheel: [{
|
|
1063
|
+
type: Input
|
|
1645
1064
|
}], value: [{
|
|
1646
1065
|
type: Input
|
|
1647
1066
|
}], spinners: [{
|