@imihai/angular-datetime-picker 22.0.8 → 22.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,29 +1,30 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Input, Directive, InjectionToken, inject, LOCALE_ID, Optional, Inject, Injectable, EventEmitter, Output, ChangeDetectionStrategy, Component, ViewChild, signal, TemplateRef, Injector, SkipSelf, untracked, forwardRef, Pipe, NgModule } from '@angular/core';
2
+ import { Input, Directive, InjectionToken, inject, LOCALE_ID, Optional, Inject, Injectable, Injector, DestroyRef, EventEmitter, afterNextRender, Output, ChangeDetectionStrategy, Component, ViewChild, signal, TemplateRef, SkipSelf, untracked, forwardRef, Pipe, NgModule } from '@angular/core';
3
3
  import * as i2 from '@angular/common';
4
4
  import { getLocaleFirstDayOfWeek, DOCUMENT, CommonModule } from '@angular/common';
5
5
  import * as i1 from '@angular/cdk/a11y';
6
6
  import { A11yModule } from '@angular/cdk/a11y';
7
7
  import * as i1$1 from '@angular/cdk/overlay';
8
8
  import { NoopScrollStrategy, Overlay, OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
9
- import { Subscription, of, merge, Subject, filter, take as take$1, defer } from 'rxjs';
9
+ import { coerceBooleanProperty, coerceNumberProperty, coerceArray } from '@angular/cdk/coercion';
10
+ import { Subscription, EMPTY, merge, Subject, filter, take, defer } from 'rxjs';
10
11
  import * as i2$1 from '@angular/cdk/portal';
11
12
  import { BasePortalOutlet, CdkPortalOutlet, ComponentPortal, PortalModule } from '@angular/cdk/portal';
12
13
  import { ENTER, PAGE_DOWN, PAGE_UP, END, HOME, DOWN_ARROW, UP_ARROW, RIGHT_ARROW, LEFT_ARROW, SPACE, ESCAPE } from '@angular/cdk/keycodes';
13
- import { coerceBooleanProperty, coerceNumberProperty, coerceArray } from '@angular/cdk/coercion';
14
- import { take, debounceTime, startWith, filter as filter$1 } from 'rxjs/operators';
14
+ import { debounceTime, startWith, take as take$1, filter as filter$1 } from 'rxjs/operators';
15
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
15
16
  import { NG_VALUE_ACCESSOR, NG_VALIDATORS, Validators } from '@angular/forms';
16
- import { Settings, Info, DateTime } from 'luxon';
17
+ import { Settings, DateTime, Info } from 'luxon';
17
18
 
18
19
  /**
19
20
  * date-time-picker-trigger.directive
20
21
  */
21
22
  class OwlDateTimeTriggerDirective {
22
23
  get disabled() {
23
- return this._disabled === undefined ? this.dtPicker.disabled : !!this._disabled;
24
+ return this._disabled === undefined ? !!this.dtPicker?.disabled : !!this._disabled;
24
25
  }
25
26
  set disabled(value) {
26
- this._disabled = value;
27
+ this._disabled = coerceBooleanProperty(value);
27
28
  }
28
29
  get owlDTTriggerDisabledClass() {
29
30
  return this.disabled;
@@ -35,7 +36,7 @@ class OwlDateTimeTriggerDirective {
35
36
  ngOnInit() {
36
37
  }
37
38
  ngOnChanges(changes) {
38
- if (changes.datepicker) {
39
+ if (changes.dtPicker) {
39
40
  this.watchStateChanges();
40
41
  }
41
42
  }
@@ -46,7 +47,7 @@ class OwlDateTimeTriggerDirective {
46
47
  this.stateChanges.unsubscribe();
47
48
  }
48
49
  handleClickOnHost(event) {
49
- if (this.dtPicker) {
50
+ if (this.dtPicker && !this.disabled) {
50
51
  this.dtPicker.open();
51
52
  event.stopPropagation();
52
53
  }
@@ -54,10 +55,10 @@ class OwlDateTimeTriggerDirective {
54
55
  watchStateChanges() {
55
56
  this.stateChanges.unsubscribe();
56
57
  const inputDisabled = this.dtPicker && this.dtPicker.dtInput ?
57
- this.dtPicker.dtInput.disabledChange : of();
58
+ this.dtPicker.dtInput.disabledChange.asObservable() : EMPTY;
58
59
  const pickerDisabled = this.dtPicker ?
59
- this.dtPicker.disabledChange : of();
60
- this.stateChanges = merge([pickerDisabled, inputDisabled])
60
+ this.dtPicker.disabledChange.asObservable() : EMPTY;
61
+ this.stateChanges = merge(pickerDisabled, inputDisabled)
61
62
  .subscribe(() => {
62
63
  this.changeDetector.markForCheck();
63
64
  });
@@ -85,13 +86,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
85
86
  /**
86
87
  * date-time-format.class
87
88
  */
88
- /** InjectionToken for date time picker that can be used to override default format. */
89
+ /** InjectionToken для переопределения формата даты и времени */
89
90
  const OWL_DATE_TIME_FORMATS = new InjectionToken('OWL_DATE_TIME_FORMATS');
90
91
 
91
92
  /**
92
93
  * date-time-adapter.class
93
94
  */
94
- /** InjectionToken for date time picker that can be used to override default locale code. */
95
+ /** InjectionToken для переопределения локали компонента выбора даты и времени */
95
96
  const OWL_DATE_TIME_LOCALE = new InjectionToken('OWL_DATE_TIME_LOCALE', {
96
97
  providedIn: 'root',
97
98
  factory: OWL_DATE_TIME_LOCALE_FACTORY
@@ -100,30 +101,30 @@ const OWL_DATE_TIME_LOCALE = new InjectionToken('OWL_DATE_TIME_LOCALE', {
100
101
  function OWL_DATE_TIME_LOCALE_FACTORY() {
101
102
  return inject(LOCALE_ID);
102
103
  }
103
- /** Provider for OWL_DATE_TIME_LOCALE injection token. */
104
+ /** Провайдер токена OWL_DATE_TIME_LOCALE */
104
105
  const OWL_DATE_TIME_LOCALE_PROVIDER = {
105
106
  provide: OWL_DATE_TIME_LOCALE,
106
107
  useExisting: LOCALE_ID
107
108
  };
108
109
  class DateTimeAdapter {
109
110
  constructor() {
110
- /** A stream that emits when the locale changes. */
111
+ /** Поток уведомлений об изменении локали */
111
112
  this._localeChanges = new Subject();
112
113
  this.firstMonthOfTheYear = 0;
113
114
  this.firstDayOfTheWeek = 0;
114
- /** total milliseconds in a day. */
115
+ /** Количество миллисекунд в сутках */
115
116
  this.millisecondsInDay = 86400000;
116
- /** total milliseconds in a minute. */
117
+ /** Количество миллисекунд в минуте */
117
118
  this.millisecondsInMinute = 60000;
118
119
  }
119
120
  get localeChanges() {
120
121
  return this._localeChanges;
121
122
  }
122
123
  /**
123
- * Compare two given dates
124
- * 1 if the first date is after the second,
125
- * -1 if the first date is before the second
126
- * 0 if dates are equal.
124
+ * Сравнивает две указанные даты
125
+ * 1, если первая дата позже второй;
126
+ * -1, если первая дата раньше второй;
127
+ * 0, если даты равны
127
128
  * */
128
129
  compare(first, second) {
129
130
  if (!this.isValid(first) || !this.isValid(second)) {
@@ -139,15 +140,15 @@ class DateTimeAdapter {
139
140
  return 1;
140
141
  }
141
142
  else {
142
- // Return 0 if diff is 0; return NaN if diff is NaN
143
+ // Возвращает 0 при diff === 0 и NaN при diff === NaN
143
144
  return diff;
144
145
  }
145
146
  }
146
147
  /**
147
- * Check if two given dates are in the same year
148
- * 1 if the first date's year is after the second,
149
- * -1 if the first date's year is before the second
150
- * 0 if two given dates are in the same year
148
+ * Сравнивает годы двух указанных дат
149
+ * 1, если год первой даты больше года второй;
150
+ * -1, если год первой даты меньше года второй;
151
+ * 0, если обе даты относятся к одному году
151
152
  * */
152
153
  compareYear(first, second) {
153
154
  if (!this.isValid(first) || !this.isValid(second)) {
@@ -167,13 +168,17 @@ class DateTimeAdapter {
167
168
  }
168
169
  }
169
170
  /**
170
- * Attempts to deserialize a value to a valid date object. This is different from parsing in that
171
- * deserialize should only accept non-ambiguous, locale-independent formats (e.g. a ISO 8601
172
- * string). The default implementation does not allow any deserialization, it simply checks that
173
- * the given value is already a valid date object or null. The `<mat-datepicker>` will call this
174
- * method on all of it's `@Input()` properties that accept dates. It is therefore possible to
175
- * support passing values from your backend directly to these properties by overriding this method
176
- * to also deserialize the format used by your backend.
171
+ * Пытается десериализовать значение в корректный объект даты
172
+ * В отличие от разбора
173
+ * пользовательского ввода, deserialize принимает только однозначные форматы, не зависящие
174
+ * от локали, например ISO 8601
175
+ * По умолчанию метод ничего не преобразует, а проверяет,
176
+ * что значение уже является корректным объектом даты или null
177
+ * Компонент выбора даты
178
+ * использует этот метод для входных значений, представляющих даты
179
+ * Переопределение
180
+ * метода позволяет передавать в такие свойства значения прямо с сервера,
181
+ * если реализовать десериализацию формата, используемого сервером
177
182
  */
178
183
  deserialize(value) {
179
184
  if (value == null ||
@@ -183,26 +188,26 @@ class DateTimeAdapter {
183
188
  return this.invalid();
184
189
  }
185
190
  /**
186
- * Sets the locale used for all dates.
191
+ * Устанавливает локаль для всех дат
187
192
  */
188
193
  setLocale(locale) {
189
194
  this.locale = locale;
190
195
  this._localeChanges.next(locale);
191
196
  }
192
197
  /**
193
- * Get the locale used for all dates.
198
+ * Возвращает локаль для всех дат
194
199
  * */
195
200
  getLocale() {
196
201
  return this.locale;
197
202
  }
198
203
  /**
199
- * Clamp the given date between min and max dates.
204
+ * Ограничивает дату минимальным и максимальным значениями
200
205
  */
201
206
  clampDate(date, min, max) {
202
- if (min && this.compare(date, min) < 0) {
207
+ if (min != null && this.compare(date, min) < 0) {
203
208
  return min;
204
209
  }
205
- if (max && this.compare(date, max) > 0) {
210
+ if (max != null && this.compare(date, max) > 0) {
206
211
  return max;
207
212
  }
208
213
  return date;
@@ -285,55 +290,56 @@ class OwlDateTime {
285
290
  this.dateTimeAdapter = dateTimeAdapter;
286
291
  this.dateTimeFormats = dateTimeFormats;
287
292
  /**
288
- * Whether to show the second's timer
293
+ * Нужно ли показывать поле секунд
289
294
  */
290
295
  this._showSecondsTimer = false;
291
296
  /**
292
- * Whether the timer is in hour12 format
297
+ * Используется ли 12-часовой формат времени
293
298
  */
294
299
  this._hour12Timer = false;
295
300
  /**
296
- * The view that the calendar should start in.
301
+ * Начальное представление календаря
297
302
  */
298
303
  this.startView = DateView.MONTH;
299
304
  /**
300
- * Whether to show calendar weeks in the calendar
305
+ * Нужно ли показывать номера недель в календаре
301
306
  * */
302
307
  this.showCalendarWeeks = false;
303
308
  /**
304
- * Whether to should only the year and multi-year views.
309
+ * Нужно ли показывать только представления года и нескольких лет
305
310
  */
306
311
  this.yearOnly = false;
307
312
  /**
308
- * Whether to should only the multi-year view.
313
+ * Нужно ли показывать только представление нескольких лет
309
314
  */
310
315
  this.multiyearOnly = false;
311
316
  /**
312
- * Hours to change per step
317
+ * Количество часов за один шаг
313
318
  */
314
319
  this._stepHour = 1;
315
320
  /**
316
- * Minutes to change per step
321
+ * Количество минут за один шаг
317
322
  */
318
323
  this._stepMinute = 1;
319
324
  /**
320
- * Seconds to change per step
325
+ * Количество секунд за один шаг
321
326
  */
322
327
  this._stepSecond = 1;
323
328
  /**
324
- * Whether to hide dates in other months at the start or end of the current month.
329
+ * Нужно ли скрывать даты соседних месяцев в начале или конце текущего месяца
325
330
  */
326
331
  this._hideOtherMonths = false;
327
332
  /**
328
- * Date Time Checker to check if the give dateTime is selectable
333
+ * Проверка доступности указанных даты и времени для выбора
329
334
  */
330
335
  this.dateTimeChecker = (dateTime) => {
331
- return (!!dateTime &&
336
+ return (dateTime != null &&
337
+ this.dateTimeAdapter.isValid(dateTime) &&
332
338
  (!this.dateTimeFilter || this.dateTimeFilter(dateTime)) &&
333
- (!this.minDateTime ||
339
+ (this.minDateTime == null ||
334
340
  this.dateTimeAdapter.compare(dateTime, this.minDateTime) >=
335
341
  0) &&
336
- (!this.maxDateTime ||
342
+ (this.maxDateTime == null ||
337
343
  this.dateTimeAdapter.compare(dateTime, this.maxDateTime) <= 0));
338
344
  };
339
345
  if (!this.dateTimeAdapter) {
@@ -394,49 +400,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
394
400
  class OwlDateTimeIntl {
395
401
  constructor() {
396
402
  /**
397
- * Stream that emits whenever the labels here are changed. Use this to notify
398
- * components if the labels have changed after initialization.
403
+ * Поток событий изменения подписей для уведомления
404
+ * компонентов об изменении подписей после инициализации
399
405
  */
400
406
  this.changes = new Subject();
401
- /** A label for the up second button (used by screen readers). */
407
+ /** Подпись кнопки увеличения секунд для программ чтения с экрана */
402
408
  this.upSecondLabel = 'Add a second';
403
- /** A label for the down second button (used by screen readers). */
409
+ /** Подпись кнопки уменьшения секунд для программ чтения с экрана */
404
410
  this.downSecondLabel = 'Minus a second';
405
- /** A label for the up minute button (used by screen readers). */
411
+ /** Подпись кнопки увеличения минут для программ чтения с экрана */
406
412
  this.upMinuteLabel = 'Add a minute';
407
- /** A label for the down minute button (used by screen readers). */
413
+ /** Подпись кнопки уменьшения минут для программ чтения с экрана */
408
414
  this.downMinuteLabel = 'Minus a minute';
409
- /** A label for the up hour button (used by screen readers). */
415
+ /** Подпись кнопки увеличения часов для программ чтения с экрана */
410
416
  this.upHourLabel = 'Add a hour';
411
- /** A label for the down hour button (used by screen readers). */
417
+ /** Подпись кнопки уменьшения часов для программ чтения с экрана */
412
418
  this.downHourLabel = 'Minus a hour';
413
- /** A label for the previous month button (used by screen readers). */
419
+ /** Подпись кнопки предыдущего месяца для программ чтения с экрана */
414
420
  this.prevMonthLabel = 'Previous month';
415
- /** A label for the next month button (used by screen readers). */
421
+ /** Подпись кнопки следующего месяца для программ чтения с экрана */
416
422
  this.nextMonthLabel = 'Next month';
417
- /** A label for the previous year button (used by screen readers). */
423
+ /** Подпись кнопки предыдущего года для программ чтения с экрана */
418
424
  this.prevYearLabel = 'Previous year';
419
- /** A label for the next year button (used by screen readers). */
425
+ /** Подпись кнопки следующего года для программ чтения с экрана */
420
426
  this.nextYearLabel = 'Next year';
421
- /** A label for the previous multi-year button (used by screen readers). */
427
+ /** Подпись кнопки предыдущей группы лет для программ чтения с экрана */
422
428
  this.prevMultiYearLabel = 'Previous 21 years';
423
- /** A label for the next multi-year button (used by screen readers). */
429
+ /** Подпись кнопки следующей группы лет для программ чтения с экрана */
424
430
  this.nextMultiYearLabel = 'Next 21 years';
425
- /** A label for the 'switch to month view' button (used by screen readers). */
431
+ /** Подпись кнопки перехода к представлению месяца для программ чтения с экрана */
426
432
  this.switchToMonthViewLabel = 'Change to month view';
427
- /** A label for the 'switch to year view' button (used by screen readers). */
433
+ /** Подпись кнопки перехода к представлению года для программ чтения с экрана */
428
434
  this.switchToMultiYearViewLabel = 'Choose month and year';
429
- /** A label for the cancel button */
435
+ /** Подпись кнопки отмены */
430
436
  this.cancelBtnLabel = 'Cancel';
431
- /** A label for the set button */
437
+ /** Подпись кнопки подтверждения */
432
438
  this.setBtnLabel = 'Set';
433
- /** A label for the range 'from' in picker info */
439
+ /** Подпись начала диапазона ('from') в информации о выбранных датах */
434
440
  this.rangeFromLabel = 'From';
435
- /** A label for the range 'to' in picker info */
441
+ /** Подпись конца диапазона ('to') в информации о выбранных датах */
436
442
  this.rangeToLabel = 'To';
437
- /** A label for the hour12 button (AM) */
443
+ /** Подпись кнопки AM в 12-часовом формате */
438
444
  this.hour12AMLabel = 'AM';
439
- /** A label for the hour12 button (PM) */
445
+ /** Подпись кнопки PM в 12-часовом формате */
440
446
  this.hour12PMLabel = 'PM';
441
447
  }
442
448
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlDateTimeIntl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
@@ -475,33 +481,41 @@ class OwlCalendarBodyComponent {
475
481
  constructor(elmRef, ngZone) {
476
482
  this.elmRef = elmRef;
477
483
  this.ngZone = ngZone;
484
+ this.injector = inject(Injector);
485
+ this.destroyRef = inject(DestroyRef);
478
486
  /**
479
- * The cell number of the active cell in the table.
487
+ * Номер активной ячейки в таблице
480
488
  */
481
489
  this.activeCell = 0;
482
490
  /**
483
- * The number of columns in the table.
491
+ * Количество столбцов в таблице
484
492
  * */
485
493
  this.numCols = 7;
486
494
  /**
487
- * The ratio (width / height) to use for the cells in the table.
495
+ * Соотношение ширины и высоты ячеек таблицы
488
496
  */
489
497
  this.cellRatio = 1;
490
498
  /**
491
- * Emit when a calendar cell is selected
499
+ * Выбранное значение в таблице
500
+ * */
501
+ this.selectedValues = [];
502
+ /**
503
+ * Событие выбора ячейки календаря
492
504
  * */
493
505
  this.select = new EventEmitter();
494
506
  }
495
507
  ngOnInit() { }
496
508
  selectCell(cell) {
497
- this.select.emit(cell);
509
+ if (cell.enabled) {
510
+ this.select.emit(cell);
511
+ }
498
512
  }
499
513
  isActiveCell(rowIndex, colIndex) {
500
514
  const cellNumber = rowIndex * this.numCols + colIndex;
501
515
  return cellNumber === this.activeCell;
502
516
  }
503
517
  /**
504
- * Check if the cell is selected
518
+ * Проверяет, выбрана ли ячейка
505
519
  */
506
520
  isSelected(value) {
507
521
  if (!this.selectedValues || this.selectedValues.length === 0) {
@@ -511,19 +525,19 @@ class OwlCalendarBodyComponent {
511
525
  return value === this.selectedValues[0];
512
526
  }
513
527
  if (this.isInRangeMode) {
514
- const fromValue = this.selectedValues[0];
515
- const toValue = this.selectedValues[1];
528
+ const fromValue = this.selectedValues?.[0];
529
+ const toValue = this.selectedValues?.[1];
516
530
  return value === fromValue || value === toValue;
517
531
  }
518
532
  }
519
533
  /**
520
- * Check if the cell in the range
534
+ * Проверяет, входит ли ячейка в диапазон
521
535
  * */
522
536
  isInRange(value) {
523
537
  if (this.isInRangeMode) {
524
- const fromValue = this.selectedValues[0];
525
- const toValue = this.selectedValues[1];
526
- if (fromValue !== null && toValue !== null) {
538
+ const fromValue = this.selectedValues?.[0];
539
+ const toValue = this.selectedValues?.[1];
540
+ if (fromValue != null && toValue != null) {
527
541
  return value >= fromValue && value <= toValue;
528
542
  }
529
543
  else {
@@ -532,37 +546,37 @@ class OwlCalendarBodyComponent {
532
546
  }
533
547
  }
534
548
  /**
535
- * Check if the cell is the range from
549
+ * Проверяет, соответствует ли ячейка началу диапазона
536
550
  * */
537
551
  isRangeFrom(value) {
538
552
  if (this.isInRangeMode) {
539
- const fromValue = this.selectedValues[0];
540
- return fromValue !== null && value === fromValue;
553
+ const fromValue = this.selectedValues?.[0];
554
+ return fromValue != null && value === fromValue;
541
555
  }
542
556
  }
543
557
  /**
544
- * Check if the cell is the range to
558
+ * Проверяет, соответствует ли ячейка концу диапазона
545
559
  * */
546
560
  isRangeTo(value) {
547
561
  if (this.isInRangeMode) {
548
- const toValue = this.selectedValues[1];
549
- return toValue !== null && value === toValue;
562
+ const toValue = this.selectedValues?.[1];
563
+ return toValue != null && value === toValue;
550
564
  }
551
565
  }
552
566
  /**
553
- * Focus to a active cell
567
+ * Переводит фокус на активную ячейку
554
568
  * */
555
569
  focusActiveCell() {
556
- this.ngZone.runOutsideAngular(() => {
557
- this.ngZone.onStable
558
- .asObservable()
559
- .pipe(take(1))
560
- .subscribe(() => {
561
- this.elmRef.nativeElement
562
- .querySelector('.owl-dt-calendar-cell-active')
563
- .focus();
564
- });
565
- });
570
+ if (this.destroyRef.destroyed) {
571
+ return;
572
+ }
573
+ this.focusRef?.destroy();
574
+ this.focusRef = afterNextRender({
575
+ write: () => {
576
+ this.focusRef = undefined;
577
+ this.elmRef.nativeElement.querySelector('.owl-dt-calendar-cell-active')?.focus();
578
+ }
579
+ }, { injector: this.injector });
566
580
  }
567
581
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlCalendarBodyComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
568
582
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: OwlCalendarBodyComponent, isStandalone: false, selector: "[owl-date-time-calendar-body]", inputs: { activeCell: "activeCell", rows: "rows", numCols: "numCols", cellRatio: "cellRatio", todayValue: "todayValue", selectedValues: "selectedValues", selectMode: "selectMode" }, outputs: { select: "select" }, host: { properties: { "class.owl-dt-calendar-body": "owlDTCalendarBodyClass" } }, exportAs: ["owlDateTimeCalendarBody"], ngImport: i0, template: "@for (row of rows; track $index; let rowIndex = $index) {\r\n <tr role=\"row\">\r\n @for (item of row; track $index; let colIndex = $index) {\r\n <td\r\n class=\"owl-dt-calendar-cell {{ item.cellClass }}\"\r\n [tabindex]=\"isActiveCell(rowIndex, colIndex) ? 0 : -1\"\r\n [class.owl-dt-calendar-cell-active]=\"\r\n isActiveCell(rowIndex, colIndex)\r\n \"\r\n [class.owl-dt-calendar-cell-disabled]=\"!item.enabled\"\r\n [class.owl-dt-calendar-cell-in-range]=\"isInRange(item.value)\"\r\n [class.owl-dt-calendar-cell-range-from]=\"\r\n isRangeFrom(item.value)\r\n \"\r\n [class.owl-dt-calendar-cell-range-to]=\"isRangeTo(item.value)\"\r\n [attr.aria-label]=\"item.ariaLabel\"\r\n [attr.aria-disabled]=\"!item.enabled || null\"\r\n [attr.aria-current]=\"item.value === todayValue ? 'date' : null\"\r\n [attr.aria-selected]=\"isSelected(item.value)\"\r\n [style.width.%]=\"100 / numCols\"\r\n [style.paddingTop.%]=\"(50 * cellRatio) / numCols\"\r\n [style.paddingBottom.%]=\"(50 * cellRatio) / numCols\"\r\n (click)=\"selectCell(item)\"\r\n >\r\n <span\r\n class=\"owl-dt-calendar-cell-content\"\r\n [ngClass]=\"{\r\n 'owl-dt-calendar-cell-out': item.out,\r\n 'owl-dt-calendar-cell-today': item.value === todayValue,\r\n 'owl-dt-calendar-cell-selected': isSelected(item.value),\r\n }\"\r\n >\r\n {{ item.displayValue }}\r\n </span>\r\n </td>\r\n }\r\n </tr>\r\n}\r\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -598,7 +612,7 @@ function multiYearOptionsFactory(options) {
598
612
  }
599
613
  class DefaultOptions {
600
614
  static create() {
601
- // Always return new instance
615
+ // Всегда возвращаем новый экземпляр
602
616
  return {
603
617
  multiYear: {
604
618
  yearRows: 7,
@@ -652,7 +666,7 @@ class OwlMultiYearViewComponent {
652
666
  return this._selecteds;
653
667
  }
654
668
  set selecteds(values) {
655
- this._selecteds = values.map((v) => {
669
+ this._selecteds = (values ?? []).map((v) => {
656
670
  v = this.dateTimeAdapter.deserialize(v);
657
671
  return this.getValidDate(v);
658
672
  });
@@ -664,8 +678,8 @@ class OwlMultiYearViewComponent {
664
678
  set pickerDateTime(value) {
665
679
  const oldDateTime = this._pickerDateTime;
666
680
  value = this.dateTimeAdapter.deserialize(value);
667
- this._pickerDateTime = this.getValidDate(value) || this.dateTimeAdapter.now();
668
- if (oldDateTime && this._pickerDateTime &&
681
+ this._pickerDateTime = this.getValidDate(value) ?? this.dateTimeAdapter.now();
682
+ if (oldDateTime != null && this._pickerDateTime != null &&
669
683
  !this.isSameYearList(oldDateTime, this._pickerDateTime)) {
670
684
  this.generateYearList();
671
685
  }
@@ -716,8 +730,8 @@ class OwlMultiYearViewComponent {
716
730
  || this.selectMode === 'rangeTo';
717
731
  }
718
732
  get activeCell() {
719
- if (this._pickerDateTime) {
720
- return this.dateTimeAdapter.getYear(this._pickerDateTime) % (this.options.yearsPerRow * this.options.yearRows);
733
+ if (this._pickerDateTime != null) {
734
+ return this.dateTimeAdapter.getYear(this._pickerDateTime) - this.getYearListStart(this._pickerDateTime);
721
735
  }
722
736
  }
723
737
  get tableHeader() {
@@ -743,23 +757,28 @@ class OwlMultiYearViewComponent {
743
757
  this.dateTimeAdapter = dateTimeAdapter;
744
758
  this.options = options;
745
759
  /**
746
- * The select mode of the picker;
760
+ * Режим выбора даты
747
761
  * */
748
762
  this._selectMode = 'single';
749
763
  this._selecteds = [];
750
764
  this.initiated = false;
751
765
  /**
752
- * Callback to invoke when a new month is selected
766
+ * Обработчик выбора нового месяца
753
767
  * */
754
768
  this.change = new EventEmitter();
755
769
  /**
756
- * Emits the selected year. This doesn't imply a change on the selected date
770
+ * Передаёт выбранный год, не изменяя выбранную дату
757
771
  * */
758
772
  this.yearSelected = new EventEmitter();
759
- /** Emits when any date is activated. */
773
+ /** Событие активации любой даты */
760
774
  this.pickerDateTimeChange = new EventEmitter();
761
- /** Emits when use keyboard enter to select a calendar cell */
775
+ /** Событие выбора ячейки календаря клавишей Enter */
762
776
  this.keyboardEnter = new EventEmitter();
777
+ this.pickerIntl.changes.pipe(takeUntilDestroyed()).subscribe(() => this.cdRef.markForCheck());
778
+ this.dateTimeAdapter.localeChanges.pipe(takeUntilDestroyed()).subscribe(() => {
779
+ this.generateYearList();
780
+ this.cdRef.markForCheck();
781
+ });
763
782
  }
764
783
  ngOnInit() {
765
784
  }
@@ -769,10 +788,12 @@ class OwlMultiYearViewComponent {
769
788
  this.initiated = true;
770
789
  }
771
790
  /**
772
- * Handle a calendarCell selected
791
+ * Обрабатывает выбор ячейки календаря
773
792
  */
774
793
  selectCalendarCell(cell) {
775
- this.selectYear(cell.value);
794
+ if (cell.enabled) {
795
+ this.selectYear(cell.value);
796
+ }
776
797
  }
777
798
  selectYear(year) {
778
799
  this.yearSelected.emit(this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1));
@@ -782,7 +803,7 @@ class OwlMultiYearViewComponent {
782
803
  this.change.emit(selected);
783
804
  }
784
805
  /**
785
- * Generate the previous year list
806
+ * Создаёт список предыдущих лет
786
807
  * */
787
808
  prevYearList(event) {
788
809
  this._pickerDateTime = this.dateTimeAdapter.addCalendarYears(this.pickerDateTime, -1 * this.options.yearsPerRow * this.options.yearRows);
@@ -790,7 +811,7 @@ class OwlMultiYearViewComponent {
790
811
  event.preventDefault();
791
812
  }
792
813
  /**
793
- * Generate the next year list
814
+ * Создаёт список следующих лет
794
815
  * */
795
816
  nextYearList(event) {
796
817
  this._pickerDateTime = this.dateTimeAdapter.addCalendarYears(this.pickerDateTime, this.options.yearsPerRow * this.options.yearRows);
@@ -798,9 +819,12 @@ class OwlMultiYearViewComponent {
798
819
  event.preventDefault();
799
820
  }
800
821
  generateYearList() {
822
+ if (this._pickerDateTime == null) {
823
+ return;
824
+ }
801
825
  this._years = [];
802
826
  const pickerDateTimeYear = this.dateTimeAdapter.getYear(this._pickerDateTime);
803
- const offset = pickerDateTimeYear % (this.options.yearsPerRow * this.options.yearRows);
827
+ const offset = pickerDateTimeYear - this.getYearListStart(this._pickerDateTime);
804
828
  for (let i = 0; i < this.options.yearRows; i++) {
805
829
  const row = [];
806
830
  for (let j = 0; j < this.options.yearsPerRow; j++) {
@@ -812,63 +836,62 @@ class OwlMultiYearViewComponent {
812
836
  }
813
837
  return;
814
838
  }
815
- /** Whether the previous period button is enabled. */
839
+ /** Доступна ли кнопка перехода к предыдущему периоду */
816
840
  previousEnabled() {
817
- if (!this.minDate) {
818
- return true;
819
- }
820
- return !this.minDate || !this.isSameYearList(this._pickerDateTime, this.minDate);
841
+ return this.minDate == null || this.getYearListStart(this._pickerDateTime) > this.getYearListStart(this.minDate);
821
842
  }
822
- /** Whether the next period button is enabled. */
843
+ /** Доступна ли кнопка перехода к следующему периоду */
823
844
  nextEnabled() {
824
- return !this.maxDate || !this.isSameYearList(this._pickerDateTime, this.maxDate);
845
+ return this.maxDate == null || this.getYearListStart(this._pickerDateTime) < this.getYearListStart(this.maxDate);
825
846
  }
826
847
  handleCalendarKeydown(event) {
827
848
  let dateTime;
828
849
  switch (event.keyCode) {
829
- // minus 1 year
850
+ // На один год назад
830
851
  case LEFT_ARROW:
831
852
  dateTime = this.dateTimeAdapter.addCalendarYears(this._pickerDateTime, -1);
832
853
  this.pickerDateTimeChange.emit(dateTime);
833
854
  break;
834
- // add 1 year
855
+ // На один год вперёд
835
856
  case RIGHT_ARROW:
836
857
  dateTime = this.dateTimeAdapter.addCalendarYears(this._pickerDateTime, 1);
837
858
  this.pickerDateTimeChange.emit(dateTime);
838
859
  break;
839
- // minus 3 years
860
+ // На три года назад
840
861
  case UP_ARROW:
841
862
  dateTime = this.dateTimeAdapter.addCalendarYears(this._pickerDateTime, -1 * this.options.yearsPerRow);
842
863
  this.pickerDateTimeChange.emit(dateTime);
843
864
  break;
844
- // add 3 years
865
+ // На три года вперёд
845
866
  case DOWN_ARROW:
846
867
  dateTime = this.dateTimeAdapter.addCalendarYears(this._pickerDateTime, this.options.yearsPerRow);
847
868
  this.pickerDateTimeChange.emit(dateTime);
848
869
  break;
849
- // go to the first year of the year page
870
+ // К первому году на текущей странице
850
871
  case HOME:
851
- dateTime = this.dateTimeAdapter.addCalendarYears(this._pickerDateTime, -this.dateTimeAdapter.getYear(this._pickerDateTime) % (this.options.yearsPerRow * this.options.yearRows));
872
+ dateTime = this.dateTimeAdapter.addCalendarYears(this._pickerDateTime, -this.activeCell);
852
873
  this.pickerDateTimeChange.emit(dateTime);
853
874
  break;
854
- // go to the last year of the year page
875
+ // К последнему году на текущей странице
855
876
  case END:
856
- dateTime = this.dateTimeAdapter.addCalendarYears(this._pickerDateTime, (this.options.yearsPerRow * this.options.yearRows) - this.dateTimeAdapter.getYear(this._pickerDateTime) % (this.options.yearsPerRow * this.options.yearRows) - 1);
877
+ dateTime = this.dateTimeAdapter.addCalendarYears(this._pickerDateTime, (this.options.yearsPerRow * this.options.yearRows) - this.activeCell - 1);
857
878
  this.pickerDateTimeChange.emit(dateTime);
858
879
  break;
859
- // minus 1 year page (or 10 year pages)
880
+ // На одну страницу лет (или десять страниц) назад
860
881
  case PAGE_UP:
861
882
  dateTime = this.dateTimeAdapter.addCalendarYears(this.pickerDateTime, event.altKey ? -10 * (this.options.yearsPerRow * this.options.yearRows) : -1 * (this.options.yearsPerRow * this.options.yearRows));
862
883
  this.pickerDateTimeChange.emit(dateTime);
863
884
  break;
864
- // add 1 year page (or 10 year pages)
885
+ // На одну страницу лет (или десять страниц) вперёд
865
886
  case PAGE_DOWN:
866
887
  dateTime = this.dateTimeAdapter.addCalendarYears(this.pickerDateTime, event.altKey ? 10 * (this.options.yearsPerRow * this.options.yearRows) : (this.options.yearsPerRow * this.options.yearRows));
867
888
  this.pickerDateTimeChange.emit(dateTime);
868
889
  break;
869
890
  case ENTER:
870
- this.selectYear(this.dateTimeAdapter.getYear(this._pickerDateTime));
871
- this.keyboardEnter.emit();
891
+ if (this.isYearEnabled(this.dateTimeAdapter.getYear(this._pickerDateTime))) {
892
+ this.selectYear(this.dateTimeAdapter.getYear(this._pickerDateTime));
893
+ this.keyboardEnter.emit();
894
+ }
872
895
  break;
873
896
  default:
874
897
  return;
@@ -877,7 +900,7 @@ class OwlMultiYearViewComponent {
877
900
  event.preventDefault();
878
901
  }
879
902
  /**
880
- * Creates an CalendarCell for the given year.
903
+ * Создаёт CalendarCell для указанного года
881
904
  */
882
905
  createYearCell(year) {
883
906
  const startDateOfYear = this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1);
@@ -887,7 +910,7 @@ class OwlMultiYearViewComponent {
887
910
  }
888
911
  setSelectedYears() {
889
912
  this._selectedYears = [];
890
- if (this.isInSingleMode && this.selected) {
913
+ if (this.isInSingleMode && this.selected != null) {
891
914
  this._selectedYears[0] = this.dateTimeAdapter.getYear(this.selected);
892
915
  }
893
916
  if (this.isInRangeMode && this.selecteds) {
@@ -901,33 +924,38 @@ class OwlMultiYearViewComponent {
901
924
  });
902
925
  }
903
926
  }
904
- /** Whether the given year is enabled. */
927
+ /** Доступен ли указанный год для выбора */
905
928
  isYearEnabled(year) {
906
- // disable if the year is greater than maxDate lower than minDate
929
+ // Отключаем выбор года, если он позже maxDate или раньше minDate
907
930
  if (year === undefined || year === null ||
908
- (this.maxDate && year > this.dateTimeAdapter.getYear(this.maxDate)) ||
909
- (this.minDate && year < this.dateTimeAdapter.getYear(this.minDate))) {
931
+ (this.maxDate != null && year > this.dateTimeAdapter.getYear(this.maxDate)) ||
932
+ (this.minDate != null && year < this.dateTimeAdapter.getYear(this.minDate))) {
910
933
  return false;
911
934
  }
912
- // enable if it reaches here and there's no filter defined
935
+ // Разрешаем выбор, если проверки пройдены и фильтр не задан
913
936
  if (!this.dateFilter) {
914
937
  return true;
915
938
  }
916
939
  const firstOfYear = this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1);
917
- // If any date in the year is enabled count the year as enabled.
940
+ // Считаем год доступным для выбора, если доступна хотя бы одна дата в нём
918
941
  for (let date = firstOfYear; this.dateTimeAdapter.getYear(date) === year; date = this.dateTimeAdapter.addCalendarDays(date, 1)) {
919
- if (this.dateFilter(date)) {
942
+ if (this.dateFilter(date) &&
943
+ (this.minDate == null || this.dateTimeAdapter.compare(date, this.minDate) >= 0) &&
944
+ (this.maxDate == null || this.dateTimeAdapter.compare(date, this.maxDate) <= 0)) {
920
945
  return true;
921
946
  }
922
947
  }
923
948
  return false;
924
949
  }
925
950
  isSameYearList(date1, date2) {
926
- return Math.floor(this.dateTimeAdapter.getYear(date1) / (this.options.yearsPerRow * this.options.yearRows)) ===
927
- Math.floor(this.dateTimeAdapter.getYear(date2) / (this.options.yearsPerRow * this.options.yearRows));
951
+ return this.getYearListStart(date1) === this.getYearListStart(date2);
952
+ }
953
+ getYearListStart(date) {
954
+ const yearsPerPage = this.options.yearsPerRow * this.options.yearRows;
955
+ return Math.floor(this.dateTimeAdapter.getYear(date) / yearsPerPage) * yearsPerPage;
928
956
  }
929
957
  /**
930
- * Get a valid date object
958
+ * Возвращает корректный объект даты
931
959
  */
932
960
  getValidDate(obj) {
933
961
  return (this.dateTimeAdapter.isDateInstance(obj) && this.dateTimeAdapter.isValid(obj)) ? obj : null;
@@ -936,14 +964,14 @@ class OwlMultiYearViewComponent {
936
964
  this.calendarBodyElm.focusActiveCell();
937
965
  }
938
966
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlMultiYearViewComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: OwlDateTimeIntl }, { token: DateTimeAdapter, optional: true }, { token: OptionsTokens.multiYear }], target: i0.ɵɵFactoryTarget.Component }); }
939
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: OwlMultiYearViewComponent, isStandalone: false, selector: "owl-date-time-multi-year-view", inputs: { selectMode: "selectMode", selected: "selected", selecteds: "selecteds", pickerDateTime: "pickerDateTime", dateFilter: "dateFilter", minDate: "minDate", maxDate: "maxDate" }, outputs: { change: "change", yearSelected: "yearSelected", pickerDateTimeChange: "pickerDateTimeChange", keyboardEnter: "keyboardEnter" }, host: { properties: { "class.owl-dt-calendar-view": "owlDTCalendarView", "class.owl-dt-calendar-multi-year-view": "owlDTCalendarMultiYearView" } }, viewQueries: [{ propertyName: "calendarBodyElm", first: true, predicate: OwlCalendarBodyComponent, descendants: true, static: true }], ngImport: i0, template: "<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n [disabled]=\"!previousEnabled()\" [attr.aria-label]=\"prevButtonLabel\"\r\n type=\"button\" tabindex=\"0\" (click)=\"prevYearList($event)\">\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG Arrow Left\"> -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\" x=\"0px\" y=\"0px\" viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\"\r\n width=\"100%\" height=\"100%\">\r\n <path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M96.633,125.369l95.053-94.533c7.101-7.055,7.101-18.492,0-25.546 c-7.1-7.054-18.613-7.054-25.714,0L58.989,111.689c-3.784,3.759-5.487,8.759-5.238,13.68c-0.249,4.922,1.454,9.921,5.238,13.681 l106.983,106.398c7.101,7.055,18.613,7.055,25.714,0c7.101-7.054,7.101-18.491,0-25.544L96.633,125.369z\"/>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n<table class=\"owl-dt-calendar-table owl-dt-calendar-multi-year-table\">\r\n <thead class=\"owl-dt-calendar-header\">\r\n <tr>\r\n <th colspan=\"3\">{{tableHeader}}</th>\r\n </tr>\r\n </thead>\r\n <tbody owl-date-time-calendar-body role=\"grid\"\r\n [rows]=\"years\" [numCols]=\"3\" [cellRatio]=\"3 / 7\"\r\n [activeCell]=\"activeCell\"\r\n [todayValue]=\"todayYear\"\r\n [selectedValues]=\"selectedYears\"\r\n [selectMode]=\"selectMode\"\r\n (keydown)=\"handleCalendarKeydown($event)\"\r\n (select)=\"selectCalendarCell($event)\"></tbody>\r\n</table>\r\n<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n [disabled]=\"!nextEnabled()\" [attr.aria-label]=\"nextButtonLabel\"\r\n type=\"button\" tabindex=\"0\" (click)=\"nextYearList($event)\">\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG Arrow Right\"> -->\r\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\" style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\">\r\n <path style=\"fill-rule:evenodd;clip-rule:evenodd;\" d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\r\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\r\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\r\n C197.237,120.447,195.534,115.448,191.75,111.689z\"/>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n", styles: [""], dependencies: [{ kind: "component", type: OwlCalendarBodyComponent, selector: "[owl-date-time-calendar-body]", inputs: ["activeCell", "rows", "numCols", "cellRatio", "todayValue", "selectedValues", "selectMode"], outputs: ["select"], exportAs: ["owlDateTimeCalendarBody"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
967
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: OwlMultiYearViewComponent, isStandalone: false, selector: "owl-date-time-multi-year-view", inputs: { selectMode: "selectMode", selected: "selected", selecteds: "selecteds", pickerDateTime: "pickerDateTime", dateFilter: "dateFilter", minDate: "minDate", maxDate: "maxDate" }, outputs: { change: "change", yearSelected: "yearSelected", pickerDateTimeChange: "pickerDateTimeChange", keyboardEnter: "keyboardEnter" }, host: { properties: { "class.owl-dt-calendar-view": "owlDTCalendarView", "class.owl-dt-calendar-multi-year-view": "owlDTCalendarMultiYearView" } }, viewQueries: [{ propertyName: "calendarBodyElm", first: true, predicate: OwlCalendarBodyComponent, descendants: true, static: true }], ngImport: i0, template: "<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n [disabled]=\"!previousEnabled()\" [attr.aria-label]=\"prevButtonLabel\"\r\n type=\"button\" tabindex=\"0\" (click)=\"prevYearList($event)\">\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043B\u0435\u0432\u043E\"> -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\" x=\"0px\" y=\"0px\" viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\"\r\n width=\"100%\" height=\"100%\">\r\n <path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M96.633,125.369l95.053-94.533c7.101-7.055,7.101-18.492,0-25.546 c-7.1-7.054-18.613-7.054-25.714,0L58.989,111.689c-3.784,3.759-5.487,8.759-5.238,13.68c-0.249,4.922,1.454,9.921,5.238,13.681 l106.983,106.398c7.101,7.055,18.613,7.055,25.714,0c7.101-7.054,7.101-18.491,0-25.544L96.633,125.369z\"/>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n<table class=\"owl-dt-calendar-table owl-dt-calendar-multi-year-table\">\r\n <thead class=\"owl-dt-calendar-header\">\r\n <tr>\r\n <th [attr.colspan]=\"options.yearsPerRow\">{{tableHeader}}</th>\r\n </tr>\r\n </thead>\r\n <tbody owl-date-time-calendar-body role=\"grid\"\r\n [rows]=\"years\" [numCols]=\"options.yearsPerRow\" [cellRatio]=\"3 / 7\"\r\n [activeCell]=\"activeCell\"\r\n [todayValue]=\"todayYear\"\r\n [selectedValues]=\"selectedYears\"\r\n [selectMode]=\"selectMode\"\r\n (keydown)=\"handleCalendarKeydown($event)\"\r\n (select)=\"selectCalendarCell($event)\"></tbody>\r\n</table>\r\n<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n [disabled]=\"!nextEnabled()\" [attr.aria-label]=\"nextButtonLabel\"\r\n type=\"button\" tabindex=\"0\" (click)=\"nextYearList($event)\">\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043F\u0440\u0430\u0432\u043E\"> -->\r\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\" style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\">\r\n <path style=\"fill-rule:evenodd;clip-rule:evenodd;\" d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\r\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\r\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\r\n C197.237,120.447,195.534,115.448,191.75,111.689z\"/>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n", styles: [""], dependencies: [{ kind: "component", type: OwlCalendarBodyComponent, selector: "[owl-date-time-calendar-body]", inputs: ["activeCell", "rows", "numCols", "cellRatio", "todayValue", "selectedValues", "selectMode"], outputs: ["select"], exportAs: ["owlDateTimeCalendarBody"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
940
968
  }
941
969
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlMultiYearViewComponent, decorators: [{
942
970
  type: Component,
943
971
  args: [{ selector: 'owl-date-time-multi-year-view', host: {
944
972
  '[class.owl-dt-calendar-view]': 'owlDTCalendarView',
945
973
  '[class.owl-dt-calendar-multi-year-view]': 'owlDTCalendarMultiYearView'
946
- }, standalone: false, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n [disabled]=\"!previousEnabled()\" [attr.aria-label]=\"prevButtonLabel\"\r\n type=\"button\" tabindex=\"0\" (click)=\"prevYearList($event)\">\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG Arrow Left\"> -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\" x=\"0px\" y=\"0px\" viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\"\r\n width=\"100%\" height=\"100%\">\r\n <path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M96.633,125.369l95.053-94.533c7.101-7.055,7.101-18.492,0-25.546 c-7.1-7.054-18.613-7.054-25.714,0L58.989,111.689c-3.784,3.759-5.487,8.759-5.238,13.68c-0.249,4.922,1.454,9.921,5.238,13.681 l106.983,106.398c7.101,7.055,18.613,7.055,25.714,0c7.101-7.054,7.101-18.491,0-25.544L96.633,125.369z\"/>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n<table class=\"owl-dt-calendar-table owl-dt-calendar-multi-year-table\">\r\n <thead class=\"owl-dt-calendar-header\">\r\n <tr>\r\n <th colspan=\"3\">{{tableHeader}}</th>\r\n </tr>\r\n </thead>\r\n <tbody owl-date-time-calendar-body role=\"grid\"\r\n [rows]=\"years\" [numCols]=\"3\" [cellRatio]=\"3 / 7\"\r\n [activeCell]=\"activeCell\"\r\n [todayValue]=\"todayYear\"\r\n [selectedValues]=\"selectedYears\"\r\n [selectMode]=\"selectMode\"\r\n (keydown)=\"handleCalendarKeydown($event)\"\r\n (select)=\"selectCalendarCell($event)\"></tbody>\r\n</table>\r\n<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n [disabled]=\"!nextEnabled()\" [attr.aria-label]=\"nextButtonLabel\"\r\n type=\"button\" tabindex=\"0\" (click)=\"nextYearList($event)\">\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG Arrow Right\"> -->\r\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\" style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\">\r\n <path style=\"fill-rule:evenodd;clip-rule:evenodd;\" d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\r\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\r\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\r\n C197.237,120.447,195.534,115.448,191.75,111.689z\"/>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n" }]
974
+ }, standalone: false, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n [disabled]=\"!previousEnabled()\" [attr.aria-label]=\"prevButtonLabel\"\r\n type=\"button\" tabindex=\"0\" (click)=\"prevYearList($event)\">\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043B\u0435\u0432\u043E\"> -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\" x=\"0px\" y=\"0px\" viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\"\r\n width=\"100%\" height=\"100%\">\r\n <path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M96.633,125.369l95.053-94.533c7.101-7.055,7.101-18.492,0-25.546 c-7.1-7.054-18.613-7.054-25.714,0L58.989,111.689c-3.784,3.759-5.487,8.759-5.238,13.68c-0.249,4.922,1.454,9.921,5.238,13.681 l106.983,106.398c7.101,7.055,18.613,7.055,25.714,0c7.101-7.054,7.101-18.491,0-25.544L96.633,125.369z\"/>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n<table class=\"owl-dt-calendar-table owl-dt-calendar-multi-year-table\">\r\n <thead class=\"owl-dt-calendar-header\">\r\n <tr>\r\n <th [attr.colspan]=\"options.yearsPerRow\">{{tableHeader}}</th>\r\n </tr>\r\n </thead>\r\n <tbody owl-date-time-calendar-body role=\"grid\"\r\n [rows]=\"years\" [numCols]=\"options.yearsPerRow\" [cellRatio]=\"3 / 7\"\r\n [activeCell]=\"activeCell\"\r\n [todayValue]=\"todayYear\"\r\n [selectedValues]=\"selectedYears\"\r\n [selectMode]=\"selectMode\"\r\n (keydown)=\"handleCalendarKeydown($event)\"\r\n (select)=\"selectCalendarCell($event)\"></tbody>\r\n</table>\r\n<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n [disabled]=\"!nextEnabled()\" [attr.aria-label]=\"nextButtonLabel\"\r\n type=\"button\" tabindex=\"0\" (click)=\"nextYearList($event)\">\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043F\u0440\u0430\u0432\u043E\"> -->\r\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\" style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\">\r\n <path style=\"fill-rule:evenodd;clip-rule:evenodd;\" d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\r\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\r\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\r\n C197.237,120.447,195.534,115.448,191.75,111.689z\"/>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n" }]
947
975
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: OwlDateTimeIntl }, { type: DateTimeAdapter, decorators: [{
948
976
  type: Optional
949
977
  }] }, { type: undefined, decorators: [{
@@ -1005,7 +1033,7 @@ class OwlYearViewComponent {
1005
1033
  }
1006
1034
  set selecteds(values) {
1007
1035
  this._selecteds = [];
1008
- for (let i = 0; i < values.length; i++) {
1036
+ for (let i = 0; i < (values?.length ?? 0); i++) {
1009
1037
  const value = this.dateTimeAdapter.deserialize(values[i]);
1010
1038
  this._selecteds.push(this.getValidDate(value));
1011
1039
  }
@@ -1018,7 +1046,7 @@ class OwlYearViewComponent {
1018
1046
  const oldDateTime = this._pickerDateTime;
1019
1047
  value = this.dateTimeAdapter.deserialize(value);
1020
1048
  this._pickerDateTime =
1021
- this.getValidDate(value) || this.dateTimeAdapter.now();
1049
+ this.getValidDate(value) ?? this.dateTimeAdapter.now();
1022
1050
  if (!this.hasSameYear(oldDateTime, this._pickerDateTime) &&
1023
1051
  this.initiated) {
1024
1052
  this.generateMonthList();
@@ -1057,7 +1085,7 @@ class OwlYearViewComponent {
1057
1085
  return this._months;
1058
1086
  }
1059
1087
  get activeCell() {
1060
- if (this._pickerDateTime) {
1088
+ if (this._pickerDateTime != null) {
1061
1089
  return this.dateTimeAdapter.getMonth(this._pickerDateTime);
1062
1090
  }
1063
1091
  }
@@ -1077,33 +1105,34 @@ class OwlYearViewComponent {
1077
1105
  this.dateTimeAdapter = dateTimeAdapter;
1078
1106
  this.dateTimeFormats = dateTimeFormats;
1079
1107
  /**
1080
- * The select mode of the picker;
1108
+ * Режим выбора даты
1081
1109
  * */
1082
1110
  this._selectMode = 'single';
1083
1111
  this._selecteds = [];
1084
1112
  this.localeSub = Subscription.EMPTY;
1085
1113
  this.initiated = false;
1086
1114
  /**
1087
- * An array to hold all selectedDates' month value
1088
- * the value is the month number in current year
1115
+ * Массив номеров месяцев из selectedDates
1116
+ * Значение — номер месяца в текущем году
1089
1117
  * */
1090
1118
  this.selectedMonths = [];
1091
1119
  /**
1092
- * Callback to invoke when a new month is selected
1120
+ * Обработчик выбора нового месяца
1093
1121
  * */
1094
1122
  this.change = new EventEmitter();
1095
1123
  /**
1096
- * Emits the selected year. This doesn't imply a change on the selected date
1124
+ * Передаёт выбранный год, не изменяя выбранную дату
1097
1125
  * */
1098
1126
  this.monthSelected = new EventEmitter();
1099
- /** Emits when any date is activated. */
1127
+ /** Событие активации любой даты */
1100
1128
  this.pickerDateTimeChange = new EventEmitter();
1101
- /** Emits when use keyboard enter to select a calendar cell */
1129
+ /** Событие выбора ячейки календаря клавишей Enter */
1102
1130
  this.keyboardEnter = new EventEmitter();
1103
1131
  this.monthNames = this.dateTimeAdapter.getMonthNames('short');
1104
1132
  }
1105
1133
  ngOnInit() {
1106
1134
  this.localeSub = this.dateTimeAdapter.localeChanges.subscribe(() => {
1135
+ this.monthNames = this.dateTimeAdapter.getMonthNames('short');
1107
1136
  this.generateMonthList();
1108
1137
  this.cdRef.markForCheck();
1109
1138
  });
@@ -1116,13 +1145,15 @@ class OwlYearViewComponent {
1116
1145
  this.localeSub.unsubscribe();
1117
1146
  }
1118
1147
  /**
1119
- * Handle a calendarCell selected
1148
+ * Обрабатывает выбор ячейки календаря
1120
1149
  */
1121
1150
  selectCalendarCell(cell) {
1122
- this.selectMonth(cell.value);
1151
+ if (cell.enabled) {
1152
+ this.selectMonth(cell.value);
1153
+ }
1123
1154
  }
1124
1155
  /**
1125
- * Handle a new month selected
1156
+ * Обрабатывает выбор нового месяца
1126
1157
  */
1127
1158
  selectMonth(month) {
1128
1159
  const firstDateOfMonth = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(this.pickerDateTime), month, 1);
@@ -1132,55 +1163,57 @@ class OwlYearViewComponent {
1132
1163
  this.change.emit(result);
1133
1164
  }
1134
1165
  /**
1135
- * Handle keydown event on calendar body
1166
+ * Обрабатывает keydown в таблице календаря
1136
1167
  */
1137
1168
  handleCalendarKeydown(event) {
1138
1169
  let dateTime;
1139
1170
  switch (event.keyCode) {
1140
- // minus 1 month
1171
+ // На один месяц назад
1141
1172
  case LEFT_ARROW:
1142
1173
  dateTime = this.dateTimeAdapter.addCalendarMonths(this.pickerDateTime, -1);
1143
1174
  this.pickerDateTimeChange.emit(dateTime);
1144
1175
  break;
1145
- // add 1 month
1176
+ // На один месяц вперёд
1146
1177
  case RIGHT_ARROW:
1147
1178
  dateTime = this.dateTimeAdapter.addCalendarMonths(this.pickerDateTime, 1);
1148
1179
  this.pickerDateTimeChange.emit(dateTime);
1149
1180
  break;
1150
- // minus 3 months
1181
+ // На три месяца назад
1151
1182
  case UP_ARROW:
1152
1183
  dateTime = this.dateTimeAdapter.addCalendarMonths(this.pickerDateTime, -3);
1153
1184
  this.pickerDateTimeChange.emit(dateTime);
1154
1185
  break;
1155
- // add 3 months
1186
+ // На три месяца вперёд
1156
1187
  case DOWN_ARROW:
1157
1188
  dateTime = this.dateTimeAdapter.addCalendarMonths(this.pickerDateTime, 3);
1158
1189
  this.pickerDateTimeChange.emit(dateTime);
1159
1190
  break;
1160
- // move to first month of current year
1191
+ // К первому месяцу текущего года
1161
1192
  case HOME:
1162
1193
  dateTime = this.dateTimeAdapter.addCalendarMonths(this.pickerDateTime, -this.dateTimeAdapter.getMonth(this.pickerDateTime));
1163
1194
  this.pickerDateTimeChange.emit(dateTime);
1164
1195
  break;
1165
- // move to last month of current year
1196
+ // К последнему месяцу текущего года
1166
1197
  case END:
1167
1198
  dateTime = this.dateTimeAdapter.addCalendarMonths(this.pickerDateTime, 11 - this.dateTimeAdapter.getMonth(this.pickerDateTime));
1168
1199
  this.pickerDateTimeChange.emit(dateTime);
1169
1200
  break;
1170
- // minus 1 year (or 10 year)
1201
+ // На один год (или десять лет) назад
1171
1202
  case PAGE_UP:
1172
1203
  dateTime = this.dateTimeAdapter.addCalendarYears(this.pickerDateTime, event.altKey ? -10 : -1);
1173
1204
  this.pickerDateTimeChange.emit(dateTime);
1174
1205
  break;
1175
- // add 1 year (or 10 year)
1206
+ // На один год (или десять лет) вперёд
1176
1207
  case PAGE_DOWN:
1177
1208
  dateTime = this.dateTimeAdapter.addCalendarYears(this.pickerDateTime, event.altKey ? 10 : 1);
1178
1209
  this.pickerDateTimeChange.emit(dateTime);
1179
1210
  break;
1180
- // Select current month
1211
+ // Выбирает текущий месяц
1181
1212
  case ENTER:
1182
- this.selectMonth(this.dateTimeAdapter.getMonth(this.pickerDateTime));
1183
- this.keyboardEnter.emit();
1213
+ if (this.isMonthEnabled(this.dateTimeAdapter.getMonth(this.pickerDateTime))) {
1214
+ this.selectMonth(this.dateTimeAdapter.getMonth(this.pickerDateTime));
1215
+ this.keyboardEnter.emit();
1216
+ }
1184
1217
  break;
1185
1218
  default:
1186
1219
  return;
@@ -1189,10 +1222,10 @@ class OwlYearViewComponent {
1189
1222
  event.preventDefault();
1190
1223
  }
1191
1224
  /**
1192
- * Generate the calendar month list
1225
+ * Создаёт список месяцев календаря
1193
1226
  * */
1194
1227
  generateMonthList() {
1195
- if (!this.pickerDateTime) {
1228
+ if (this.pickerDateTime == null) {
1196
1229
  return;
1197
1230
  }
1198
1231
  this.setSelectedMonths();
@@ -1210,7 +1243,7 @@ class OwlYearViewComponent {
1210
1243
  return;
1211
1244
  }
1212
1245
  /**
1213
- * Creates an CalendarCell for the given month.
1246
+ * Создаёт CalendarCell для указанного месяца
1214
1247
  */
1215
1248
  createMonthCell(month) {
1216
1249
  const startDateOfMonth = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(this.pickerDateTime), month, 1);
@@ -1219,18 +1252,18 @@ class OwlYearViewComponent {
1219
1252
  return new CalendarCell(month, this.monthNames[month - this.dateTimeAdapter.firstMonthOfTheYear], ariaLabel, this.isMonthEnabled(month), false, cellClass);
1220
1253
  }
1221
1254
  /**
1222
- * Check if the given month is enable
1255
+ * Проверяет доступность указанного месяца для выбора
1223
1256
  */
1224
1257
  isMonthEnabled(month) {
1225
1258
  const firstDateOfMonth = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(this.pickerDateTime), month, 1);
1226
- // If any date in the month is selectable,
1227
- // we count the month as enable
1259
+ // Если в месяце доступна для выбора хотя бы одна дата,
1260
+ // считаем месяц доступным для выбора
1228
1261
  for (let date = firstDateOfMonth; this.dateTimeAdapter.getMonth(date) === month; date = this.dateTimeAdapter.addCalendarDays(date, 1)) {
1229
- if (!!date &&
1262
+ if (date != null &&
1230
1263
  (!this.dateFilter || this.dateFilter(date)) &&
1231
- (!this.minDate ||
1264
+ (this.minDate == null ||
1232
1265
  this.dateTimeAdapter.compare(date, this.minDate) >= 0) &&
1233
- (!this.maxDate ||
1266
+ (this.maxDate == null ||
1234
1267
  this.dateTimeAdapter.compare(date, this.maxDate) <= 0)) {
1235
1268
  return true;
1236
1269
  }
@@ -1238,15 +1271,15 @@ class OwlYearViewComponent {
1238
1271
  return false;
1239
1272
  }
1240
1273
  /**
1241
- * Gets the month in this year that the given Date falls on.
1242
- * Returns null if the given Date is in another year.
1274
+ * Возвращает месяц указанной даты в текущем году
1275
+ * Возвращает null, если указанная дата находится в другом году
1243
1276
  */
1244
1277
  getMonthInCurrentYear(date) {
1245
- if (this.getValidDate(date) && this.getValidDate(this._pickerDateTime)) {
1278
+ if (this.getValidDate(date) != null && this.getValidDate(this._pickerDateTime) != null) {
1246
1279
  const result = this.dateTimeAdapter.compareYear(date, this._pickerDateTime);
1247
- // < 0: the selected date is in an earlier year, so return -1.
1248
- // > 0: the selected date is in a later year, so return 12.
1249
- // 0: both values are in the same year, so return the actual month.
1280
+ // < 0: выбранная дата находится в предыдущем году, поэтому возвращаем -1
1281
+ // > 0: выбранная дата находится в следующем году, поэтому возвращаем 12
1282
+ // 0: оба значения находятся в одном году, поэтому возвращаем номер месяца
1250
1283
  if (result < 0) {
1251
1284
  return -1;
1252
1285
  }
@@ -1262,13 +1295,13 @@ class OwlYearViewComponent {
1262
1295
  }
1263
1296
  }
1264
1297
  /**
1265
- * Set the selectedMonths value
1266
- * In single mode, it has only one value which represent the month the selected date in
1267
- * In range mode, it would has two values, one for the month the fromValue in and the other for the month the toValue in
1298
+ * Задаёт значение selectedMonths
1299
+ * В режиме single содержит одно значение — месяц выбранной даты
1300
+ * В режиме range содержит два значения: месяц fromValue и месяц toValue
1268
1301
  * */
1269
1302
  setSelectedMonths() {
1270
1303
  this.selectedMonths = [];
1271
- if (this.isInSingleMode && this.selected) {
1304
+ if (this.isInSingleMode && this.selected != null) {
1272
1305
  this.selectedMonths[0] = this.getMonthInCurrentYear(this.selected);
1273
1306
  }
1274
1307
  if (this.isInRangeMode && this.selecteds) {
@@ -1277,16 +1310,16 @@ class OwlYearViewComponent {
1277
1310
  }
1278
1311
  }
1279
1312
  /**
1280
- * Check the given dates are in the same year
1313
+ * Проверяет, находятся ли указанные даты в одном году
1281
1314
  */
1282
1315
  hasSameYear(dateLeft, dateRight) {
1283
- return !!(dateLeft &&
1284
- dateRight &&
1316
+ return !!(dateLeft != null &&
1317
+ dateRight != null &&
1285
1318
  this.dateTimeAdapter.getYear(dateLeft) ===
1286
1319
  this.dateTimeAdapter.getYear(dateRight));
1287
1320
  }
1288
1321
  /**
1289
- * Get a valid date object
1322
+ * Возвращает корректный объект даты
1290
1323
  */
1291
1324
  getValidDate(obj) {
1292
1325
  return this.dateTimeAdapter.isDateInstance(obj) &&
@@ -1384,7 +1417,7 @@ class OwlMonthViewComponent {
1384
1417
  return this._selecteds;
1385
1418
  }
1386
1419
  set selecteds(values) {
1387
- this._selecteds = values.map(v => {
1420
+ this._selecteds = (values ?? []).map(v => {
1388
1421
  v = this.dateTimeAdapter.deserialize(v);
1389
1422
  return this.getValidDate(v);
1390
1423
  });
@@ -1397,7 +1430,7 @@ class OwlMonthViewComponent {
1397
1430
  const oldDateTime = this._pickerDateTime;
1398
1431
  value = this.dateTimeAdapter.deserialize(value);
1399
1432
  this._pickerDateTime =
1400
- this.getValidDate(value) || this.dateTimeAdapter.now();
1433
+ this.getValidDate(value) ?? this.dateTimeAdapter.now();
1401
1434
  this.firstDateOfMonth = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(this._pickerDateTime), this.dateTimeAdapter.getMonth(this._pickerDateTime), 1);
1402
1435
  if (!this.isSameMonth(oldDateTime, this._pickerDateTime) &&
1403
1436
  this.initiated) {
@@ -1443,7 +1476,7 @@ class OwlMonthViewComponent {
1443
1476
  return this._days;
1444
1477
  }
1445
1478
  get activeCell() {
1446
- if (this.pickerDateTime) {
1479
+ if (this.pickerDateTime != null) {
1447
1480
  return (this.dateTimeAdapter.getDate(this.pickerDateTime) +
1448
1481
  this.firstRowOffset -
1449
1482
  1);
@@ -1465,35 +1498,35 @@ class OwlMonthViewComponent {
1465
1498
  this.dateTimeAdapter = dateTimeAdapter;
1466
1499
  this.dateTimeFormats = dateTimeFormats;
1467
1500
  /**
1468
- * Whether to hide dates in other months at the start or end of the current month.
1501
+ * Нужно ли скрывать даты соседних месяцев в начале или конце текущего месяца
1469
1502
  * */
1470
1503
  this.hideOtherMonths = false;
1471
1504
  /**
1472
- * Whether to show calendar weeks in the calendar
1505
+ * Нужно ли показывать номера недель в календаре
1473
1506
  * */
1474
1507
  this.showCalendarWeeks = false;
1475
1508
  this.isDefaultFirstDayOfWeek = true;
1476
1509
  /**
1477
- * The select mode of the picker;
1510
+ * Режим выбора даты
1478
1511
  * */
1479
1512
  this._selectMode = 'single';
1480
1513
  this._selecteds = [];
1481
1514
  this.localeSub = Subscription.EMPTY;
1482
1515
  this.initiated = false;
1483
1516
  /**
1484
- * An array to hold all selectedDates' value
1485
- * the value is the day number in current month
1517
+ * Массив значений selectedDates
1518
+ * Значение — номер дня в текущем месяце
1486
1519
  * */
1487
1520
  this.selectedDates = [];
1488
1521
  /**
1489
- * Callback to invoke when a new date is selected
1522
+ * Обработчик выбора новой даты
1490
1523
  * */
1491
1524
  this.selectedChange = new EventEmitter();
1492
1525
  /**
1493
- * Callback to invoke when any date is selected.
1526
+ * Обработчик выбора любой даты
1494
1527
  * */
1495
1528
  this.userSelection = new EventEmitter();
1496
- /** Emits when any date is activated. */
1529
+ /** Событие активации любой даты */
1497
1530
  this.pickerDateTimeChange = new EventEmitter();
1498
1531
  }
1499
1532
  ngOnInit() {
@@ -1514,19 +1547,19 @@ class OwlMonthViewComponent {
1514
1547
  this.localeSub.unsubscribe();
1515
1548
  }
1516
1549
  /**
1517
- * Handle a calendarCell selected
1550
+ * Обрабатывает выбор ячейки календаря
1518
1551
  */
1519
1552
  selectCalendarCell(cell) {
1520
- // Cases in which the date would not be selected
1521
- // 1, the calendar cell is NOT enabled (is NOT valid)
1522
- // 2, the selected date is NOT in current picker's month and the hideOtherMonths is enabled
1553
+ // Условия, при которых дата не выбирается:
1554
+ // 1) Ячейка календаря недоступна для выбора
1555
+ // 2) Дата находится вне текущего месяца и включён hideOtherMonths
1523
1556
  if (!cell.enabled || (this.hideOtherMonths && cell.out)) {
1524
1557
  return;
1525
1558
  }
1526
1559
  this.selectDate(cell.value);
1527
1560
  }
1528
1561
  /**
1529
- * Handle a new date selected
1562
+ * Обрабатывает выбор новой даты
1530
1563
  */
1531
1564
  selectDate(date) {
1532
1565
  const daysDiff = date - 1;
@@ -1535,59 +1568,59 @@ class OwlMonthViewComponent {
1535
1568
  this.userSelection.emit();
1536
1569
  }
1537
1570
  /**
1538
- * Handle keydown event on calendar body
1571
+ * Обрабатывает keydown в таблице календаря
1539
1572
  */
1540
1573
  handleCalendarKeydown(event) {
1541
1574
  let dateTime;
1542
1575
  switch (event.keyCode) {
1543
- // minus 1 day
1576
+ // На один день назад
1544
1577
  case LEFT_ARROW:
1545
1578
  dateTime = this.dateTimeAdapter.addCalendarDays(this.pickerDateTime, -1);
1546
1579
  this.pickerDateTimeChange.emit(dateTime);
1547
1580
  break;
1548
- // add 1 day
1581
+ // На один день вперёд
1549
1582
  case RIGHT_ARROW:
1550
1583
  dateTime = this.dateTimeAdapter.addCalendarDays(this.pickerDateTime, 1);
1551
1584
  this.pickerDateTimeChange.emit(dateTime);
1552
1585
  break;
1553
- // minus 1 week
1586
+ // На одну неделю назад
1554
1587
  case UP_ARROW:
1555
1588
  dateTime = this.dateTimeAdapter.addCalendarDays(this.pickerDateTime, -7);
1556
1589
  this.pickerDateTimeChange.emit(dateTime);
1557
1590
  break;
1558
- // add 1 week
1591
+ // На одну неделю вперёд
1559
1592
  case DOWN_ARROW:
1560
1593
  dateTime = this.dateTimeAdapter.addCalendarDays(this.pickerDateTime, 7);
1561
1594
  this.pickerDateTimeChange.emit(dateTime);
1562
1595
  break;
1563
- // move to first day of current month
1596
+ // К первому дню текущего месяца
1564
1597
  case HOME:
1565
1598
  dateTime = this.dateTimeAdapter.addCalendarDays(this.pickerDateTime, 1 - this.dateTimeAdapter.getDate(this.pickerDateTime));
1566
1599
  this.pickerDateTimeChange.emit(dateTime);
1567
1600
  break;
1568
- // move to last day of current month
1601
+ // К последнему дню текущего месяца
1569
1602
  case END:
1570
1603
  dateTime = this.dateTimeAdapter.addCalendarDays(this.pickerDateTime, this.dateTimeAdapter.getNumDaysInMonth(this.pickerDateTime) -
1571
1604
  this.dateTimeAdapter.getDate(this.pickerDateTime));
1572
1605
  this.pickerDateTimeChange.emit(dateTime);
1573
1606
  break;
1574
- // minus 1 month (or 1 year)
1607
+ // На один месяц (или год) назад
1575
1608
  case PAGE_UP:
1576
1609
  dateTime = event.altKey
1577
1610
  ? this.dateTimeAdapter.addCalendarYears(this.pickerDateTime, -1)
1578
1611
  : this.dateTimeAdapter.addCalendarMonths(this.pickerDateTime, -1);
1579
1612
  this.pickerDateTimeChange.emit(dateTime);
1580
1613
  break;
1581
- // add 1 month (or 1 year)
1614
+ // На один месяц (или год) вперёд
1582
1615
  case PAGE_DOWN:
1583
1616
  dateTime = event.altKey
1584
1617
  ? this.dateTimeAdapter.addCalendarYears(this.pickerDateTime, 1)
1585
1618
  : this.dateTimeAdapter.addCalendarMonths(this.pickerDateTime, 1);
1586
1619
  this.pickerDateTimeChange.emit(dateTime);
1587
1620
  break;
1588
- // Select the active date.
1621
+ // Выбирает активную дату
1589
1622
  case ENTER:
1590
- if (!this.dateFilter || this.dateFilter(this.pickerDateTime)) {
1623
+ if (this.isDateEnabled(this.dateTimeAdapter.addCalendarDays(this.firstDateOfMonth, this.dateTimeAdapter.getDate(this.pickerDateTime) - 1))) {
1591
1624
  this.selectDate(this.dateTimeAdapter.getDate(this.pickerDateTime));
1592
1625
  }
1593
1626
  break;
@@ -1598,7 +1631,7 @@ class OwlMonthViewComponent {
1598
1631
  event.preventDefault();
1599
1632
  }
1600
1633
  /**
1601
- * Generate the calendar weekdays array
1634
+ * Создаёт массив дней недели для календаря
1602
1635
  * */
1603
1636
  generateWeekDays() {
1604
1637
  const longWeekdays = this.dateTimeAdapter.getDayOfWeekNames('long');
@@ -1615,10 +1648,10 @@ class OwlMonthViewComponent {
1615
1648
  return;
1616
1649
  }
1617
1650
  /**
1618
- * Generate the calendar days array
1651
+ * Создаёт массив дней календаря
1619
1652
  * */
1620
1653
  generateCalendar() {
1621
- if (!this.pickerDateTime) {
1654
+ if (this.pickerDateTime == null) {
1622
1655
  return;
1623
1656
  }
1624
1657
  this.todayDate = null;
@@ -1652,11 +1685,11 @@ class OwlMonthViewComponent {
1652
1685
  }
1653
1686
  getISOWeek(d) {
1654
1687
  const clonedDate = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
1655
- // Make Sunday's day number 7
1688
+ // Используем для воскресенья номер дня 7
1656
1689
  clonedDate.setUTCDate(clonedDate.getUTCDate() + 4 - (clonedDate.getUTCDay() || 7));
1657
- // Get first day of year
1690
+ // Получаем первый день года
1658
1691
  const yearStart = new Date(Date.UTC(clonedDate.getUTCFullYear(), 0, 1));
1659
- // Calculate full weeks to nearest Thursday
1692
+ // Вычисляем число полных недель до ближайшего четверга
1660
1693
  const weekNo = Math.ceil((((+clonedDate - +yearStart) / 86400000) + 1) / 7);
1661
1694
  return weekNo;
1662
1695
  }
@@ -1671,36 +1704,36 @@ class OwlMonthViewComponent {
1671
1704
  }
1672
1705
  }
1673
1706
  /**
1674
- * Creates CalendarCell for days.
1707
+ * Создаёт CalendarCell для дней
1675
1708
  */
1676
1709
  createDateCell(date, daysDiff) {
1677
- // total days of the month
1710
+ // Количество дней в месяце
1678
1711
  const daysInMonth = this.dateTimeAdapter.getNumDaysInMonth(this.pickerDateTime);
1679
1712
  const dateNum = this.dateTimeAdapter.getDate(date);
1680
1713
  // const dateName = this.dateNames[dateNum - 1];
1681
1714
  const dateName = dateNum.toString();
1682
1715
  const ariaLabel = this.dateTimeAdapter.format(date, this.dateTimeFormats.dateA11yLabel);
1683
- // check if the date if selectable
1716
+ // Проверяем доступность даты для выбора
1684
1717
  const enabled = this.isDateEnabled(date);
1685
- // check if date is not in current month
1718
+ // Проверяем, находится ли дата вне текущего месяца
1686
1719
  const dayValue = daysDiff + 1;
1687
1720
  const out = dayValue < 1 || dayValue > daysInMonth;
1688
1721
  const cellClass = 'owl-dt-day-' + this.dateTimeAdapter.getDay(date);
1689
1722
  return new CalendarCell(dayValue, dateName, ariaLabel, enabled, out, cellClass);
1690
1723
  }
1691
1724
  /**
1692
- * Check if the date is valid
1725
+ * Проверяет допустимость даты
1693
1726
  */
1694
1727
  isDateEnabled(date) {
1695
- return (!!date &&
1728
+ return (date != null &&
1696
1729
  (!this.dateFilter || this.dateFilter(date)) &&
1697
- (!this.minDate ||
1730
+ (this.minDate == null ||
1698
1731
  this.dateTimeAdapter.compare(date, this.minDate) >= 0) &&
1699
- (!this.maxDate ||
1732
+ (this.maxDate == null ||
1700
1733
  this.dateTimeAdapter.compare(date, this.maxDate) <= 0));
1701
1734
  }
1702
1735
  /**
1703
- * Get a valid date object
1736
+ * Возвращает корректный объект даты
1704
1737
  */
1705
1738
  getValidDate(obj) {
1706
1739
  return this.dateTimeAdapter.isDateInstance(obj) &&
@@ -1709,11 +1742,11 @@ class OwlMonthViewComponent {
1709
1742
  : null;
1710
1743
  }
1711
1744
  /**
1712
- * Check if the give dates are none-null and in the same month
1745
+ * Проверяет, что даты не равны null и находятся в одном месяце
1713
1746
  */
1714
1747
  isSameMonth(dateLeft, dateRight) {
1715
- return (dateLeft &&
1716
- dateRight &&
1748
+ return (dateLeft != null &&
1749
+ dateRight != null &&
1717
1750
  this.dateTimeAdapter.isValid(dateLeft) &&
1718
1751
  this.dateTimeAdapter.isValid(dateRight) &&
1719
1752
  this.dateTimeAdapter.getYear(dateLeft) ===
@@ -1728,16 +1761,16 @@ class OwlMonthViewComponent {
1728
1761
  return Math.ceil((((+jsDate - +yearStart) / 86400000) + 1) / 7);
1729
1762
  }
1730
1763
  /**
1731
- * Set the selectedDates value.
1732
- * In single mode, it has only one value which represent the selected date
1733
- * In range mode, it would has two values, one for the fromValue and the other for the toValue
1764
+ * Задаёт значение selectedDates
1765
+ * В режиме single содержит одно значение — выбранную дату
1766
+ * В режиме range содержит два значения: fromValue и toValue
1734
1767
  * */
1735
1768
  setSelectedDates() {
1736
1769
  this.selectedDates = [];
1737
- if (!this.firstDateOfMonth) {
1770
+ if (this.firstDateOfMonth == null) {
1738
1771
  return;
1739
1772
  }
1740
- if (this.isInSingleMode && this.selected) {
1773
+ if (this.isInSingleMode && this.selected != null) {
1741
1774
  const dayDiff = this.dateTimeAdapter.differenceInCalendarDays(this.selected, this.firstDateOfMonth);
1742
1775
  this.selectedDates[0] = dayDiff + 1;
1743
1776
  return;
@@ -1813,7 +1846,7 @@ class OwlCalendarComponent {
1813
1846
  set minDate(value) {
1814
1847
  value = this.dateTimeAdapter.deserialize(value);
1815
1848
  value = this.getValidDate(value);
1816
- this._minDate = value
1849
+ this._minDate = value != null
1817
1850
  ? this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(value), this.dateTimeAdapter.getMonth(value), this.dateTimeAdapter.getDate(value))
1818
1851
  : null;
1819
1852
  }
@@ -1823,7 +1856,7 @@ class OwlCalendarComponent {
1823
1856
  set maxDate(value) {
1824
1857
  value = this.dateTimeAdapter.deserialize(value);
1825
1858
  value = this.getValidDate(value);
1826
- this._maxDate = value
1859
+ this._maxDate = value != null
1827
1860
  ? this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(value), this.dateTimeAdapter.getMonth(value), this.dateTimeAdapter.getDate(value))
1828
1861
  : null;
1829
1862
  }
@@ -1833,7 +1866,7 @@ class OwlCalendarComponent {
1833
1866
  set pickerDateTime(value) {
1834
1867
  value = this.dateTimeAdapter.deserialize(value);
1835
1868
  this._pickerDateTime =
1836
- this.getValidDate(value) || this.dateTimeAdapter.now();
1869
+ this.getValidDate(value) ?? this.dateTimeAdapter.now();
1837
1870
  }
1838
1871
  get selected() {
1839
1872
  return this._selected;
@@ -1846,7 +1879,7 @@ class OwlCalendarComponent {
1846
1879
  return this._selecteds;
1847
1880
  }
1848
1881
  set selecteds(values) {
1849
- this._selecteds = values.map(v => {
1882
+ this._selecteds = (values ?? []).map(v => {
1850
1883
  v = this.dateTimeAdapter.deserialize(v);
1851
1884
  return this.getValidDate(v);
1852
1885
  });
@@ -1905,7 +1938,7 @@ class OwlCalendarComponent {
1905
1938
  return this._currentView === DateView.MONTH;
1906
1939
  }
1907
1940
  /**
1908
- * Bind class 'owl-dt-calendar' to host
1941
+ * Добавляет класс 'owl-dt-calendar' к элементу компонента
1909
1942
  * */
1910
1943
  get owlDTCalendarClass() {
1911
1944
  return true;
@@ -1917,56 +1950,58 @@ class OwlCalendarComponent {
1917
1950
  this.cdRef = cdRef;
1918
1951
  this.dateTimeAdapter = dateTimeAdapter;
1919
1952
  this.dateTimeFormats = dateTimeFormats;
1953
+ this.injector = inject(Injector);
1954
+ this.destroyRef = inject(DestroyRef);
1920
1955
  this.DateView = DateView;
1921
1956
  this._selecteds = [];
1922
1957
  /**
1923
- * The view that the calendar should start in.
1958
+ * Начальное представление календаря
1924
1959
  */
1925
1960
  this.startView = DateView.MONTH;
1926
1961
  /**
1927
- * Whether to should only the year and multi-year views.
1962
+ * Нужно ли показывать только представления года и нескольких лет
1928
1963
  */
1929
1964
  this.yearOnly = false;
1930
1965
  /**
1931
- * Whether to show calendar weeks in the calendar
1966
+ * Нужно ли показывать номера недель в календаре
1932
1967
  * */
1933
1968
  this.showCalendarWeeks = false;
1934
1969
  /**
1935
- * Whether to should only the multi-year view.
1970
+ * Нужно ли показывать только представление нескольких лет
1936
1971
  */
1937
1972
  this.multiyearOnly = false;
1938
- /** Emits when the displayed date and time changes. */
1973
+ /** Событие изменения отображаемых даты и времени */
1939
1974
  this.pickerDateTimeChange = new EventEmitter();
1940
- /** Emits when the selected date changes. */
1975
+ /** Событие изменения выбранной даты */
1941
1976
  this.dateClicked = new EventEmitter();
1942
- /** Emits when the currently selected date changes. */
1977
+ /** Событие изменения текущей выбранной даты */
1943
1978
  this.selectedChange = new EventEmitter();
1944
- /** Emits when any date is selected. */
1979
+ /** Событие выбора любой даты */
1945
1980
  this.userSelection = new EventEmitter();
1946
1981
  /**
1947
- * Emits the selected year. This doesn't imply a change on the selected date
1982
+ * Передаёт выбранный год, не изменяя выбранную дату
1948
1983
  * */
1949
1984
  this.yearSelected = new EventEmitter();
1950
1985
  /**
1951
- * Emits the selected month. This doesn't imply a change on the selected date
1986
+ * Передаёт выбранный месяц, не изменяя выбранную дату
1952
1987
  * */
1953
1988
  this.monthSelected = new EventEmitter();
1954
1989
  this.intlChangesSub = Subscription.EMPTY;
1955
1990
  /**
1956
- * Used for scheduling that focus should be moved to the active cell on the next tick.
1957
- * We need to schedule it, rather than do it immediately, because we have to wait
1958
- * for Angular to re-evaluate the view children.
1991
+ * Откладывает перевод фокуса на активную ячейку до следующего обновления представления
1992
+ * Перевод фокуса откладывается, чтобы дождаться, пока Angular
1993
+ * обновит дочерние элементы представления
1959
1994
  */
1960
1995
  this.moveFocusOnNextTick = false;
1961
1996
  /**
1962
- * Date filter for the month and year view
1997
+ * Фильтр дат для представлений месяца и года
1963
1998
  */
1964
1999
  this.dateFilterForViews = (date) => {
1965
- return (!!date &&
2000
+ return (date != null &&
1966
2001
  (!this.dateFilter || this.dateFilter(date)) &&
1967
- (!this.minDate ||
2002
+ (this.minDate == null ||
1968
2003
  this.dateTimeAdapter.compare(date, this.minDate) >= 0) &&
1969
- (!this.maxDate ||
2004
+ (this.maxDate == null ||
1970
2005
  this.dateTimeAdapter.compare(date, this.maxDate) <= 0));
1971
2006
  };
1972
2007
  this.intlChangesSub = this.pickerIntl.changes.subscribe(() => {
@@ -1988,7 +2023,7 @@ class OwlCalendarComponent {
1988
2023
  this.intlChangesSub.unsubscribe();
1989
2024
  }
1990
2025
  /**
1991
- * Toggle between month view and year view
2026
+ * Переключает представления месяца и года
1992
2027
  */
1993
2028
  toggleViews() {
1994
2029
  let nextView = null;
@@ -2009,7 +2044,7 @@ class OwlCalendarComponent {
2009
2044
  this.currentView = nextView;
2010
2045
  }
2011
2046
  /**
2012
- * Handles user clicks on the previous button.
2047
+ * Обрабатывает нажатие кнопки перехода к предыдущему периоду
2013
2048
  * */
2014
2049
  previousClicked() {
2015
2050
  this.pickerDateTime = this.isMonthView
@@ -2018,7 +2053,7 @@ class OwlCalendarComponent {
2018
2053
  this.pickerDateTimeChange.emit(this.pickerDateTime);
2019
2054
  }
2020
2055
  /**
2021
- * Handles user clicks on the next button.
2056
+ * Обрабатывает нажатие кнопки перехода к следующему периоду
2022
2057
  * */
2023
2058
  nextClicked() {
2024
2059
  this.pickerDateTime = this.isMonthView
@@ -2038,7 +2073,7 @@ class OwlCalendarComponent {
2038
2073
  }*/
2039
2074
  }
2040
2075
  /**
2041
- * Change the displayed date and switch to a specific view.
2076
+ * Меняет отображаемую дату и переключается на указанное представление
2042
2077
  */
2043
2078
  goToDateInView(date, view) {
2044
2079
  this.handlePickerDateTimeChange(date);
@@ -2053,7 +2088,7 @@ class OwlCalendarComponent {
2053
2088
  return;
2054
2089
  }
2055
2090
  /**
2056
- * Change the displayed date.
2091
+ * Меняет отображаемую дату
2057
2092
  */
2058
2093
  handlePickerDateTimeChange(date) {
2059
2094
  this.pickerDateTime = this.dateTimeAdapter.clampDate(date, this.minDate, this.maxDate);
@@ -2064,31 +2099,31 @@ class OwlCalendarComponent {
2064
2099
  this.userSelection.emit();
2065
2100
  }
2066
2101
  /**
2067
- * Whether the previous period button is enabled.
2102
+ * Доступна ли кнопка перехода к предыдущему периоду
2068
2103
  */
2069
2104
  prevButtonEnabled() {
2070
- return (!this.minDate || !this.isSameView(this.pickerDateTime, this.minDate));
2105
+ return (this.minDate == null || !this.isSameView(this.pickerDateTime, this.minDate));
2071
2106
  }
2072
2107
  /**
2073
- * Whether the next period button is enabled.
2108
+ * Доступна ли кнопка перехода к следующему периоду
2074
2109
  */
2075
2110
  nextButtonEnabled() {
2076
- return (!this.maxDate || !this.isSameView(this.pickerDateTime, this.maxDate));
2111
+ return (this.maxDate == null || !this.isSameView(this.pickerDateTime, this.maxDate));
2077
2112
  }
2078
2113
  /**
2079
- * Focus to the host element
2114
+ * Переводит фокус на элемент компонента
2080
2115
  * */
2081
2116
  focusActiveCell() {
2082
- this.ngZone.runOutsideAngular(() => {
2083
- this.ngZone.onStable
2084
- .asObservable()
2085
- .pipe(take(1))
2086
- .subscribe(() => {
2087
- this.elmRef.nativeElement
2088
- .querySelector('.owl-dt-calendar-cell-active')
2089
- .focus();
2090
- });
2091
- });
2117
+ if (this.destroyRef.destroyed) {
2118
+ return;
2119
+ }
2120
+ this.focusRef?.destroy();
2121
+ this.focusRef = afterNextRender({
2122
+ write: () => {
2123
+ this.focusRef = undefined;
2124
+ this.elmRef.nativeElement.querySelector('.owl-dt-calendar-cell-active')?.focus();
2125
+ }
2126
+ }, { injector: this.injector });
2092
2127
  }
2093
2128
  selectYearInMultiYearView(normalizedYear) {
2094
2129
  this.yearSelected.emit(normalizedYear);
@@ -2097,20 +2132,20 @@ class OwlCalendarComponent {
2097
2132
  this.monthSelected.emit(normalizedMonth);
2098
2133
  }
2099
2134
  /**
2100
- * Whether the two dates represent the same view in the current view mode (month or year).
2135
+ * Соответствуют ли две даты одному представлению в текущем режиме (месяц или год)
2101
2136
  */
2102
2137
  isSameView(date1, date2) {
2103
2138
  if (this._currentView === DateView.MONTH) {
2104
- return !!(date1 &&
2105
- date2 &&
2139
+ return !!(date1 != null &&
2140
+ date2 != null &&
2106
2141
  this.dateTimeAdapter.getYear(date1) ===
2107
2142
  this.dateTimeAdapter.getYear(date2) &&
2108
2143
  this.dateTimeAdapter.getMonth(date1) ===
2109
2144
  this.dateTimeAdapter.getMonth(date2));
2110
2145
  }
2111
2146
  else if (this._currentView === DateView.YEAR) {
2112
- return !!(date1 &&
2113
- date2 &&
2147
+ return !!(date1 != null &&
2148
+ date2 != null &&
2114
2149
  this.dateTimeAdapter.getYear(date1) ===
2115
2150
  this.dateTimeAdapter.getYear(date2));
2116
2151
  }
@@ -2119,7 +2154,7 @@ class OwlCalendarComponent {
2119
2154
  }
2120
2155
  }
2121
2156
  /**
2122
- * Get a valid date object
2157
+ * Возвращает корректный объект даты
2123
2158
  */
2124
2159
  getValidDate(obj) {
2125
2160
  return this.dateTimeAdapter.isDateInstance(obj) &&
@@ -2128,13 +2163,13 @@ class OwlCalendarComponent {
2128
2163
  : null;
2129
2164
  }
2130
2165
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlCalendarComponent, deps: [{ token: i0.ElementRef }, { token: OwlDateTimeIntl }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: DateTimeAdapter, optional: true }, { token: OWL_DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
2131
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: OwlCalendarComponent, isStandalone: false, selector: "owl-date-time-calendar", inputs: { minDate: "minDate", maxDate: "maxDate", pickerDateTime: "pickerDateTime", selected: "selected", selecteds: "selecteds", dateFilter: "dateFilter", firstDayOfWeek: "firstDayOfWeek", selectMode: "selectMode", startView: "startView", yearOnly: "yearOnly", showCalendarWeeks: "showCalendarWeeks", multiyearOnly: "multiyearOnly", hideOtherMonths: "hideOtherMonths" }, outputs: { pickerDateTimeChange: "pickerDateTimeChange", dateClicked: "dateClicked", selectedChange: "selectedChange", userSelection: "userSelection", yearSelected: "yearSelected", monthSelected: "monthSelected" }, host: { properties: { "class.owl-dt-calendar": "owlDTCalendarClass" } }, exportAs: ["owlDateTimeCalendar"], ngImport: i0, template: "<div class=\"owl-dt-calendar-control\">\r\n <!-- focus when keyboard tab (http://kizu.ru/en/blog/keyboard-only-focus/#x) -->\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [style.visibility]=\"showControlArrows ? 'visible' : 'hidden'\"\r\n [disabled]=\"!prevButtonEnabled()\"\r\n [attr.aria-label]=\"prevButtonLabel\"\r\n (click)=\"previousClicked()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n <!-- <editor-fold desc=\"SVG Arrow Left\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background: new 0 0 250.738 250.738\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n style=\"fill-rule: evenodd; clip-rule: evenodd\"\r\n d=\"M96.633,125.369l95.053-94.533c7.101-7.055,7.101-18.492,0-25.546 c-7.1-7.054-18.613-7.054-25.714,0L58.989,111.689c-3.784,3.759-5.487,8.759-5.238,13.68c-0.249,4.922,1.454,9.921,5.238,13.681 l106.983,106.398c7.101,7.055,18.613,7.055,25.714,0c7.101-7.054,7.101-18.491,0-25.544L96.633,125.369z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </button>\r\n <div class=\"owl-dt-calendar-control-content\">\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-period-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [attr.aria-label]=\"periodButtonLabel\"\r\n (click)=\"toggleViews()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n {{ periodButtonText }}\r\n\r\n <span\r\n class=\"owl-dt-control-button-arrow\"\r\n [style.transform]=\"\r\n 'rotate(' + (isMonthView ? 0 : 180) + 'deg)'\r\n \"\r\n >\r\n <!-- <editor-fold desc=\"SVG Arrow\"> -->\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n width=\"50%\"\r\n height=\"50%\"\r\n viewBox=\"0 0 292.362 292.362\"\r\n style=\"enable-background: new 0 0 292.362 292.362\"\r\n xml:space=\"preserve\"\r\n >\r\n <g>\r\n <path\r\n d=\"M286.935,69.377c-3.614-3.617-7.898-5.424-12.848-5.424H18.274c-4.952,0-9.233,1.807-12.85,5.424\r\n C1.807,72.998,0,77.279,0,82.228c0,4.948,1.807,9.229,5.424,12.847l127.907,127.907c3.621,3.617,7.902,5.428,12.85,5.428\r\n s9.233-1.811,12.847-5.428L286.935,95.074c3.613-3.617,5.427-7.898,5.427-12.847C292.362,77.279,290.548,72.998,286.935,69.377z\"\r\n />\r\n </g>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </span>\r\n </button>\r\n </div>\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [style.visibility]=\"showControlArrows ? 'visible' : 'hidden'\"\r\n [disabled]=\"!nextButtonEnabled()\"\r\n [attr.aria-label]=\"nextButtonLabel\"\r\n (click)=\"nextClicked()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n <!-- <editor-fold desc=\"SVG Arrow Right\"> -->\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background: new 0 0 250.738 250.738\"\r\n xml:space=\"preserve\"\r\n >\r\n <path\r\n style=\"fill-rule: evenodd; clip-rule: evenodd\"\r\n d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\r\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\r\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\r\n C197.237,120.447,195.534,115.448,191.75,111.689z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </button>\r\n</div>\r\n<div class=\"owl-dt-calendar-main\" cdkMonitorSubtreeFocus tabindex=\"-1\">\r\n @switch (currentView) {\r\n @case (DateView.MONTH) {\r\n <owl-date-time-month-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [firstDayOfWeek]=\"firstDayOfWeek\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [showCalendarWeeks]=\"showCalendarWeeks\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n [hideOtherMonths]=\"hideOtherMonths\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (selectedChange)=\"dateSelected($event)\"\r\n (userSelection)=\"userSelected()\"\r\n ></owl-date-time-month-view>\r\n }\r\n @case (DateView.YEAR) {\r\n <owl-date-time-year-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n (keyboardEnter)=\"focusActiveCell()\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (monthSelected)=\"selectMonthInYearView($event)\"\r\n (change)=\"goToDateInView($event, DateView.MONTH)\"\r\n ></owl-date-time-year-view>\r\n }\r\n @case (DateView.MULTI_YEARS) {\r\n <owl-date-time-multi-year-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n (keyboardEnter)=\"focusActiveCell()\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (yearSelected)=\"selectYearInMultiYearView($event)\"\r\n (change)=\"goToDateInView($event, DateView.YEAR)\"\r\n ></owl-date-time-multi-year-view>\r\n }\r\n }\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "directive", type: i1.CdkMonitorFocus, selector: "[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]", outputs: ["cdkFocusChange"], exportAs: ["cdkMonitorFocus"] }, { kind: "component", type: OwlMultiYearViewComponent, selector: "owl-date-time-multi-year-view", inputs: ["selectMode", "selected", "selecteds", "pickerDateTime", "dateFilter", "minDate", "maxDate"], outputs: ["change", "yearSelected", "pickerDateTimeChange", "keyboardEnter"] }, { kind: "component", type: OwlYearViewComponent, selector: "owl-date-time-year-view", inputs: ["selectMode", "selected", "selecteds", "pickerDateTime", "dateFilter", "minDate", "maxDate"], outputs: ["change", "monthSelected", "pickerDateTimeChange", "keyboardEnter"], exportAs: ["owlMonthView"] }, { kind: "component", type: OwlMonthViewComponent, selector: "owl-date-time-month-view", inputs: ["hideOtherMonths", "showCalendarWeeks", "firstDayOfWeek", "selectMode", "selected", "selecteds", "pickerDateTime", "dateFilter", "minDate", "maxDate"], outputs: ["selectedChange", "userSelection", "pickerDateTimeChange"], exportAs: ["owlYearView"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2166
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: OwlCalendarComponent, isStandalone: false, selector: "owl-date-time-calendar", inputs: { minDate: "minDate", maxDate: "maxDate", pickerDateTime: "pickerDateTime", selected: "selected", selecteds: "selecteds", dateFilter: "dateFilter", firstDayOfWeek: "firstDayOfWeek", selectMode: "selectMode", startView: "startView", yearOnly: "yearOnly", showCalendarWeeks: "showCalendarWeeks", multiyearOnly: "multiyearOnly", hideOtherMonths: "hideOtherMonths" }, outputs: { pickerDateTimeChange: "pickerDateTimeChange", dateClicked: "dateClicked", selectedChange: "selectedChange", userSelection: "userSelection", yearSelected: "yearSelected", monthSelected: "monthSelected" }, host: { properties: { "class.owl-dt-calendar": "owlDTCalendarClass" } }, exportAs: ["owlDateTimeCalendar"], ngImport: i0, template: "<div class=\"owl-dt-calendar-control\">\r\n <!-- \u0424\u043E\u043A\u0443\u0441 \u043F\u0440\u0438 \u043D\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043A\u043B\u0430\u0432\u0438\u0448\u0435\u0439 Tab (http://kizu.ru/en/blog/keyboard-only-focus/#x) -->\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [style.visibility]=\"showControlArrows ? 'visible' : 'hidden'\"\r\n [disabled]=\"!prevButtonEnabled()\"\r\n [attr.aria-label]=\"prevButtonLabel\"\r\n (click)=\"previousClicked()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043B\u0435\u0432\u043E\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background: new 0 0 250.738 250.738\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n style=\"fill-rule: evenodd; clip-rule: evenodd\"\r\n d=\"M96.633,125.369l95.053-94.533c7.101-7.055,7.101-18.492,0-25.546 c-7.1-7.054-18.613-7.054-25.714,0L58.989,111.689c-3.784,3.759-5.487,8.759-5.238,13.68c-0.249,4.922,1.454,9.921,5.238,13.681 l106.983,106.398c7.101,7.055,18.613,7.055,25.714,0c7.101-7.054,7.101-18.491,0-25.544L96.633,125.369z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </button>\r\n <div class=\"owl-dt-calendar-control-content\">\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-period-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [attr.aria-label]=\"periodButtonLabel\"\r\n (click)=\"toggleViews()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n {{ periodButtonText }}\r\n\r\n <span\r\n class=\"owl-dt-control-button-arrow\"\r\n [style.transform]=\"\r\n 'rotate(' + (isMonthView ? 0 : 180) + 'deg)'\r\n \"\r\n >\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430\"> -->\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n width=\"50%\"\r\n height=\"50%\"\r\n viewBox=\"0 0 292.362 292.362\"\r\n style=\"enable-background: new 0 0 292.362 292.362\"\r\n xml:space=\"preserve\"\r\n >\r\n <g>\r\n <path\r\n d=\"M286.935,69.377c-3.614-3.617-7.898-5.424-12.848-5.424H18.274c-4.952,0-9.233,1.807-12.85,5.424\r\n C1.807,72.998,0,77.279,0,82.228c0,4.948,1.807,9.229,5.424,12.847l127.907,127.907c3.621,3.617,7.902,5.428,12.85,5.428\r\n s9.233-1.811,12.847-5.428L286.935,95.074c3.613-3.617,5.427-7.898,5.427-12.847C292.362,77.279,290.548,72.998,286.935,69.377z\"\r\n />\r\n </g>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </span>\r\n </button>\r\n </div>\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [style.visibility]=\"showControlArrows ? 'visible' : 'hidden'\"\r\n [disabled]=\"!nextButtonEnabled()\"\r\n [attr.aria-label]=\"nextButtonLabel\"\r\n (click)=\"nextClicked()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043F\u0440\u0430\u0432\u043E\"> -->\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background: new 0 0 250.738 250.738\"\r\n xml:space=\"preserve\"\r\n >\r\n <path\r\n style=\"fill-rule: evenodd; clip-rule: evenodd\"\r\n d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\r\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\r\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\r\n C197.237,120.447,195.534,115.448,191.75,111.689z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </button>\r\n</div>\r\n<div class=\"owl-dt-calendar-main\" cdkMonitorSubtreeFocus tabindex=\"-1\">\r\n @switch (currentView) {\r\n @case (DateView.MONTH) {\r\n <owl-date-time-month-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [firstDayOfWeek]=\"firstDayOfWeek\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [showCalendarWeeks]=\"showCalendarWeeks\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n [hideOtherMonths]=\"hideOtherMonths\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (selectedChange)=\"dateSelected($event)\"\r\n (userSelection)=\"userSelected()\"\r\n ></owl-date-time-month-view>\r\n }\r\n @case (DateView.YEAR) {\r\n <owl-date-time-year-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n (keyboardEnter)=\"focusActiveCell()\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (monthSelected)=\"selectMonthInYearView($event)\"\r\n (change)=\"goToDateInView($event, DateView.MONTH)\"\r\n ></owl-date-time-year-view>\r\n }\r\n @case (DateView.MULTI_YEARS) {\r\n <owl-date-time-multi-year-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n (keyboardEnter)=\"focusActiveCell()\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (yearSelected)=\"selectYearInMultiYearView($event)\"\r\n (change)=\"goToDateInView($event, DateView.YEAR)\"\r\n ></owl-date-time-multi-year-view>\r\n }\r\n }\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "directive", type: i1.CdkMonitorFocus, selector: "[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]", outputs: ["cdkFocusChange"], exportAs: ["cdkMonitorFocus"] }, { kind: "component", type: OwlMultiYearViewComponent, selector: "owl-date-time-multi-year-view", inputs: ["selectMode", "selected", "selecteds", "pickerDateTime", "dateFilter", "minDate", "maxDate"], outputs: ["change", "yearSelected", "pickerDateTimeChange", "keyboardEnter"] }, { kind: "component", type: OwlYearViewComponent, selector: "owl-date-time-year-view", inputs: ["selectMode", "selected", "selecteds", "pickerDateTime", "dateFilter", "minDate", "maxDate"], outputs: ["change", "monthSelected", "pickerDateTimeChange", "keyboardEnter"], exportAs: ["owlMonthView"] }, { kind: "component", type: OwlMonthViewComponent, selector: "owl-date-time-month-view", inputs: ["hideOtherMonths", "showCalendarWeeks", "firstDayOfWeek", "selectMode", "selected", "selecteds", "pickerDateTime", "dateFilter", "minDate", "maxDate"], outputs: ["selectedChange", "userSelection", "pickerDateTimeChange"], exportAs: ["owlYearView"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2132
2167
  }
2133
2168
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlCalendarComponent, decorators: [{
2134
2169
  type: Component,
2135
2170
  args: [{ selector: 'owl-date-time-calendar', exportAs: 'owlDateTimeCalendar', standalone: false, host: {
2136
2171
  '[class.owl-dt-calendar]': 'owlDTCalendarClass'
2137
- }, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"owl-dt-calendar-control\">\r\n <!-- focus when keyboard tab (http://kizu.ru/en/blog/keyboard-only-focus/#x) -->\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [style.visibility]=\"showControlArrows ? 'visible' : 'hidden'\"\r\n [disabled]=\"!prevButtonEnabled()\"\r\n [attr.aria-label]=\"prevButtonLabel\"\r\n (click)=\"previousClicked()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n <!-- <editor-fold desc=\"SVG Arrow Left\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background: new 0 0 250.738 250.738\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n style=\"fill-rule: evenodd; clip-rule: evenodd\"\r\n d=\"M96.633,125.369l95.053-94.533c7.101-7.055,7.101-18.492,0-25.546 c-7.1-7.054-18.613-7.054-25.714,0L58.989,111.689c-3.784,3.759-5.487,8.759-5.238,13.68c-0.249,4.922,1.454,9.921,5.238,13.681 l106.983,106.398c7.101,7.055,18.613,7.055,25.714,0c7.101-7.054,7.101-18.491,0-25.544L96.633,125.369z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </button>\r\n <div class=\"owl-dt-calendar-control-content\">\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-period-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [attr.aria-label]=\"periodButtonLabel\"\r\n (click)=\"toggleViews()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n {{ periodButtonText }}\r\n\r\n <span\r\n class=\"owl-dt-control-button-arrow\"\r\n [style.transform]=\"\r\n 'rotate(' + (isMonthView ? 0 : 180) + 'deg)'\r\n \"\r\n >\r\n <!-- <editor-fold desc=\"SVG Arrow\"> -->\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n width=\"50%\"\r\n height=\"50%\"\r\n viewBox=\"0 0 292.362 292.362\"\r\n style=\"enable-background: new 0 0 292.362 292.362\"\r\n xml:space=\"preserve\"\r\n >\r\n <g>\r\n <path\r\n d=\"M286.935,69.377c-3.614-3.617-7.898-5.424-12.848-5.424H18.274c-4.952,0-9.233,1.807-12.85,5.424\r\n C1.807,72.998,0,77.279,0,82.228c0,4.948,1.807,9.229,5.424,12.847l127.907,127.907c3.621,3.617,7.902,5.428,12.85,5.428\r\n s9.233-1.811,12.847-5.428L286.935,95.074c3.613-3.617,5.427-7.898,5.427-12.847C292.362,77.279,290.548,72.998,286.935,69.377z\"\r\n />\r\n </g>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </span>\r\n </button>\r\n </div>\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [style.visibility]=\"showControlArrows ? 'visible' : 'hidden'\"\r\n [disabled]=\"!nextButtonEnabled()\"\r\n [attr.aria-label]=\"nextButtonLabel\"\r\n (click)=\"nextClicked()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n <!-- <editor-fold desc=\"SVG Arrow Right\"> -->\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background: new 0 0 250.738 250.738\"\r\n xml:space=\"preserve\"\r\n >\r\n <path\r\n style=\"fill-rule: evenodd; clip-rule: evenodd\"\r\n d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\r\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\r\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\r\n C197.237,120.447,195.534,115.448,191.75,111.689z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </button>\r\n</div>\r\n<div class=\"owl-dt-calendar-main\" cdkMonitorSubtreeFocus tabindex=\"-1\">\r\n @switch (currentView) {\r\n @case (DateView.MONTH) {\r\n <owl-date-time-month-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [firstDayOfWeek]=\"firstDayOfWeek\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [showCalendarWeeks]=\"showCalendarWeeks\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n [hideOtherMonths]=\"hideOtherMonths\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (selectedChange)=\"dateSelected($event)\"\r\n (userSelection)=\"userSelected()\"\r\n ></owl-date-time-month-view>\r\n }\r\n @case (DateView.YEAR) {\r\n <owl-date-time-year-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n (keyboardEnter)=\"focusActiveCell()\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (monthSelected)=\"selectMonthInYearView($event)\"\r\n (change)=\"goToDateInView($event, DateView.MONTH)\"\r\n ></owl-date-time-year-view>\r\n }\r\n @case (DateView.MULTI_YEARS) {\r\n <owl-date-time-multi-year-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n (keyboardEnter)=\"focusActiveCell()\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (yearSelected)=\"selectYearInMultiYearView($event)\"\r\n (change)=\"goToDateInView($event, DateView.YEAR)\"\r\n ></owl-date-time-multi-year-view>\r\n }\r\n }\r\n</div>\r\n" }]
2172
+ }, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"owl-dt-calendar-control\">\r\n <!-- \u0424\u043E\u043A\u0443\u0441 \u043F\u0440\u0438 \u043D\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043A\u043B\u0430\u0432\u0438\u0448\u0435\u0439 Tab (http://kizu.ru/en/blog/keyboard-only-focus/#x) -->\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [style.visibility]=\"showControlArrows ? 'visible' : 'hidden'\"\r\n [disabled]=\"!prevButtonEnabled()\"\r\n [attr.aria-label]=\"prevButtonLabel\"\r\n (click)=\"previousClicked()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043B\u0435\u0432\u043E\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background: new 0 0 250.738 250.738\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n style=\"fill-rule: evenodd; clip-rule: evenodd\"\r\n d=\"M96.633,125.369l95.053-94.533c7.101-7.055,7.101-18.492,0-25.546 c-7.1-7.054-18.613-7.054-25.714,0L58.989,111.689c-3.784,3.759-5.487,8.759-5.238,13.68c-0.249,4.922,1.454,9.921,5.238,13.681 l106.983,106.398c7.101,7.055,18.613,7.055,25.714,0c7.101-7.054,7.101-18.491,0-25.544L96.633,125.369z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </button>\r\n <div class=\"owl-dt-calendar-control-content\">\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-period-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [attr.aria-label]=\"periodButtonLabel\"\r\n (click)=\"toggleViews()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n {{ periodButtonText }}\r\n\r\n <span\r\n class=\"owl-dt-control-button-arrow\"\r\n [style.transform]=\"\r\n 'rotate(' + (isMonthView ? 0 : 180) + 'deg)'\r\n \"\r\n >\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430\"> -->\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n width=\"50%\"\r\n height=\"50%\"\r\n viewBox=\"0 0 292.362 292.362\"\r\n style=\"enable-background: new 0 0 292.362 292.362\"\r\n xml:space=\"preserve\"\r\n >\r\n <g>\r\n <path\r\n d=\"M286.935,69.377c-3.614-3.617-7.898-5.424-12.848-5.424H18.274c-4.952,0-9.233,1.807-12.85,5.424\r\n C1.807,72.998,0,77.279,0,82.228c0,4.948,1.807,9.229,5.424,12.847l127.907,127.907c3.621,3.617,7.902,5.428,12.85,5.428\r\n s9.233-1.811,12.847-5.428L286.935,95.074c3.613-3.617,5.427-7.898,5.427-12.847C292.362,77.279,290.548,72.998,286.935,69.377z\"\r\n />\r\n </g>\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </span>\r\n </button>\r\n </div>\r\n <button\r\n class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"0\"\r\n [style.visibility]=\"showControlArrows ? 'visible' : 'hidden'\"\r\n [disabled]=\"!nextButtonEnabled()\"\r\n [attr.aria-label]=\"nextButtonLabel\"\r\n (click)=\"nextClicked()\"\r\n >\r\n <span\r\n class=\"owl-dt-control-content owl-dt-control-button-content\"\r\n tabindex=\"-1\"\r\n >\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043F\u0440\u0430\u0432\u043E\"> -->\r\n <svg\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 250.738 250.738\"\r\n style=\"enable-background: new 0 0 250.738 250.738\"\r\n xml:space=\"preserve\"\r\n >\r\n <path\r\n style=\"fill-rule: evenodd; clip-rule: evenodd\"\r\n d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\r\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\r\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\r\n C197.237,120.447,195.534,115.448,191.75,111.689z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n </button>\r\n</div>\r\n<div class=\"owl-dt-calendar-main\" cdkMonitorSubtreeFocus tabindex=\"-1\">\r\n @switch (currentView) {\r\n @case (DateView.MONTH) {\r\n <owl-date-time-month-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [firstDayOfWeek]=\"firstDayOfWeek\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [showCalendarWeeks]=\"showCalendarWeeks\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n [hideOtherMonths]=\"hideOtherMonths\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (selectedChange)=\"dateSelected($event)\"\r\n (userSelection)=\"userSelected()\"\r\n ></owl-date-time-month-view>\r\n }\r\n @case (DateView.YEAR) {\r\n <owl-date-time-year-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n (keyboardEnter)=\"focusActiveCell()\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (monthSelected)=\"selectMonthInYearView($event)\"\r\n (change)=\"goToDateInView($event, DateView.MONTH)\"\r\n ></owl-date-time-year-view>\r\n }\r\n @case (DateView.MULTI_YEARS) {\r\n <owl-date-time-multi-year-view\r\n [pickerDateTime]=\"pickerDateTime\"\r\n [selected]=\"selected\"\r\n [selecteds]=\"selecteds\"\r\n [selectMode]=\"selectMode\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [dateFilter]=\"dateFilter\"\r\n (keyboardEnter)=\"focusActiveCell()\"\r\n (pickerDateTimeChange)=\"handlePickerDateTimeChange($event)\"\r\n (yearSelected)=\"selectYearInMultiYearView($event)\"\r\n (change)=\"goToDateInView($event, DateView.YEAR)\"\r\n ></owl-date-time-multi-year-view>\r\n }\r\n }\r\n</div>\r\n" }]
2138
2173
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: OwlDateTimeIntl }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: DateTimeAdapter, decorators: [{
2139
2174
  type: Optional
2140
2175
  }] }, { type: undefined, decorators: [{
@@ -2187,12 +2222,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
2187
2222
  */
2188
2223
  class OwlTimerBoxComponent {
2189
2224
  get displayValue() {
2190
- if (this.hasFocus) {
2191
- // Don't try to reformat the value that user is currently editing
2225
+ if (this.isEditing) {
2226
+ // Не переформатируем значение, пока пользователь его редактирует
2192
2227
  return this.valueInput.nativeElement.value;
2193
2228
  }
2194
- const value = this.boxValue || this.value;
2195
- if (value === null || isNaN(value)) {
2229
+ const value = this.boxValue ?? this.value;
2230
+ if (value == null || isNaN(value)) {
2196
2231
  return '';
2197
2232
  }
2198
2233
  return value < 10 ? '0' + value.toString() : value.toString();
@@ -2200,14 +2235,15 @@ class OwlTimerBoxComponent {
2200
2235
  get owlDTTimerBoxClass() {
2201
2236
  return true;
2202
2237
  }
2203
- constructor() {
2238
+ constructor(changeDetector) {
2239
+ this.changeDetector = changeDetector;
2204
2240
  this.showDivider = false;
2205
2241
  this.step = 1;
2206
2242
  this.valueChange = new EventEmitter();
2207
2243
  this.inputChange = new EventEmitter();
2208
2244
  this.inputStream = new Subject();
2209
2245
  this.inputStreamSub = Subscription.EMPTY;
2210
- this.hasFocus = false;
2246
+ this.isEditing = false;
2211
2247
  this.onValueInputMouseWheelBind = this.onValueInputMouseWheel.bind(this);
2212
2248
  }
2213
2249
  ngOnInit() {
@@ -2230,19 +2266,26 @@ class OwlTimerBoxComponent {
2230
2266
  this.updateValue(this.value - this.step);
2231
2267
  }
2232
2268
  handleInputChange(val) {
2269
+ this.isEditing = true;
2233
2270
  this.inputStream.next(val);
2234
2271
  }
2235
2272
  focusIn() {
2236
- this.hasFocus = true;
2273
+ this.isEditing = true;
2237
2274
  }
2238
2275
  focusOut(value) {
2239
- this.hasFocus = false;
2240
- if (value) {
2276
+ const wasEditing = this.isEditing;
2277
+ this.isEditing = false;
2278
+ // Отменяем ожидающий debounce: blur сразу фиксирует текущий текст
2279
+ this.inputStream.next('');
2280
+ if (wasEditing && value) {
2241
2281
  const inputValue = coerceNumberProperty(value, 0);
2242
2282
  this.updateValueViaInput(inputValue);
2243
2283
  }
2244
2284
  }
2245
2285
  updateValue(value) {
2286
+ // Шаг заменяет введённый текст; отложенный input и blur не должны откатывать значение
2287
+ this.isEditing = false;
2288
+ this.inputStream.next('');
2246
2289
  this.valueChange.emit(value);
2247
2290
  }
2248
2291
  updateValueViaInput(value) {
@@ -2253,7 +2296,7 @@ class OwlTimerBoxComponent {
2253
2296
  }
2254
2297
  onValueInputMouseWheel(event) {
2255
2298
  event = event || window.event;
2256
- const delta = event.wheelDelta || -event.deltaY || -event.detail;
2299
+ const delta = event.deltaY != null ? -event.deltaY : event.wheelDelta || -event.detail;
2257
2300
  if (delta > 0) {
2258
2301
  if (!this.upBtnDisabled) {
2259
2302
  this.upBtnClicked();
@@ -2264,23 +2307,24 @@ class OwlTimerBoxComponent {
2264
2307
  this.downBtnClicked();
2265
2308
  }
2266
2309
  }
2310
+ this.changeDetector.markForCheck();
2267
2311
  event.preventDefault ? event.preventDefault() : (event.returnValue = false);
2268
2312
  }
2269
2313
  bindValueInputMouseWheel() {
2270
- this.valueInput.nativeElement.addEventListener('onwheel' in document ? 'wheel' : 'mousewheel', this.onValueInputMouseWheelBind);
2314
+ this.valueInput.nativeElement.addEventListener('onwheel' in this.valueInput.nativeElement.ownerDocument ? 'wheel' : 'mousewheel', this.onValueInputMouseWheelBind);
2271
2315
  }
2272
2316
  unbindValueInputMouseWheel() {
2273
- this.valueInput.nativeElement.removeEventListener('onwheel' in document ? 'wheel' : 'mousewheel', this.onValueInputMouseWheelBind);
2317
+ this.valueInput.nativeElement.removeEventListener('onwheel' in this.valueInput.nativeElement.ownerDocument ? 'wheel' : 'mousewheel', this.onValueInputMouseWheelBind);
2274
2318
  }
2275
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlTimerBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2276
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: OwlTimerBoxComponent, isStandalone: false, selector: "owl-date-time-timer-box", inputs: { showDivider: "showDivider", upBtnAriaLabel: "upBtnAriaLabel", upBtnDisabled: "upBtnDisabled", downBtnAriaLabel: "downBtnAriaLabel", downBtnDisabled: "downBtnDisabled", boxValue: "boxValue", value: "value", min: "min", max: "max", step: "step", inputLabel: "inputLabel" }, outputs: { valueChange: "valueChange", inputChange: "inputChange" }, host: { properties: { "class.owl-dt-timer-box": "owlDTTimerBoxClass" } }, viewQueries: [{ propertyName: "valueInput", first: true, predicate: ["valueInput"], descendants: true, static: true }], exportAs: ["owlDateTimeTimerBox"], ngImport: i0, template: "@if (showDivider) {\r\n <div class=\"owl-dt-timer-divider\" aria-hidden=\"true\"></div>\r\n}\r\n<button\r\n class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n [disabled]=\"upBtnDisabled\"\r\n [attr.aria-label]=\"upBtnAriaLabel\"\r\n (click)=\"upBtnClicked()\"\r\n>\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG Arrow Up\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 451.847 451.846\"\r\n style=\"enable-background: new 0 0 451.847 451.846\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n d=\"M248.292,106.406l194.281,194.29c12.365,12.359,12.365,32.391,0,44.744c-12.354,12.354-32.391,12.354-44.744,0\r\n L225.923,173.529L54.018,345.44c-12.36,12.354-32.395,12.354-44.748,0c-12.359-12.354-12.359-32.391,0-44.75L203.554,106.4\r\n c6.18-6.174,14.271-9.259,22.369-9.259C234.018,97.141,242.115,100.232,248.292,106.406z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n<label class=\"owl-dt-timer-content\">\r\n <input\r\n class=\"owl-dt-timer-input\"\r\n maxlength=\"2\"\r\n [value]=\"displayValue\"\r\n (keydown.arrowup)=\"!upBtnDisabled && upBtnClicked()\"\r\n (keydown.arrowdown)=\"!downBtnDisabled && downBtnClicked()\"\r\n (input)=\"handleInputChange(valueInput.value)\"\r\n (focusin)=\"focusIn()\"\r\n (focusout)=\"focusOut(valueInput.value)\"\r\n #valueInput\r\n />\r\n <span class=\"owl-hidden-accessible\">{{ inputLabel }}</span>\r\n</label>\r\n<button\r\n class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n [disabled]=\"downBtnDisabled\"\r\n [attr.aria-label]=\"downBtnAriaLabel\"\r\n (click)=\"downBtnClicked()\"\r\n>\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG Arrow Down\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 451.847 451.846\"\r\n style=\"enable-background: new 0 0 451.847 451.846\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n d=\"M225.923,354.706c-8.098,0-16.195-3.092-22.369-9.263L9.27,151.157c-12.359-12.359-12.359-32.397,0-44.751\r\n c12.354-12.354,32.388-12.354,44.748,0l171.905,171.915l171.906-171.909c12.359-12.354,32.391-12.354,44.744,0\r\n c12.365,12.354,12.365,32.392,0,44.751L248.292,345.449C242.115,351.621,234.018,354.706,225.923,354.706z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2319
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlTimerBoxComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2320
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: OwlTimerBoxComponent, isStandalone: false, selector: "owl-date-time-timer-box", inputs: { showDivider: "showDivider", upBtnAriaLabel: "upBtnAriaLabel", upBtnDisabled: "upBtnDisabled", downBtnAriaLabel: "downBtnAriaLabel", downBtnDisabled: "downBtnDisabled", boxValue: "boxValue", value: "value", min: "min", max: "max", step: "step", inputLabel: "inputLabel" }, outputs: { valueChange: "valueChange", inputChange: "inputChange" }, host: { properties: { "class.owl-dt-timer-box": "owlDTTimerBoxClass" } }, viewQueries: [{ propertyName: "valueInput", first: true, predicate: ["valueInput"], descendants: true, static: true }], exportAs: ["owlDateTimeTimerBox"], ngImport: i0, template: "@if (showDivider) {\r\n <div class=\"owl-dt-timer-divider\" aria-hidden=\"true\"></div>\r\n}\r\n<button\r\n class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n [disabled]=\"upBtnDisabled\"\r\n [attr.aria-label]=\"upBtnAriaLabel\"\r\n (click)=\"upBtnClicked()\"\r\n>\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u0432\u0435\u0440\u0445\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 451.847 451.846\"\r\n style=\"enable-background: new 0 0 451.847 451.846\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n d=\"M248.292,106.406l194.281,194.29c12.365,12.359,12.365,32.391,0,44.744c-12.354,12.354-32.391,12.354-44.744,0\r\n L225.923,173.529L54.018,345.44c-12.36,12.354-32.395,12.354-44.748,0c-12.359-12.354-12.359-32.391,0-44.75L203.554,106.4\r\n c6.18-6.174,14.271-9.259,22.369-9.259C234.018,97.141,242.115,100.232,248.292,106.406z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n<label class=\"owl-dt-timer-content\">\r\n <input\r\n class=\"owl-dt-timer-input\"\r\n maxlength=\"2\"\r\n [value]=\"displayValue\"\r\n (keydown.arrowup)=\"!upBtnDisabled && upBtnClicked()\"\r\n (keydown.arrowdown)=\"!downBtnDisabled && downBtnClicked()\"\r\n (input)=\"handleInputChange(valueInput.value)\"\r\n (focusin)=\"focusIn()\"\r\n (focusout)=\"focusOut(valueInput.value)\"\r\n #valueInput\r\n />\r\n <span class=\"owl-hidden-accessible\">{{ inputLabel }}</span>\r\n</label>\r\n<button\r\n class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n [disabled]=\"downBtnDisabled\"\r\n [attr.aria-label]=\"downBtnAriaLabel\"\r\n (click)=\"downBtnClicked()\"\r\n>\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043D\u0438\u0437\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 451.847 451.846\"\r\n style=\"enable-background: new 0 0 451.847 451.846\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n d=\"M225.923,354.706c-8.098,0-16.195-3.092-22.369-9.263L9.27,151.157c-12.359-12.359-12.359-32.397,0-44.751\r\n c12.354-12.354,32.388-12.354,44.748,0l171.905,171.915l171.906-171.909c12.359-12.354,32.391-12.354,44.744,0\r\n c12.365,12.354,12.365,32.392,0,44.751L248.292,345.449C242.115,351.621,234.018,354.706,225.923,354.706z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2277
2321
  }
2278
2322
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlTimerBoxComponent, decorators: [{
2279
2323
  type: Component,
2280
2324
  args: [{ exportAs: 'owlDateTimeTimerBox', selector: 'owl-date-time-timer-box', standalone: false, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, host: {
2281
2325
  '[class.owl-dt-timer-box]': 'owlDTTimerBoxClass'
2282
- }, template: "@if (showDivider) {\r\n <div class=\"owl-dt-timer-divider\" aria-hidden=\"true\"></div>\r\n}\r\n<button\r\n class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n [disabled]=\"upBtnDisabled\"\r\n [attr.aria-label]=\"upBtnAriaLabel\"\r\n (click)=\"upBtnClicked()\"\r\n>\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG Arrow Up\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 451.847 451.846\"\r\n style=\"enable-background: new 0 0 451.847 451.846\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n d=\"M248.292,106.406l194.281,194.29c12.365,12.359,12.365,32.391,0,44.744c-12.354,12.354-32.391,12.354-44.744,0\r\n L225.923,173.529L54.018,345.44c-12.36,12.354-32.395,12.354-44.748,0c-12.359-12.354-12.359-32.391,0-44.75L203.554,106.4\r\n c6.18-6.174,14.271-9.259,22.369-9.259C234.018,97.141,242.115,100.232,248.292,106.406z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n<label class=\"owl-dt-timer-content\">\r\n <input\r\n class=\"owl-dt-timer-input\"\r\n maxlength=\"2\"\r\n [value]=\"displayValue\"\r\n (keydown.arrowup)=\"!upBtnDisabled && upBtnClicked()\"\r\n (keydown.arrowdown)=\"!downBtnDisabled && downBtnClicked()\"\r\n (input)=\"handleInputChange(valueInput.value)\"\r\n (focusin)=\"focusIn()\"\r\n (focusout)=\"focusOut(valueInput.value)\"\r\n #valueInput\r\n />\r\n <span class=\"owl-hidden-accessible\">{{ inputLabel }}</span>\r\n</label>\r\n<button\r\n class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n [disabled]=\"downBtnDisabled\"\r\n [attr.aria-label]=\"downBtnAriaLabel\"\r\n (click)=\"downBtnClicked()\"\r\n>\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG Arrow Down\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 451.847 451.846\"\r\n style=\"enable-background: new 0 0 451.847 451.846\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n d=\"M225.923,354.706c-8.098,0-16.195-3.092-22.369-9.263L9.27,151.157c-12.359-12.359-12.359-32.397,0-44.751\r\n c12.354-12.354,32.388-12.354,44.748,0l171.905,171.915l171.906-171.909c12.359-12.354,32.391-12.354,44.744,0\r\n c12.365,12.354,12.365,32.392,0,44.751L248.292,345.449C242.115,351.621,234.018,354.706,225.923,354.706z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n" }]
2283
- }], ctorParameters: () => [], propDecorators: { showDivider: [{
2326
+ }, template: "@if (showDivider) {\r\n <div class=\"owl-dt-timer-divider\" aria-hidden=\"true\"></div>\r\n}\r\n<button\r\n class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n [disabled]=\"upBtnDisabled\"\r\n [attr.aria-label]=\"upBtnAriaLabel\"\r\n (click)=\"upBtnClicked()\"\r\n>\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u0432\u0435\u0440\u0445\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 451.847 451.846\"\r\n style=\"enable-background: new 0 0 451.847 451.846\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n d=\"M248.292,106.406l194.281,194.29c12.365,12.359,12.365,32.391,0,44.744c-12.354,12.354-32.391,12.354-44.744,0\r\n L225.923,173.529L54.018,345.44c-12.36,12.354-32.395,12.354-44.748,0c-12.359-12.354-12.359-32.391,0-44.75L203.554,106.4\r\n c6.18-6.174,14.271-9.259,22.369-9.259C234.018,97.141,242.115,100.232,248.292,106.406z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n<label class=\"owl-dt-timer-content\">\r\n <input\r\n class=\"owl-dt-timer-input\"\r\n maxlength=\"2\"\r\n [value]=\"displayValue\"\r\n (keydown.arrowup)=\"!upBtnDisabled && upBtnClicked()\"\r\n (keydown.arrowdown)=\"!downBtnDisabled && downBtnClicked()\"\r\n (input)=\"handleInputChange(valueInput.value)\"\r\n (focusin)=\"focusIn()\"\r\n (focusout)=\"focusOut(valueInput.value)\"\r\n #valueInput\r\n />\r\n <span class=\"owl-hidden-accessible\">{{ inputLabel }}</span>\r\n</label>\r\n<button\r\n class=\"owl-dt-control-button owl-dt-control-arrow-button\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n [disabled]=\"downBtnDisabled\"\r\n [attr.aria-label]=\"downBtnAriaLabel\"\r\n (click)=\"downBtnClicked()\"\r\n>\r\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\r\n <!-- <editor-fold desc=\"SVG-\u0441\u0442\u0440\u0435\u043B\u043A\u0430 \u0432\u043D\u0438\u0437\"> -->\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n version=\"1.1\"\r\n x=\"0px\"\r\n y=\"0px\"\r\n viewBox=\"0 0 451.847 451.846\"\r\n style=\"enable-background: new 0 0 451.847 451.846\"\r\n xml:space=\"preserve\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <path\r\n d=\"M225.923,354.706c-8.098,0-16.195-3.092-22.369-9.263L9.27,151.157c-12.359-12.359-12.359-32.397,0-44.751\r\n c12.354-12.354,32.388-12.354,44.748,0l171.905,171.915l171.906-171.909c12.359-12.354,32.391-12.354,44.744,0\r\n c12.365,12.354,12.365,32.392,0,44.751L248.292,345.449C242.115,351.621,234.018,354.706,225.923,354.706z\"\r\n />\r\n </svg>\r\n <!-- </editor-fold> -->\r\n </span>\r\n</button>\r\n" }]
2327
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { showDivider: [{
2284
2328
  type: Input
2285
2329
  }], upBtnAriaLabel: [{
2286
2330
  type: Input
@@ -2321,7 +2365,7 @@ class OwlTimerComponent {
2321
2365
  set pickerDateTime(value) {
2322
2366
  value = this.dateTimeAdapter.deserialize(value);
2323
2367
  this._pickerDateTime =
2324
- this.getValidDate(value) || this.dateTimeAdapter.now();
2368
+ this.getValidDate(value) ?? this.dateTimeAdapter.now();
2325
2369
  }
2326
2370
  get minDateTime() {
2327
2371
  return this._minDateTime;
@@ -2341,9 +2385,9 @@ class OwlTimerComponent {
2341
2385
  return this.dateTimeAdapter.getHours(this.pickerDateTime);
2342
2386
  }
2343
2387
  /**
2344
- * The value would be displayed in hourBox.
2345
- * We need this because the value displayed in hourBox it not
2346
- * the same as the hourValue when the timer is in hour12Timer mode.
2388
+ * Значение, отображаемое в hourBox
2389
+ * Оно требуется, поскольку значение в hourBox отличается
2390
+ * от hourValue в режиме hour12Timer
2347
2391
  * */
2348
2392
  get hourBoxValue() {
2349
2393
  let hours = this.hourValue;
@@ -2409,38 +2453,47 @@ class OwlTimerComponent {
2409
2453
  this.pickerIntl = pickerIntl;
2410
2454
  this.cdRef = cdRef;
2411
2455
  this.dateTimeAdapter = dateTimeAdapter;
2412
- this.isPM = false; // Whether the current time is PM in 12-hour mode.
2456
+ this.injector = inject(Injector);
2457
+ this.destroyRef = inject(DestroyRef);
2458
+ this.intlChangesSub = Subscription.EMPTY;
2459
+ this.isPM = false; // Относится ли текущее время к PM в 12-часовом формате
2413
2460
  /**
2414
- * Hours to change per step
2461
+ * Количество часов за один шаг
2415
2462
  */
2416
2463
  this.stepHour = 1;
2417
2464
  /**
2418
- * Minutes to change per step
2465
+ * Количество минут за один шаг
2419
2466
  */
2420
2467
  this.stepMinute = 1;
2421
2468
  /**
2422
- * Seconds to change per step
2469
+ * Количество секунд за один шаг
2423
2470
  */
2424
2471
  this.stepSecond = 1;
2425
2472
  this.selectedChange = new EventEmitter();
2473
+ this.intlChangesSub = this.pickerIntl.changes.subscribe(() => this.cdRef.markForCheck());
2426
2474
  }
2427
2475
  ngOnInit() { }
2476
+ ngOnDestroy() {
2477
+ this.intlChangesSub.unsubscribe();
2478
+ }
2428
2479
  /**
2429
- * Focus to the host element
2480
+ * Переводит фокус на элемент компонента
2430
2481
  * */
2431
2482
  focus() {
2432
- this.ngZone.runOutsideAngular(() => {
2433
- this.ngZone.onStable
2434
- .asObservable()
2435
- .pipe(take(1))
2436
- .subscribe(() => {
2483
+ if (this.destroyRef.destroyed) {
2484
+ return;
2485
+ }
2486
+ this.focusRef?.destroy();
2487
+ this.focusRef = afterNextRender({
2488
+ write: () => {
2489
+ this.focusRef = undefined;
2437
2490
  this.elmRef.nativeElement.focus();
2438
- });
2439
- });
2491
+ }
2492
+ }, { injector: this.injector });
2440
2493
  }
2441
2494
  /**
2442
- * Set the hour value via typing into timer box input
2443
- * We need this to handle the hour value when the timer is in hour12 mode
2495
+ * Задаёт час при вводе текста в поле времени
2496
+ * Нужно для обработки часа в 12-часовом формате времени
2444
2497
  * */
2445
2498
  setHourValueViaInput(hours) {
2446
2499
  if (this.hour12Timer && this.isPM && hours >= 1 && hours <= 11) {
@@ -2482,52 +2535,52 @@ class OwlTimerComponent {
2482
2535
  event.preventDefault();
2483
2536
  }
2484
2537
  /**
2485
- * Check if the up hour button is enabled
2538
+ * Проверяет доступность кнопки увеличения часов
2486
2539
  */
2487
2540
  upHourEnabled() {
2488
- return (!this.maxDateTime ||
2541
+ return (this.maxDateTime == null ||
2489
2542
  this.compareHours(this.stepHour, this.maxDateTime) < 1);
2490
2543
  }
2491
2544
  /**
2492
- * Check if the down hour button is enabled
2545
+ * Проверяет доступность кнопки уменьшения часов
2493
2546
  */
2494
2547
  downHourEnabled() {
2495
- return (!this.minDateTime ||
2548
+ return (this.minDateTime == null ||
2496
2549
  this.compareHours(-this.stepHour, this.minDateTime) > -1);
2497
2550
  }
2498
2551
  /**
2499
- * Check if the up minute button is enabled
2552
+ * Проверяет доступность кнопки увеличения минут
2500
2553
  */
2501
2554
  upMinuteEnabled() {
2502
- return (!this.maxDateTime ||
2555
+ return (this.maxDateTime == null ||
2503
2556
  this.compareMinutes(this.stepMinute, this.maxDateTime) < 1);
2504
2557
  }
2505
2558
  /**
2506
- * Check if the down minute button is enabled
2559
+ * Проверяет доступность кнопки уменьшения минут
2507
2560
  */
2508
2561
  downMinuteEnabled() {
2509
- return (!this.minDateTime ||
2562
+ return (this.minDateTime == null ||
2510
2563
  this.compareMinutes(-this.stepMinute, this.minDateTime) > -1);
2511
2564
  }
2512
2565
  /**
2513
- * Check if the up second button is enabled
2566
+ * Проверяет доступность кнопки увеличения секунд
2514
2567
  */
2515
2568
  upSecondEnabled() {
2516
- return (!this.maxDateTime ||
2569
+ return (this.maxDateTime == null ||
2517
2570
  this.compareSeconds(this.stepSecond, this.maxDateTime) < 1);
2518
2571
  }
2519
2572
  /**
2520
- * Check if the down second button is enabled
2573
+ * Проверяет доступность кнопки уменьшения секунд
2521
2574
  */
2522
2575
  downSecondEnabled() {
2523
- return (!this.minDateTime ||
2576
+ return (this.minDateTime == null ||
2524
2577
  this.compareSeconds(-this.stepSecond, this.minDateTime) > -1);
2525
2578
  }
2526
2579
  /**
2527
- * Adjust the displayed hour and compare it to the given date.
2528
- * 1 is after the comparedDate
2529
- * -1 is before the comparedDate
2530
- * 0 is equal the comparedDate
2580
+ * Изменяет отображаемый час и сравнивает результат с указанной датой
2581
+ * 1 — позже comparedDate
2582
+ * -1 — раньше comparedDate
2583
+ * 0 — совпадает с comparedDate
2531
2584
  * */
2532
2585
  compareHours(amount, comparedDate) {
2533
2586
  const hours = this.dateTimeAdapter.getHours(this.pickerDateTime) + amount;
@@ -2535,10 +2588,10 @@ class OwlTimerComponent {
2535
2588
  return this.dateTimeAdapter.compare(result, comparedDate);
2536
2589
  }
2537
2590
  /**
2538
- * Adjust the displayed minute and compare it to the given date.
2539
- * 1 is after the comparedDate
2540
- * -1 is before the comparedDate
2541
- * 0 is equal the comparedDate
2591
+ * Изменяет отображаемую минуту и сравнивает результат с указанной датой
2592
+ * 1 — позже comparedDate
2593
+ * -1 — раньше comparedDate
2594
+ * 0 — совпадает с comparedDate
2542
2595
  * */
2543
2596
  compareMinutes(amount, comparedDate) {
2544
2597
  const minutes = this.dateTimeAdapter.getMinutes(this.pickerDateTime) + amount;
@@ -2546,10 +2599,10 @@ class OwlTimerComponent {
2546
2599
  return this.dateTimeAdapter.compare(result, comparedDate);
2547
2600
  }
2548
2601
  /**
2549
- * Adjust the displayed second and compare it to the given date.
2550
- * 1 is after the comparedDate
2551
- * -1 is before the comparedDate
2552
- * 0 is equal the comparedDate
2602
+ * Изменяет отображаемую секунду и сравнивает результат с указанной датой
2603
+ * 1 — позже comparedDate
2604
+ * -1 — раньше comparedDate
2605
+ * 0 — совпадает с comparedDate
2553
2606
  * */
2554
2607
  compareSeconds(amount, comparedDate) {
2555
2608
  const seconds = this.dateTimeAdapter.getSeconds(this.pickerDateTime) + amount;
@@ -2557,7 +2610,7 @@ class OwlTimerComponent {
2557
2610
  return this.dateTimeAdapter.compare(result, comparedDate);
2558
2611
  }
2559
2612
  /**
2560
- * Get a valid date object
2613
+ * Возвращает корректный объект даты
2561
2614
  */
2562
2615
  getValidDate(obj) {
2563
2616
  return this.dateTimeAdapter.isDateInstance(obj) &&
@@ -2616,7 +2669,7 @@ class OwlDateTimeContainerComponent {
2616
2669
  return this._clampedPickerDateTime;
2617
2670
  }
2618
2671
  set pickerDateTime(value) {
2619
- if (value) {
2672
+ if (value != null) {
2620
2673
  this._clampedPickerDateTime = this.dateTimeAdapter.clampDate(value, this.picker.minDateTime, this.picker.maxDateTime);
2621
2674
  }
2622
2675
  this.cdRef.markForCheck();
@@ -2631,39 +2684,39 @@ class OwlDateTimeContainerComponent {
2631
2684
  return this.pickerIntl.setBtnLabel;
2632
2685
  }
2633
2686
  /**
2634
- * The range 'from' label
2687
+ * Подпись начала диапазона ('from')
2635
2688
  * */
2636
2689
  get fromLabel() {
2637
2690
  return this.pickerIntl.rangeFromLabel;
2638
2691
  }
2639
2692
  /**
2640
- * The range 'to' label
2693
+ * Подпись конца диапазона ('to')
2641
2694
  * */
2642
2695
  get toLabel() {
2643
2696
  return this.pickerIntl.rangeToLabel;
2644
2697
  }
2645
2698
  /**
2646
- * The range 'from' formatted value
2699
+ * Отформатированное значение начала диапазона ('from')
2647
2700
  * */
2648
2701
  get fromFormattedValue() {
2649
2702
  const value = this.picker.selecteds[0];
2650
- return value
2703
+ return value != null
2651
2704
  ? this.dateTimeAdapter.format(value, this.picker.formatString)
2652
2705
  : '';
2653
2706
  }
2654
2707
  /**
2655
- * The range 'to' formatted value
2708
+ * Отформатированное значение конца диапазона ('to')
2656
2709
  * */
2657
2710
  get toFormattedValue() {
2658
2711
  const value = this.picker.selecteds[1];
2659
- return value
2712
+ return value != null
2660
2713
  ? this.dateTimeAdapter.format(value, this.picker.formatString)
2661
2714
  : '';
2662
2715
  }
2663
2716
  /**
2664
- * Cases in which the control buttons show in the picker
2665
- * 1) picker mode is 'dialog'
2666
- * 2) picker type is NOT 'calendar' and the picker mode is NOT 'inline'
2717
+ * Условия отображения кнопок управления:
2718
+ * 1) Режим компонента — 'dialog'
2719
+ * 2) Тип компонента отличается от 'calendar', а режим — от 'inline'
2667
2720
  * */
2668
2721
  get showControlButtons() {
2669
2722
  return (this.picker.pickerMode === 'dialog' ||
@@ -2699,26 +2752,30 @@ class OwlDateTimeContainerComponent {
2699
2752
  this.elmRef = elmRef;
2700
2753
  this.pickerIntl = pickerIntl;
2701
2754
  this.dateTimeAdapter = dateTimeAdapter;
2702
- this.activeSelectedIndex = 0; // The current active SelectedIndex in range select mode (0: 'from', 1: 'to')
2703
- /** Emits when an animation state changes. */
2755
+ this.activeSelectedIndex = 0; // Индекс активной границы диапазона (0: 'from', 1: 'to')
2756
+ /** Событие изменения состояния анимации */
2704
2757
  this.animationStateChanged = new EventEmitter();
2705
2758
  /**
2706
- * Stream emits when try to hide picker
2759
+ * Поток запросов на закрытие компонента выбора
2707
2760
  * */
2708
2761
  this.hidePicker$ = new Subject();
2709
2762
  /**
2710
- * Stream emits when try to confirm the selected value
2763
+ * Поток запросов на подтверждение выбранного значения
2711
2764
  * */
2712
2765
  this.confirmSelected$ = new Subject();
2713
2766
  this.beforePickerOpened$ = new Subject();
2714
2767
  this.pickerOpened$ = new Subject();
2768
+ this.pickerIntl.changes.pipe(takeUntilDestroyed()).subscribe(() => this.cdRef.markForCheck());
2769
+ }
2770
+ refreshView() {
2771
+ this.cdRef.markForCheck();
2715
2772
  }
2716
2773
  ngOnInit() {
2717
2774
  if (this.picker.selectMode === 'range') {
2718
- if (this.picker.selecteds[0]) {
2775
+ if (this.picker.selecteds[0] != null) {
2719
2776
  this.retainStartTime = this.dateTimeAdapter.clone(this.picker.selecteds[0]);
2720
2777
  }
2721
- if (this.picker.selecteds[1]) {
2778
+ if (this.picker.selecteds[1] != null) {
2722
2779
  this.retainEndTime = this.dateTimeAdapter.clone(this.picker.selecteds[1]);
2723
2780
  }
2724
2781
  }
@@ -2748,15 +2805,18 @@ class OwlDateTimeContainerComponent {
2748
2805
  });
2749
2806
  }
2750
2807
  dateSelected(date) {
2808
+ if (this.picker.disabled) {
2809
+ return;
2810
+ }
2751
2811
  let result;
2752
2812
  if (this.picker.isInSingleMode) {
2753
2813
  result = this.dateSelectedInSingleMode(date);
2754
- if (result) {
2814
+ if (result != null) {
2755
2815
  this.pickerDateTime = result;
2756
2816
  this.picker.select(result);
2757
2817
  }
2758
2818
  else {
2759
- // we close the picker when result is null and pickerType is calendar.
2819
+ // Закрываем компонент выбора, если result равен null и pickerType равен 'calendar'
2760
2820
  if (this.pickerType === 'calendar') {
2761
2821
  this.hidePicker$.next(null);
2762
2822
  }
@@ -2765,13 +2825,16 @@ class OwlDateTimeContainerComponent {
2765
2825
  }
2766
2826
  if (this.picker.isInRangeMode) {
2767
2827
  result = this.dateSelectedInRangeMode(date);
2768
- if (result) {
2828
+ if (result != null) {
2769
2829
  this.pickerDateTime = result[this.activeSelectedIndex];
2770
2830
  this.picker.select(result);
2771
2831
  }
2772
2832
  }
2773
2833
  }
2774
2834
  timeSelected(time) {
2835
+ if (this.picker.disabled) {
2836
+ return;
2837
+ }
2775
2838
  this.pickerDateTime = this.dateTimeAdapter.clone(time);
2776
2839
  if (!this.picker.dateTimeChecker(this.pickerDateTime)) {
2777
2840
  return;
@@ -2782,13 +2845,13 @@ class OwlDateTimeContainerComponent {
2782
2845
  }
2783
2846
  if (this.picker.isInRangeMode) {
2784
2847
  const selecteds = [...this.picker.selecteds];
2785
- // check if the 'from' is after 'to' or 'to'is before 'from'
2786
- // In this case, we set both the 'from' and 'to' the same value
2848
+ // Проверяем, находится ли начало диапазона после конца или конец перед началом
2849
+ // В этом случае задаём обеим границам диапазона одинаковое значение
2787
2850
  if ((this.activeSelectedIndex === 0 &&
2788
- selecteds[1] &&
2851
+ selecteds[1] != null &&
2789
2852
  this.dateTimeAdapter.compare(this.pickerDateTime, selecteds[1]) === 1) ||
2790
2853
  (this.activeSelectedIndex === 1 &&
2791
- selecteds[0] &&
2854
+ selecteds[0] != null &&
2792
2855
  this.dateTimeAdapter.compare(this.pickerDateTime, selecteds[0]) === -1)) {
2793
2856
  selecteds[0] = this.pickerDateTime;
2794
2857
  selecteds[1] = this.pickerDateTime;
@@ -2796,17 +2859,17 @@ class OwlDateTimeContainerComponent {
2796
2859
  else {
2797
2860
  selecteds[this.activeSelectedIndex] = this.pickerDateTime;
2798
2861
  }
2799
- if (selecteds[0]) {
2862
+ if (selecteds[0] != null) {
2800
2863
  this.retainStartTime = this.dateTimeAdapter.clone(selecteds[0]);
2801
2864
  }
2802
- if (selecteds[1]) {
2865
+ if (selecteds[1] != null) {
2803
2866
  this.retainEndTime = this.dateTimeAdapter.clone(selecteds[1]);
2804
2867
  }
2805
2868
  this.picker.select(selecteds);
2806
2869
  }
2807
2870
  }
2808
2871
  /**
2809
- * Handle click on cancel button
2872
+ * Обрабатывает нажатие кнопки отмены
2810
2873
  */
2811
2874
  onCancelClicked(event) {
2812
2875
  this.hidePicker$.next(null);
@@ -2814,9 +2877,13 @@ class OwlDateTimeContainerComponent {
2814
2877
  return;
2815
2878
  }
2816
2879
  /**
2817
- * Handle click on set button
2880
+ * Обрабатывает нажатие кнопки подтверждения
2818
2881
  */
2819
2882
  onSetClicked(event) {
2883
+ if (this.picker.disabled) {
2884
+ event.preventDefault();
2885
+ return;
2886
+ }
2820
2887
  if (!this.picker.dateTimeChecker(this.pickerDateTime)) {
2821
2888
  this.hidePicker$.next(null);
2822
2889
  event.preventDefault();
@@ -2827,7 +2894,7 @@ class OwlDateTimeContainerComponent {
2827
2894
  return;
2828
2895
  }
2829
2896
  /**
2830
- * Handle click on inform radio group
2897
+ * Обрабатывает выбор границы диапазона в группе переключателей
2831
2898
  */
2832
2899
  handleClickOnInfoGroup(event, index) {
2833
2900
  this.setActiveSelectedIndex(index);
@@ -2835,7 +2902,7 @@ class OwlDateTimeContainerComponent {
2835
2902
  event.stopPropagation();
2836
2903
  }
2837
2904
  /**
2838
- * Handle click on inform radio group
2905
+ * Обрабатывает выбор границы диапазона в группе переключателей
2839
2906
  */
2840
2907
  handleKeydownOnInfoGroup(event, next, index) {
2841
2908
  switch (event.keyCode) {
@@ -2873,10 +2940,11 @@ class OwlDateTimeContainerComponent {
2873
2940
  easing: 'cubic-bezier(0.25, 0.8, 0.25, 1)',
2874
2941
  fill: 'forwards'
2875
2942
  });
2876
- animation.finished.then(() => {
2943
+ const complete = () => {
2877
2944
  this.handleContainerAnimationDone('enter');
2878
2945
  event.animationComplete();
2879
- });
2946
+ };
2947
+ animation.finished.then(complete, complete);
2880
2948
  }
2881
2949
  }
2882
2950
  onAnimateLeave(event) {
@@ -2887,40 +2955,42 @@ class OwlDateTimeContainerComponent {
2887
2955
  event.animationComplete();
2888
2956
  }
2889
2957
  else {
2890
- event.target.animate([
2958
+ const animation = event.target.animate([
2891
2959
  { opacity: 1 },
2892
2960
  { opacity: 0 }
2893
2961
  ], {
2894
2962
  duration: duration ?? 100,
2895
2963
  easing: 'linear',
2896
2964
  fill: 'forwards'
2897
- }).finished.then(() => {
2965
+ });
2966
+ const complete = () => {
2898
2967
  this.handleContainerAnimationDone('leave');
2899
2968
  event.animationComplete();
2900
- });
2969
+ };
2970
+ animation.finished.then(complete, complete);
2901
2971
  }
2902
2972
  }
2903
2973
  /**
2904
- * Set the value of activeSelectedIndex
2974
+ * Задаёт значение activeSelectedIndex
2905
2975
  */
2906
2976
  setActiveSelectedIndex(index) {
2907
2977
  if (this.picker.selectMode === 'range' &&
2908
2978
  this.activeSelectedIndex !== index) {
2909
2979
  this.activeSelectedIndex = index;
2910
2980
  const selected = this.picker.selecteds[this.activeSelectedIndex];
2911
- if (this.picker.selecteds && selected) {
2981
+ if (this.picker.selecteds && selected != null) {
2912
2982
  this.pickerDateTime = this.dateTimeAdapter.clone(selected);
2913
2983
  }
2914
2984
  }
2915
2985
  return;
2916
2986
  }
2917
2987
  initPicker() {
2918
- this.pickerDateTime = this.picker.startAt || this.dateTimeAdapter.now();
2988
+ this.pickerDateTime = this.picker.startAt ?? this.dateTimeAdapter.now();
2919
2989
  this.activeSelectedIndex = this.picker.selectMode === 'rangeTo' ? 1 : 0;
2920
2990
  }
2921
2991
  /**
2922
- * Select calendar date in single mode,
2923
- * it returns null when date is not selected.
2992
+ * Выбирает дату календаря в режиме single
2993
+ * Возвращает null, если дата не выбрана
2924
2994
  */
2925
2995
  dateSelectedInSingleMode(date) {
2926
2996
  if (this.dateTimeAdapter.isSameDay(date, this.picker.selected)) {
@@ -2929,28 +2999,28 @@ class OwlDateTimeContainerComponent {
2929
2999
  return this.updateAndCheckCalendarDate(date);
2930
3000
  }
2931
3001
  /**
2932
- * Select dates in range Mode
3002
+ * Выбирает даты в режиме диапазона
2933
3003
  */
2934
3004
  dateSelectedInRangeMode(date) {
2935
3005
  let from = this.picker.selecteds[0];
2936
3006
  let to = this.picker.selecteds[1];
2937
3007
  const result = this.updateAndCheckCalendarDate(date);
2938
- if (!result) {
3008
+ if (result == null) {
2939
3009
  return null;
2940
3010
  }
2941
- // if the given calendar day is after or equal to 'from',
2942
- // set ths given date as 'to'
2943
- // otherwise, set it as 'from' and set 'to' to null
3011
+ // Если указанный день совпадает с началом диапазона или находится после него,
3012
+ // задаём его как конец диапазона ('to')
3013
+ // Иначе задаём его как начало диапазона ('from'), а конец ('to') сбрасываем в null
2944
3014
  if (this.picker.selectMode === 'range') {
2945
3015
  if (this.picker.selecteds &&
2946
3016
  this.picker.selecteds.length &&
2947
- !to &&
2948
- from &&
3017
+ to == null &&
3018
+ from != null &&
2949
3019
  this.dateTimeAdapter.differenceInCalendarDays(result, from) >= 0) {
2950
- if (this.picker.endAt && !this.retainEndTime) {
3020
+ if (this.picker.endAt != null && this.retainEndTime == null) {
2951
3021
  to = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(result), this.dateTimeAdapter.getMonth(result), this.dateTimeAdapter.getDate(result), this.dateTimeAdapter.getHours(this.picker.endAt), this.dateTimeAdapter.getMinutes(this.picker.endAt), this.dateTimeAdapter.getSeconds(this.picker.endAt));
2952
3022
  }
2953
- else if (this.retainEndTime) {
3023
+ else if (this.retainEndTime != null) {
2954
3024
  to = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(result), this.dateTimeAdapter.getMonth(result), this.dateTimeAdapter.getDate(result), this.dateTimeAdapter.getHours(this.retainEndTime), this.dateTimeAdapter.getMinutes(this.retainEndTime), this.dateTimeAdapter.getSeconds(this.retainEndTime));
2955
3025
  }
2956
3026
  else {
@@ -2959,10 +3029,10 @@ class OwlDateTimeContainerComponent {
2959
3029
  this.activeSelectedIndex = 1;
2960
3030
  }
2961
3031
  else {
2962
- if (this.picker.startAt && !this.retainStartTime) {
3032
+ if (this.picker.startAt != null && this.retainStartTime == null) {
2963
3033
  from = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(result), this.dateTimeAdapter.getMonth(result), this.dateTimeAdapter.getDate(result), this.dateTimeAdapter.getHours(this.picker.startAt), this.dateTimeAdapter.getMinutes(this.picker.startAt), this.dateTimeAdapter.getSeconds(this.picker.startAt));
2964
3034
  }
2965
- else if (this.retainStartTime) {
3035
+ else if (this.retainStartTime != null) {
2966
3036
  from = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(result), this.dateTimeAdapter.getMonth(result), this.dateTimeAdapter.getDate(result), this.dateTimeAdapter.getHours(this.retainStartTime), this.dateTimeAdapter.getMinutes(this.retainStartTime), this.dateTimeAdapter.getSeconds(this.retainStartTime));
2967
3037
  }
2968
3038
  else {
@@ -2974,30 +3044,41 @@ class OwlDateTimeContainerComponent {
2974
3044
  }
2975
3045
  else if (this.picker.selectMode === 'rangeFrom') {
2976
3046
  from = result;
2977
- // if the from value is after the to value, set the to value as null
2978
- if (to && this.dateTimeAdapter.compare(from, to) > 0) {
3047
+ // Если начало диапазона находится после конца, сбрасываем конец в null
3048
+ if (to != null && this.dateTimeAdapter.compare(from, to) > 0) {
2979
3049
  to = null;
2980
3050
  }
2981
3051
  }
2982
3052
  else if (this.picker.selectMode === 'rangeTo') {
2983
3053
  to = result;
2984
- // if the from value is after the to value, set the from value as null
2985
- if (from && this.dateTimeAdapter.compare(from, to) > 0) {
3054
+ // Если начало диапазона находится после конца, сбрасываем начало в null
3055
+ if (from != null && this.dateTimeAdapter.compare(from, to) > 0) {
2986
3056
  from = null;
2987
3057
  }
2988
3058
  }
3059
+ // Сохранённое время может выходить за min/max, даже если день доступен для выбора
3060
+ const selected = this.dateTimeAdapter.clampDate(this.activeSelectedIndex === 0 ? from : to, this.picker.minDateTime, this.picker.maxDateTime);
3061
+ if (!this.picker.dateTimeChecker(selected)) {
3062
+ return null;
3063
+ }
3064
+ if (this.activeSelectedIndex === 0) {
3065
+ from = selected;
3066
+ }
3067
+ else {
3068
+ to = selected;
3069
+ }
2989
3070
  return [from, to];
2990
3071
  }
2991
3072
  /**
2992
- * Update the given calendar date's time and check if it is valid
2993
- * Because the calendar date has 00:00:00 as default time, if the picker type is 'both',
2994
- * we need to update the given calendar date's time before selecting it.
2995
- * if it is valid, return the updated dateTime
2996
- * if it is not valid, return null
3073
+ * Обновляет время указанной даты календаря и проверяет её допустимость
3074
+ * Поскольку время даты календаря по умолчанию равно 00:00:00, в режиме 'both'
3075
+ * перед выбором даты необходимо обновить её время
3076
+ * Если дата допустима, возвращает обновлённое значение dateTime
3077
+ * Если дата недопустима, возвращает null
2997
3078
  */
2998
3079
  updateAndCheckCalendarDate(date) {
2999
3080
  let result;
3000
- // if the picker is 'both', update the calendar date's time value
3081
+ // В режиме 'both' обновляем время даты календаря
3001
3082
  if (this.picker.pickerType === 'both') {
3002
3083
  result = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(date), this.dateTimeAdapter.getMonth(date), this.dateTimeAdapter.getDate(date), this.dateTimeAdapter.getHours(this.pickerDateTime), this.dateTimeAdapter.getMinutes(this.pickerDateTime), this.dateTimeAdapter.getSeconds(this.pickerDateTime));
3003
3084
  result = this.dateTimeAdapter.clampDate(result, this.picker.minDateTime, this.picker.maxDateTime);
@@ -3005,11 +3086,11 @@ class OwlDateTimeContainerComponent {
3005
3086
  else {
3006
3087
  result = this.dateTimeAdapter.clone(date);
3007
3088
  }
3008
- // check the updated dateTime
3089
+ // Проверяем обновлённое значение dateTime
3009
3090
  return this.picker.dateTimeChecker(result) ? result : null;
3010
3091
  }
3011
3092
  /**
3012
- * Focus to the picker
3093
+ * Переводит фокус на компонент выбора
3013
3094
  * */
3014
3095
  focusPicker() {
3015
3096
  if (this.picker.pickerMode === 'inline') {
@@ -3024,7 +3105,7 @@ class OwlDateTimeContainerComponent {
3024
3105
  }
3025
3106
  parseCssVariableDuration(el, cssVariableName) {
3026
3107
  const durationStr = getComputedStyle(el).getPropertyValue(cssVariableName).trim();
3027
- // Convert to ms
3108
+ // Переводим в миллисекунды
3028
3109
  let duration = undefined;
3029
3110
  if (durationStr.endsWith('ms')) {
3030
3111
  duration = parseFloat(durationStr);
@@ -3069,51 +3150,51 @@ let uniqueId = 0;
3069
3150
  class OwlDialogConfig {
3070
3151
  constructor() {
3071
3152
  /**
3072
- * ID of the element that describes the dialog.
3153
+ * ID элемента с описанием диалогового окна
3073
3154
  */
3074
3155
  this.ariaDescribedBy = null;
3075
3156
  /**
3076
- * Whether to focus the dialog when the dialog is opened
3157
+ * Нужно ли переводить фокус на диалоговое окно при открытии
3077
3158
  */
3078
3159
  this.autoFocus = true;
3079
- /** Whether the dialog has a backdrop. */
3160
+ /** Есть ли у диалогового окна фон */
3080
3161
  this.hasBackdrop = true;
3081
- /** Data being injected into the child component. */
3162
+ /** Данные, передаваемые в дочерний компонент через DI */
3082
3163
  this.data = null;
3083
- /** Whether the user can use escape or clicking outside to close a modal. */
3164
+ /** Может ли пользователь закрыть диалоговое окно клавишей Escape или нажатием за его пределами */
3084
3165
  this.disableClose = false;
3085
3166
  /**
3086
- * The ARIA role of the dialog element.
3167
+ * ARIA-роль элемента диалогового окна
3087
3168
  */
3088
3169
  this.role = 'dialog';
3089
3170
  /**
3090
- * Custom class for the pane
3171
+ * Пользовательский класс панели
3091
3172
  * */
3092
3173
  this.paneClass = '';
3093
3174
  /**
3094
- * Mouse Event
3175
+ * Событие мыши
3095
3176
  * */
3096
3177
  this.event = null;
3097
3178
  /**
3098
- * Custom class for the backdrop
3179
+ * Пользовательский класс фона
3099
3180
  * */
3100
3181
  this.backdropClass = '';
3101
3182
  /**
3102
- * Whether the dialog should close when the user goes backwards/forwards in history.
3183
+ * Нужно ли закрывать диалоговое окно при переходе назад или вперёд в истории браузера
3103
3184
  * */
3104
3185
  this.closeOnNavigation = true;
3105
- /** Width of the dialog. */
3186
+ /** Ширина диалогового окна */
3106
3187
  this.width = '';
3107
- /** Height of the dialog. */
3188
+ /** Высота диалогового окна */
3108
3189
  this.height = '';
3109
3190
  /**
3110
- * The max-width of the overlay panel.
3111
- * If a number is provided, pixel units are assumed.
3191
+ * Максимальная ширина overlay-панели
3192
+ * Числовое значение задаётся в пикселях
3112
3193
  * */
3113
3194
  this.maxWidth = '85vw';
3114
3195
  /**
3115
- * The scroll strategy when the dialog is open
3116
- * Learn more this from https://material.angular.io/cdk/overlay/overview#scroll-strategies
3196
+ * Стратегия прокрутки при открытом диалоговом окне
3197
+ * Подробнее: https://material.angular.io/cdk/overlay/overview#scroll-strategies
3117
3198
  * */
3118
3199
  this.scrollStrategy = new NoopScrollStrategy();
3119
3200
  this.id = `owl-dialog-${uniqueId++}`;
@@ -3128,39 +3209,43 @@ class OwlDialogRef {
3128
3209
  this.overlayRef = overlayRef;
3129
3210
  this.container = container;
3130
3211
  this.id = id;
3212
+ this.closing = false;
3131
3213
  this._beforeClose$ = new Subject();
3132
3214
  this._beforeOpen$ = new Subject();
3133
3215
  this._afterOpen$ = new Subject();
3134
3216
  this._afterClosed$ = new Subject();
3135
- /** Subscription to changes in the user's location. */
3217
+ /** Подписка на изменения адреса в браузере */
3136
3218
  this.locationChanged = Subscription.EMPTY;
3137
3219
  /**
3138
- * The instance of component opened into modal
3220
+ * Экземпляр компонента, открытого в диалоговом окне
3139
3221
  * */
3140
3222
  this.componentInstance = signal(undefined, /* @ts-ignore */
3141
3223
  ...(ngDevMode ? [{ debugName: "componentInstance" }] : /* istanbul ignore next */ []));
3142
- /** Whether the user is allowed to close the dialog. */
3224
+ /** Разрешено ли пользователю закрывать диалоговое окно */
3143
3225
  this.disableClose = true;
3144
3226
  this.disableClose = this.container.config.disableClose;
3145
3227
  this.container.animationStateChanged
3146
- .pipe(filter((event) => event.phaseName === 'start' && event.toState === 'enter'), take$1(1))
3228
+ .pipe(filter((event) => event.phaseName === 'start' && event.toState === 'enter'), take(1))
3147
3229
  .subscribe(() => {
3148
3230
  this._beforeOpen$.next(null);
3149
3231
  this._beforeOpen$.complete();
3150
3232
  });
3151
3233
  this.container.animationStateChanged
3152
- .pipe(filter((event) => event.phaseName === 'done' && event.toState === 'enter'), take$1(1))
3234
+ .pipe(filter((event) => event.phaseName === 'done' && event.toState === 'enter'), take(1))
3153
3235
  .subscribe(() => {
3154
3236
  this._afterOpen$.next(null);
3155
3237
  this._afterOpen$.complete();
3156
3238
  });
3157
3239
  this.container.animationStateChanged
3158
- .pipe(filter((event) => event.phaseName === 'done' && event.toState === 'leave'), take$1(1))
3240
+ .pipe(filter((event) => event.phaseName === 'done' && event.toState === 'leave'), take(1))
3159
3241
  .subscribe(() => {
3160
3242
  this.overlayRef.dispose();
3161
3243
  this.locationChanged.unsubscribe();
3162
3244
  this._afterClosed$.next(this.result);
3163
3245
  this._afterClosed$.complete();
3246
+ this._beforeOpen$.complete();
3247
+ this._afterOpen$.complete();
3248
+ this._beforeClose$.complete();
3164
3249
  this.componentInstance.set(undefined);
3165
3250
  });
3166
3251
  this.overlayRef.keydownEvents()
@@ -3175,9 +3260,13 @@ class OwlDialogRef {
3175
3260
  }
3176
3261
  }
3177
3262
  close(dialogResult) {
3263
+ if (this.closing) {
3264
+ return;
3265
+ }
3266
+ this.closing = true;
3178
3267
  this.result = dialogResult;
3179
3268
  this.container.animationStateChanged
3180
- .pipe(filter(event => event.phaseName === 'start'), take$1(1))
3269
+ .pipe(filter(event => event.phaseName === 'start' && event.toState === 'leave'), take(1))
3181
3270
  .subscribe(() => {
3182
3271
  this._beforeClose$.next(dialogResult);
3183
3272
  this._beforeClose$.complete();
@@ -3186,20 +3275,20 @@ class OwlDialogRef {
3186
3275
  this.container.startExitAnimation();
3187
3276
  }
3188
3277
  /**
3189
- * Gets an observable that emits when the overlay's backdrop has been clicked.
3278
+ * Возвращает Observable нажатий на фон overlay
3190
3279
  */
3191
3280
  backdropClick() {
3192
3281
  return this.overlayRef.backdropClick();
3193
3282
  }
3194
3283
  /**
3195
- * Gets an observable that emits when keydown events are targeted on the overlay.
3284
+ * Возвращает Observable событий keydown, направленных на overlay
3196
3285
  */
3197
3286
  keydownEvents() {
3198
3287
  return this.overlayRef.keydownEvents();
3199
3288
  }
3200
3289
  /**
3201
- * Updates the dialog's position.
3202
- * @param position New dialog position.
3290
+ * Обновляет положение диалогового окна
3291
+ * @param position Новое положение диалогового окна
3203
3292
  */
3204
3293
  updatePosition(position) {
3205
3294
  const strategy = this.getPositionStrategy();
@@ -3219,9 +3308,9 @@ class OwlDialogRef {
3219
3308
  return this;
3220
3309
  }
3221
3310
  /**
3222
- * Updates the dialog's width and height.
3223
- * @param width New width of the dialog.
3224
- * @param height New height of the dialog.
3311
+ * Обновляет ширину и высоту диалогового окна
3312
+ * @param width Новая ширина диалогового окна
3313
+ * @param height Новая высота диалогового окна
3225
3314
  */
3226
3315
  updateSize(width = 'auto', height = 'auto') {
3227
3316
  this.getPositionStrategy().width(width).height(height);
@@ -3243,7 +3332,7 @@ class OwlDialogRef {
3243
3332
  afterClosed() {
3244
3333
  return this._afterClosed$.asObservable();
3245
3334
  }
3246
- /** Fetches the position strategy object from the overlay ref. */
3335
+ /** Возвращает стратегию позиционирования из ссылки на overlay */
3247
3336
  getPositionStrategy() {
3248
3337
  return this.overlayRef.getConfig().positionStrategy;
3249
3338
  }
@@ -3280,13 +3369,16 @@ class OwlDialogContainerComponent extends BasePortalOutlet {
3280
3369
  this.focusTrapFactory = focusTrapFactory;
3281
3370
  this.document = document;
3282
3371
  this.portalOutlet = null;
3283
- /** ID of the element that should be considered as the dialog's label. */
3372
+ this.contentAnimationSubscription = Subscription.EMPTY;
3373
+ this.exiting = false;
3374
+ this.destroyed = false;
3375
+ /** ID элемента, используемого как заголовок диалогового окна */
3284
3376
  this.ariaLabelledBy = null;
3285
- /** Emits when an animation state changes. */
3377
+ /** Событие изменения состояния анимации */
3286
3378
  this.animationStateChanged = new EventEmitter();
3287
3379
  this.isAnimating = signal(false, /* @ts-ignore */
3288
3380
  ...(ngDevMode ? [{ debugName: "isAnimating" }] : /* istanbul ignore next */ []));
3289
- // for animation purpose
3381
+ // Для анимации
3290
3382
  this.params = {
3291
3383
  x: '0px',
3292
3384
  y: '0px',
@@ -3294,13 +3386,19 @@ class OwlDialogContainerComponent extends BasePortalOutlet {
3294
3386
  oy: '50%',
3295
3387
  scale: 0
3296
3388
  };
3297
- // A variable to hold the focused element before the dialog was open.
3298
- // This would help us to refocus back to element when the dialog was closed.
3389
+ // Сохраняет элемент, находившийся в фокусе до открытия диалогового окна
3390
+ // Позволяет вернуть фокус на этот элемент после закрытия окна
3299
3391
  this.elementFocusedBeforeDialogWasOpened = null;
3300
3392
  }
3301
3393
  ngOnInit() { }
3394
+ ngOnDestroy() {
3395
+ this.destroyed = true;
3396
+ this.contentAnimationSubscription.unsubscribe();
3397
+ this.restoreFocus();
3398
+ this.animationStateChanged.complete();
3399
+ }
3302
3400
  /**
3303
- * Attach a ComponentPortal as content to this dialog container.
3401
+ * Подключает ComponentPortal как содержимое контейнера диалогового окна
3304
3402
  */
3305
3403
  attachComponentPortal(portal) {
3306
3404
  if (this.portalOutlet.hasAttached()) {
@@ -3309,7 +3407,14 @@ class OwlDialogContainerComponent extends BasePortalOutlet {
3309
3407
  this.savePreviouslyFocusedElement();
3310
3408
  const component = this.portalOutlet.attachComponentPortal(portal);
3311
3409
  const pickerContainer = component.instance;
3312
- pickerContainer.animationStateChanged.subscribe(state => this.onAnimationDone(state));
3410
+ this.contentAnimationSubscription = pickerContainer.animationStateChanged.subscribe(state => {
3411
+ if (state.phaseName === 'start') {
3412
+ this.onAnimationStart(state);
3413
+ }
3414
+ else {
3415
+ this.onAnimationDone(state);
3416
+ }
3417
+ });
3313
3418
  this._component = component;
3314
3419
  return component;
3315
3420
  }
@@ -3319,14 +3424,20 @@ class OwlDialogContainerComponent extends BasePortalOutlet {
3319
3424
  setConfig(config) {
3320
3425
  this._config = config;
3321
3426
  if (config.event) {
3322
- this.calculateZoomOrigin(event);
3427
+ this.calculateZoomOrigin(config.event);
3323
3428
  }
3324
3429
  }
3325
3430
  onAnimationStart(event) {
3431
+ if (this.exiting && event.toState === 'enter') {
3432
+ return;
3433
+ }
3326
3434
  this.isAnimating.set(true);
3327
3435
  this.animationStateChanged.emit(event);
3328
3436
  }
3329
3437
  onAnimationDone(event) {
3438
+ if (this.exiting && event.toState === 'enter') {
3439
+ return;
3440
+ }
3330
3441
  if (event.toState === 'enter') {
3331
3442
  this.trapFocus();
3332
3443
  }
@@ -3337,11 +3448,12 @@ class OwlDialogContainerComponent extends BasePortalOutlet {
3337
3448
  this.isAnimating.set(false);
3338
3449
  }
3339
3450
  startExitAnimation() {
3451
+ this.exiting = true;
3340
3452
  this._component.destroy();
3341
3453
  }
3342
3454
  /**
3343
- * Calculate origin used in the `zoomFadeInFrom()`
3344
- * for animation purpose
3455
+ * Вычисляет точку начала, используемую в `zoomFadeInFrom()`,
3456
+ * Для анимации
3345
3457
  */
3346
3458
  calculateZoomOrigin(event) {
3347
3459
  if (!event) {
@@ -3363,13 +3475,17 @@ class OwlDialogContainerComponent extends BasePortalOutlet {
3363
3475
  return;
3364
3476
  }
3365
3477
  /**
3366
- * Save the focused element before dialog was open
3478
+ * Сохраняет элемент, находившийся в фокусе до открытия диалогового окна
3367
3479
  */
3368
3480
  savePreviouslyFocusedElement() {
3369
3481
  if (this.document) {
3370
3482
  this.elementFocusedBeforeDialogWasOpened = this.document
3371
3483
  .activeElement;
3372
- Promise.resolve().then(() => this.elementRef.nativeElement.focus());
3484
+ Promise.resolve().then(() => {
3485
+ if (!this.destroyed && !this.exiting) {
3486
+ this.elementRef.nativeElement.focus();
3487
+ }
3488
+ });
3373
3489
  }
3374
3490
  }
3375
3491
  trapFocus() {
@@ -3382,13 +3498,17 @@ class OwlDialogContainerComponent extends BasePortalOutlet {
3382
3498
  }
3383
3499
  restoreFocus() {
3384
3500
  const toFocus = this.elementFocusedBeforeDialogWasOpened;
3385
- // We need the extra check, because IE can set the `activeElement` to null in some cases.
3386
- if (toFocus && typeof toFocus.focus === 'function') {
3501
+ // Дополнительная проверка нужна, поскольку IE иногда задаёт `activeElement` равным null
3502
+ const activeElement = this.document?.activeElement;
3503
+ if (toFocus && typeof toFocus.focus === 'function' &&
3504
+ (!activeElement || activeElement === this.document.body || this.elementRef.nativeElement.contains(activeElement))) {
3387
3505
  toFocus.focus();
3388
3506
  }
3389
3507
  if (this.focusTrap) {
3390
3508
  this.focusTrap.destroy();
3509
+ this.focusTrap = null;
3391
3510
  }
3511
+ this.elementFocusedBeforeDialogWasOpened = null;
3392
3512
  }
3393
3513
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlDialogContainerComponent, deps: [{ token: i0.ElementRef }, { token: i1.FocusTrapFactory }, { token: DOCUMENT, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
3394
3514
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: OwlDialogContainerComponent, isStandalone: false, selector: "owl-dialog-container", host: { properties: { "class.owl-dialog-container": "owlDialogContainerClass", "attr.tabindex": "owlDialogContainerTabIndex", "attr.id": "owlDialogContainerId", "attr.role": "owlDialogContainerRole", "attr.aria-labelledby": "owlDialogContainerAriaLabelledby", "attr.aria-describedby": "owlDialogContainerAriaDescribedby" } }, viewQueries: [{ propertyName: "portalOutlet", first: true, predicate: CdkPortalOutlet, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template [cdkPortalOutlet]></ng-template>\r\n", dependencies: [{ kind: "directive", type: i2$1.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }] }); }
@@ -3417,11 +3537,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
3417
3537
  * object.utils
3418
3538
  */
3419
3539
  /**
3420
- * Extends an object with the *enumerable* and *own* properties of one or more source objects,
3421
- * similar to Object.assign.
3540
+ * Дополняет объект собственными перечисляемыми свойствами одного или нескольких исходных объектов,
3541
+ * аналогично Object.assign
3422
3542
  *
3423
- * @param dest The object which will have properties copied to it.
3424
- * @param sources The source objects from which properties will be copied.
3543
+ * @param dest Объект, в который копируются свойства
3544
+ * @param sources Исходные объекты, из которых копируются свойства
3425
3545
  */
3426
3546
  function extendObject(dest, ...sources) {
3427
3547
  if (dest == null) {
@@ -3430,7 +3550,7 @@ function extendObject(dest, ...sources) {
3430
3550
  for (const source of sources) {
3431
3551
  if (source != null) {
3432
3552
  for (const key in source) {
3433
- if (source.hasOwnProperty(key)) {
3553
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
3434
3554
  dest[key] = source[key];
3435
3555
  }
3436
3556
  }
@@ -3448,7 +3568,7 @@ function extendObject(dest, ...sources) {
3448
3568
  */
3449
3569
  const OWL_DIALOG_DATA = new InjectionToken('OwlDialogData');
3450
3570
  /**
3451
- * Injection token that determines the scroll handling while the dialog is open.
3571
+ * Токен DI, определяющий обработку прокрутки при открытом диалоговом окне
3452
3572
  * */
3453
3573
  const OWL_DIALOG_SCROLL_STRATEGY = new InjectionToken('owl-dialog-scroll-strategy');
3454
3574
  function OWL_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay) {
@@ -3462,23 +3582,26 @@ const OWL_DIALOG_SCROLL_STRATEGY_PROVIDER = {
3462
3582
  useFactory: OWL_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY
3463
3583
  };
3464
3584
  /**
3465
- * Injection token that can be used to specify default dialog options.
3585
+ * Токен DI для задания параметров диалогового окна по умолчанию
3466
3586
  * */
3467
3587
  const OWL_DIALOG_DEFAULT_OPTIONS = new InjectionToken('owl-dialog-default-options');
3468
3588
  class OwlDialogService {
3469
- /** Keeps track of the currently-open dialogs. */
3589
+ get ariaHiddenElements() {
3590
+ return this.parentDialog ? this.parentDialog.ariaHiddenElements : this._ariaHiddenElements;
3591
+ }
3592
+ /** Хранит текущие открытые диалоговые окна */
3470
3593
  get openDialogs() {
3471
3594
  return this.parentDialog
3472
3595
  ? this.parentDialog.openDialogs
3473
3596
  : this._openDialogsAtThisLevel;
3474
3597
  }
3475
- /** Stream that emits when a dialog has been opened. */
3598
+ /** Поток событий открытия диалогового окна */
3476
3599
  get beforeOpen() {
3477
3600
  return this.parentDialog
3478
3601
  ? this.parentDialog.beforeOpen
3479
3602
  : this._beforeOpenAtThisLevel;
3480
3603
  }
3481
- /** Stream that emits when a dialog has been opened. */
3604
+ /** Поток событий открытия диалогового окна */
3482
3605
  get afterOpen() {
3483
3606
  return this.parentDialog
3484
3607
  ? this.parentDialog.afterOpen
@@ -3497,22 +3620,19 @@ class OwlDialogService {
3497
3620
  this.defaultOptions = defaultOptions;
3498
3621
  this.parentDialog = parentDialog;
3499
3622
  this.overlayContainer = overlayContainer;
3500
- this.ariaHiddenElements = new Map();
3623
+ this._ariaHiddenElements = new Map();
3501
3624
  this._openDialogsAtThisLevel = [];
3502
3625
  this._beforeOpenAtThisLevel = new Subject();
3503
3626
  this._afterOpenAtThisLevel = new Subject();
3504
3627
  this._afterAllClosedAtThisLevel = new Subject();
3505
3628
  /**
3506
- * Stream that emits when all open dialog have finished closing.
3507
- * Will emit on subscribe if there are no open dialogs to begin with.
3629
+ * Поток событий завершения закрытия всех диалоговых окон
3630
+ * Если открытых окон нет, событие отправляется сразу при подписке
3508
3631
  */
3509
- this.afterAllClosed = defer(() => this._openDialogsAtThisLevel.length
3632
+ this.afterAllClosed = defer(() => this.openDialogs.length
3510
3633
  ? this._afterAllClosed
3511
3634
  : this._afterAllClosed.pipe(startWith(undefined)));
3512
3635
  this.scrollStrategy = scrollStrategy;
3513
- if (!parentDialog && location) {
3514
- location.subscribe(() => this.closeAll());
3515
- }
3516
3636
  }
3517
3637
  open(componentOrTemplateRef, config) {
3518
3638
  config = applyConfigDefaults(config, this.defaultOptions);
@@ -3534,7 +3654,7 @@ class OwlDialogService {
3534
3654
  return dialogRef;
3535
3655
  }
3536
3656
  /**
3537
- * Closes all of the currently-open dialogs.
3657
+ * Закрывает все открытые диалоговые окна
3538
3658
  */
3539
3659
  closeAll() {
3540
3660
  let i = this.openDialogs.length;
@@ -3543,8 +3663,8 @@ class OwlDialogService {
3543
3663
  }
3544
3664
  }
3545
3665
  /**
3546
- * Finds an open dialog by its id.
3547
- * @param id ID to use when looking up the dialog.
3666
+ * Находит открытое диалоговое окно по ID
3667
+ * @param id ID искомого диалогового окна
3548
3668
  */
3549
3669
  getDialogById(id) {
3550
3670
  return this.openDialogs.find(dialog => dialog.id === id);
@@ -3609,11 +3729,11 @@ class OwlDialogService {
3609
3729
  return state;
3610
3730
  }
3611
3731
  removeOpenDialog(dialogRef) {
3612
- const index = this._openDialogsAtThisLevel.indexOf(dialogRef);
3732
+ const index = this.openDialogs.indexOf(dialogRef);
3613
3733
  if (index > -1) {
3614
3734
  this.openDialogs.splice(index, 1);
3615
- // If all the dialogs were closed, remove/restore the `aria-hidden`
3616
- // to a the siblings and emit to the `afterAllClosed` stream.
3735
+ // Если все диалоговые окна закрыты, удаляем или восстанавливаем `aria-hidden`
3736
+ // у соседних элементов и отправляем событие в поток `afterAllClosed`
3617
3737
  if (!this.openDialogs.length) {
3618
3738
  this.ariaHiddenElements.forEach((previousValue, element) => {
3619
3739
  if (previousValue) {
@@ -3629,11 +3749,11 @@ class OwlDialogService {
3629
3749
  }
3630
3750
  }
3631
3751
  /**
3632
- * Hides all of the content that isn't an overlay from assistive technology.
3752
+ * Скрывает от вспомогательных технологий всё содержимое за пределами overlay
3633
3753
  */
3634
3754
  hideNonDialogContentFromAssistiveTechnology() {
3635
3755
  const overlayContainer = this.overlayContainer.getContainerElement();
3636
- // Ensure that the overlay container is attached to the DOM.
3756
+ // Проверяем, что контейнер overlay подключён к DOM
3637
3757
  if (overlayContainer.parentElement) {
3638
3758
  const siblings = overlayContainer.parentElement.children;
3639
3759
  for (let i = siblings.length - 1; i > -1; i--) {
@@ -3669,19 +3789,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
3669
3789
  type: SkipSelf
3670
3790
  }] }, { type: i1$1.OverlayContainer }] });
3671
3791
  /**
3672
- * Applies default options to the dialog config.
3673
- * @param config Config to be modified.
3674
- * @param defaultOptions Default config setting
3675
- * @returns The new configuration object.
3792
+ * Применяет параметры по умолчанию к конфигурации диалогового окна
3793
+ * @param config Изменяемая конфигурация
3794
+ * @param defaultOptions Параметры конфигурации по умолчанию
3795
+ * @returns Новый объект конфигурации
3676
3796
  */
3677
3797
  function applyConfigDefaults(config, defaultOptions) {
3678
- return extendObject(new OwlDialogConfig(), config, defaultOptions);
3798
+ return extendObject(new OwlDialogConfig(), defaultOptions, config);
3679
3799
  }
3680
3800
 
3681
3801
  /**
3682
3802
  * date-time-picker.component
3683
3803
  */
3684
- /** Injection token that determines the scroll handling while the dtPicker is open. */
3804
+ /** Токен DI, определяющий обработку прокрутки при открытом компоненте выбора даты и времени */
3685
3805
  const OWL_DTPICKER_SCROLL_STRATEGY = new InjectionToken('owl-dtpicker-scroll-strategy');
3686
3806
  /** @docs-private */
3687
3807
  function OWL_DTPICKER_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay) {
@@ -3696,21 +3816,21 @@ const OWL_DTPICKER_SCROLL_STRATEGY_PROVIDER = {
3696
3816
  };
3697
3817
  class OwlDateTimeComponent extends OwlDateTime {
3698
3818
  get startAt() {
3699
- // If an explicit startAt is set we start there, otherwise we start at whatever the currently
3700
- // selected value is.
3701
- if (this._startAt) {
3819
+ // Если startAt задан явно, открываем календарь на этой дате
3820
+ // Иначе используем текущее выбранное значение
3821
+ if (this._startAt != null) {
3702
3822
  return this._startAt;
3703
3823
  }
3704
3824
  if (this._dtInput) {
3705
3825
  if (this._dtInput.selectMode === 'single') {
3706
- return this._dtInput.value || null;
3826
+ return this._dtInput.value ?? null;
3707
3827
  }
3708
3828
  else if (this._dtInput.selectMode === 'range' ||
3709
3829
  this._dtInput.selectMode === 'rangeFrom') {
3710
- return this._dtInput.values[0] || null;
3830
+ return this._dtInput.values[0] ?? null;
3711
3831
  }
3712
3832
  else if (this._dtInput.selectMode === 'rangeTo') {
3713
- return this._dtInput.values[1] || null;
3833
+ return this._dtInput.values[1] ?? null;
3714
3834
  }
3715
3835
  }
3716
3836
  else {
@@ -3721,16 +3841,16 @@ class OwlDateTimeComponent extends OwlDateTime {
3721
3841
  this._startAt = this.getValidDate(this.dateTimeAdapter.deserialize(date));
3722
3842
  }
3723
3843
  get endAt() {
3724
- if (this._endAt) {
3844
+ if (this._endAt != null) {
3725
3845
  return this._endAt;
3726
3846
  }
3727
3847
  if (this._dtInput) {
3728
3848
  if (this._dtInput.selectMode === 'single') {
3729
- return this._dtInput.value || null;
3849
+ return this._dtInput.value ?? null;
3730
3850
  }
3731
3851
  else if (this._dtInput.selectMode === 'range' ||
3732
3852
  this._dtInput.selectMode === 'rangeFrom') {
3733
- return this._dtInput.values[1] || null;
3853
+ return this._dtInput.values[1] ?? null;
3734
3854
  }
3735
3855
  }
3736
3856
  else {
@@ -3772,6 +3892,7 @@ class OwlDateTimeComponent extends OwlDateTime {
3772
3892
  if (value !== this._disabled) {
3773
3893
  this._disabled = value;
3774
3894
  this.disabledChange.next(value);
3895
+ this.refreshView();
3775
3896
  }
3776
3897
  }
3777
3898
  get opened() {
@@ -3788,20 +3909,20 @@ class OwlDateTimeComponent extends OwlDateTime {
3788
3909
  }
3789
3910
  set selected(value) {
3790
3911
  this._selected = value;
3791
- this.changeDetector.markForCheck();
3912
+ this.refreshView();
3792
3913
  }
3793
3914
  get selecteds() {
3794
3915
  return this._selecteds;
3795
3916
  }
3796
3917
  set selecteds(values) {
3797
3918
  this._selecteds = values;
3798
- this.changeDetector.markForCheck();
3919
+ this.refreshView();
3799
3920
  }
3800
- /** The minimum selectable date. */
3921
+ /** Минимальная доступная для выбора дата */
3801
3922
  get minDateTime() {
3802
3923
  return this._dtInput && this._dtInput.min;
3803
3924
  }
3804
- /** The maximum selectable date. */
3925
+ /** Максимальная доступная для выбора дата */
3805
3926
  get maxDateTime() {
3806
3927
  return this._dtInput && this._dtInput.max;
3807
3928
  }
@@ -3827,69 +3948,78 @@ class OwlDateTimeComponent extends OwlDateTime {
3827
3948
  this.dateTimeAdapter = dateTimeAdapter;
3828
3949
  this.dateTimeFormats = dateTimeFormats;
3829
3950
  this.document = document;
3830
- /** Custom class for the picker backdrop. */
3951
+ /** Пользовательский класс фона компонента выбора */
3831
3952
  this.backdropClass = [];
3832
- /** Custom class for the picker overlay pane. */
3953
+ /** Пользовательский класс overlay-панели компонента выбора */
3833
3954
  this.panelClass = [];
3834
3955
  /**
3835
- * Set the type of the dateTime picker
3836
- * 'both' -- show both calendar and timer
3837
- * 'calendar' -- show only calendar
3838
- * 'timer' -- show only timer
3956
+ * Задаёт тип компонента выбора даты и времени:
3957
+ * 'both' — календарь и выбор времени
3958
+ * 'calendar' — только календарь
3959
+ * 'timer' — только выбор времени
3839
3960
  */
3840
3961
  this._pickerType = 'both';
3841
3962
  /**
3842
- * Whether the picker open as a dialog
3963
+ * Открывается ли компонент выбора в диалоговом окне
3843
3964
  */
3844
3965
  this._pickerMode = 'popup';
3845
- /** Whether the calendar is open. */
3966
+ /** Открыт ли календарь */
3846
3967
  this._opened = false;
3968
+ this.closing = false;
3969
+ this.destroyed = false;
3970
+ this.injector = inject(Injector);
3847
3971
  /**
3848
- * Callback when the picker is closed
3972
+ * Обработчик закрытия компонента выбора
3849
3973
  * */
3850
3974
  this.afterPickerClosed = new EventEmitter();
3851
3975
  /**
3852
- * Callback before the picker is open
3976
+ * Обработчик перед открытием компонента выбора
3853
3977
  * */
3854
3978
  this.beforePickerOpen = new EventEmitter();
3855
3979
  /**
3856
- * Callback when the picker is open
3980
+ * Обработчик открытия компонента выбора
3857
3981
  * */
3858
3982
  this.afterPickerOpen = new EventEmitter();
3859
3983
  /**
3860
- * Emits selected year in multi-year view
3861
- * This doesn't imply a change on the selected date.
3984
+ * Передаёт выбранный год в представлении нескольких лет
3985
+ * При этом выбранная дата не изменяется
3862
3986
  * */
3863
3987
  this.yearSelected = new EventEmitter();
3864
3988
  /**
3865
- * Emits selected month in year view
3866
- * This doesn't imply a change on the selected date.
3989
+ * Передаёт выбранный месяц в представлении года
3990
+ * При этом выбранная дата не изменяется
3867
3991
  * */
3868
3992
  this.monthSelected = new EventEmitter();
3869
3993
  /**
3870
- * Emits selected date
3994
+ * Передаёт выбранную дату
3871
3995
  * */
3872
3996
  this.dateSelected = new EventEmitter();
3873
3997
  /**
3874
- * Emit when the selected value has been confirmed
3998
+ * Событие подтверждения выбранного значения
3875
3999
  * */
3876
4000
  this.confirmSelectedChange = new EventEmitter();
3877
4001
  /**
3878
- * Emits when the date time picker is disabled.
4002
+ * Событие отключения компонента выбора даты и времени
3879
4003
  * */
3880
4004
  this.disabledChange = new EventEmitter();
4005
+ this.dialogClosedStreamSub = Subscription.EMPTY;
3881
4006
  this.dtInputSub = Subscription.EMPTY;
3882
4007
  this.hidePickerStreamSub = Subscription.EMPTY;
3883
4008
  this.confirmSelectedStreamSub = Subscription.EMPTY;
3884
4009
  this.pickerOpenedStreamSub = Subscription.EMPTY;
3885
4010
  this.pickerBeforeOpenedStreamSub = Subscription.EMPTY;
3886
- /** The element that was focused before the date time picker was opened. */
4011
+ /** Элемент, находившийся в фокусе до открытия компонента выбора даты и времени */
3887
4012
  this.focusedElementBeforeOpen = null;
3888
4013
  this._selecteds = [];
3889
4014
  this.defaultScrollStrategy = defaultScrollStrategy;
3890
4015
  }
4016
+ refreshView() {
4017
+ this.changeDetector.markForCheck();
4018
+ this.pickerContainer?.refreshView();
4019
+ }
3891
4020
  ngOnInit() { }
3892
4021
  ngOnDestroy() {
4022
+ this.destroyed = true;
3893
4023
  this.close();
3894
4024
  this.dtInputSub.unsubscribe();
3895
4025
  this.disabledChange.complete();
@@ -3912,7 +4042,7 @@ class OwlDateTimeComponent extends OwlDateTime {
3912
4042
  });
3913
4043
  }
3914
4044
  open() {
3915
- if (this._opened || this.disabled) {
4045
+ if (this._opened || this.closing || this.destroyed || this.disabled) {
3916
4046
  return;
3917
4047
  }
3918
4048
  if (!this._dtInput) {
@@ -3921,31 +4051,33 @@ class OwlDateTimeComponent extends OwlDateTime {
3921
4051
  if (this.document) {
3922
4052
  this.focusedElementBeforeOpen = this.document.activeElement;
3923
4053
  }
3924
- // reset the picker selected value
4054
+ // Сбрасываем выбранное значение компонента
3925
4055
  if (this.isInSingleMode) {
3926
4056
  this.selected = this._dtInput.value;
3927
4057
  }
3928
4058
  else if (this.isInRangeMode) {
3929
4059
  this.selecteds = this._dtInput.values;
3930
4060
  }
3931
- // when the picker is open , we make sure the picker's current selected time value
3932
- // is the same as the _startAt time value.
3933
- if (this.selected && this.pickerType !== 'calendar' && this._startAt) {
4061
+ // При открытии компонента выбора приводим текущее выбранное время
4062
+ // к времени из _startAt
4063
+ if (this.selected != null && this.pickerType !== 'calendar' && this._startAt != null) {
3934
4064
  this.selected = this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(this.selected), this.dateTimeAdapter.getMonth(this.selected), this.dateTimeAdapter.getDate(this.selected), this.dateTimeAdapter.getHours(this._startAt), this.dateTimeAdapter.getMinutes(this._startAt), this.dateTimeAdapter.getSeconds(this._startAt));
3935
4065
  }
4066
+ this._opened = true;
4067
+ this.changeDetector.markForCheck();
3936
4068
  this.pickerMode === 'dialog' ? this.openAsDialog() : this.openAsPopup();
3937
4069
  this.pickerContainer.picker = this;
3938
- // Listen to picker container's hidePickerStream
4070
+ // Подписываемся на hidePickerStream контейнера компонента выбора
3939
4071
  this.hidePickerStreamSub = this.pickerContainer.hidePickerStream.subscribe(() => {
3940
4072
  this.close();
3941
4073
  });
3942
- // Listen to picker container's confirmSelectedStream
4074
+ // Подписываемся на confirmSelectedStream контейнера компонента выбора
3943
4075
  this.confirmSelectedStreamSub = this.pickerContainer.confirmSelectedStream.subscribe((event) => {
3944
4076
  this.confirmSelect(event);
3945
4077
  });
3946
4078
  }
3947
4079
  /**
3948
- * Selects the given date
4080
+ * Выбирает указанную дату
3949
4081
  */
3950
4082
  select(date) {
3951
4083
  if (Array.isArray(date)) {
@@ -3955,105 +4087,82 @@ class OwlDateTimeComponent extends OwlDateTime {
3955
4087
  this.selected = date;
3956
4088
  }
3957
4089
  /**
3958
- * Cases in which automatically confirm the select when date or dates are selected:
3959
- * 1) picker mode is NOT 'dialog'
3960
- * 2) picker type is 'calendar' and selectMode is 'single'.
3961
- * 3) picker type is 'calendar' and selectMode is 'range' and
3962
- * the 'selecteds' has 'from'(selecteds[0]) and 'to'(selecteds[1]) values.
3963
- * 4) selectMode is 'rangeFrom' and selecteds[0] has value.
3964
- * 5) selectMode is 'rangeTo' and selecteds[1] has value.
4090
+ * Условия автоматического подтверждения выбранной даты или диапазона:
4091
+ * 1) Режим компонента отличается от 'dialog'
4092
+ * 2) Тип компонента — 'calendar', а selectMode — 'single'
4093
+ * 3) Тип компонента — 'calendar', selectMode — 'range',
4094
+ * а в selecteds заданы начало (selecteds[0]) и конец (selecteds[1]) диапазона
4095
+ * 4) selectMode — 'rangeFrom', а selecteds[0] содержит значение
4096
+ * 5) selectMode — 'rangeTo', а selecteds[1] содержит значение
3965
4097
  * */
3966
4098
  if (this.pickerMode !== 'dialog' &&
3967
4099
  this.pickerType === 'calendar' &&
3968
- ((this.selectMode === 'single' && this.selected) ||
3969
- (this.selectMode === 'rangeFrom' && this.selecteds[0]) ||
3970
- (this.selectMode === 'rangeTo' && this.selecteds[1]) ||
4100
+ ((this.selectMode === 'single' && this.selected != null) ||
4101
+ (this.selectMode === 'rangeFrom' && this.selecteds[0] != null) ||
4102
+ (this.selectMode === 'rangeTo' && this.selecteds[1] != null) ||
3971
4103
  (this.selectMode === 'range' &&
3972
- this.selecteds[0] &&
3973
- this.selecteds[1]))) {
4104
+ this.selecteds[0] != null &&
4105
+ this.selecteds[1] != null))) {
3974
4106
  this.confirmSelect();
3975
4107
  }
3976
4108
  }
3977
4109
  /**
3978
- * Emits the selected year in multi-year view
4110
+ * Передаёт выбранный год в представлении нескольких лет
3979
4111
  * */
3980
4112
  selectYear(normalizedYear) {
3981
4113
  this.yearSelected.emit(normalizedYear);
3982
4114
  }
3983
4115
  /**
3984
- * Emits selected month in year view
4116
+ * Передаёт выбранный месяц в представлении года
3985
4117
  * */
3986
4118
  selectMonth(normalizedMonth) {
3987
4119
  this.monthSelected.emit(normalizedMonth);
3988
4120
  }
3989
4121
  /**
3990
- * Emits the selected date
4122
+ * Передаёт выбранную дату
3991
4123
  * */
3992
4124
  selectDate(normalizedDate) {
3993
4125
  this.dateSelected.emit(normalizedDate);
3994
4126
  }
3995
4127
  /**
3996
- * Hide the picker
4128
+ * Закрывает компонент выбора
3997
4129
  */
3998
4130
  close() {
3999
- if (!this._opened) {
4131
+ if (!this._opened || this.closing) {
4000
4132
  return;
4001
4133
  }
4002
- if (this.popupRef && this.popupRef.hasAttached()) {
4134
+ this.closing = true;
4135
+ this._opened = false;
4136
+ this.positionRenderRef?.destroy();
4137
+ this.positionRenderRef = undefined;
4138
+ this.hidePickerStreamSub?.unsubscribe();
4139
+ this.confirmSelectedStreamSub?.unsubscribe();
4140
+ this.pickerBeforeOpenedStreamSub?.unsubscribe();
4141
+ this.pickerOpenedStreamSub?.unsubscribe();
4142
+ this.dialogClosedStreamSub.unsubscribe();
4143
+ const dialogRef = this.dialogRef;
4144
+ this.dialogRef = null;
4145
+ dialogRef?.close();
4146
+ if (this.popupRef?.hasAttached()) {
4003
4147
  this.popupRef.detach();
4004
4148
  }
4005
- if (this.pickerContainerPortal &&
4006
- this.pickerContainerPortal.isAttached) {
4149
+ if (this.pickerContainerPortal?.isAttached) {
4007
4150
  this.pickerContainerPortal.detach();
4008
4151
  }
4009
- if (this.hidePickerStreamSub) {
4010
- this.hidePickerStreamSub.unsubscribe();
4011
- this.hidePickerStreamSub = null;
4012
- }
4013
- if (this.confirmSelectedStreamSub) {
4014
- this.confirmSelectedStreamSub.unsubscribe();
4015
- this.confirmSelectedStreamSub = null;
4016
- }
4017
- if (this.pickerBeforeOpenedStreamSub) {
4018
- this.pickerBeforeOpenedStreamSub.unsubscribe();
4019
- this.pickerBeforeOpenedStreamSub = null;
4020
- }
4021
- if (this.pickerOpenedStreamSub) {
4022
- this.pickerOpenedStreamSub.unsubscribe();
4023
- this.pickerOpenedStreamSub = null;
4024
- }
4025
- if (this.dialogRef) {
4026
- this.dialogRef.close();
4027
- this.dialogRef = null;
4028
- }
4029
- const completeClose = () => {
4030
- if (this._opened) {
4031
- this._opened = false;
4032
- const selected = this.selected || this.selecteds;
4033
- this.afterPickerClosed.emit(selected);
4034
- this.focusedElementBeforeOpen = null;
4035
- }
4036
- };
4037
- if (this.focusedElementBeforeOpen &&
4038
- typeof this.focusedElementBeforeOpen.focus === 'function') {
4039
- // Because IE moves focus asynchronously, we can't count on it being restored before we've
4040
- // marked the datepicker as closed. If the event fires out of sequence and the element that
4041
- // we're refocusing opens the datepicker on focus, the user could be stuck with not being
4042
- // able to close the calendar at all. We work around it by making the logic, that marks
4043
- // the datepicker as closed, async as well.
4044
- this.focusedElementBeforeOpen.focus();
4045
- setTimeout(completeClose);
4046
- }
4047
- else {
4048
- completeClose();
4049
- }
4152
+ this.pickerContainer = null;
4153
+ // Игнорируем обработчики фокуса, пытающиеся повторно открыть компонент при восстановлении фокуса
4154
+ this.focusedElementBeforeOpen?.focus();
4155
+ this.focusedElementBeforeOpen = null;
4156
+ this.changeDetector.markForCheck();
4157
+ this.closing = false;
4158
+ this.afterPickerClosed.emit(this.isInSingleMode ? this.selected : this.selecteds);
4050
4159
  }
4051
4160
  /**
4052
- * Confirm the selected value
4161
+ * Подтверждает выбранное значение
4053
4162
  */
4054
4163
  confirmSelect(event) {
4055
4164
  if (this.isInSingleMode) {
4056
- const selected = this.selected || this.startAt || this.dateTimeAdapter.now();
4165
+ const selected = this.selected ?? this.startAt ?? this.dateTimeAdapter.now();
4057
4166
  this.confirmSelectedChange.emit(selected);
4058
4167
  }
4059
4168
  else if (this.isInRangeMode) {
@@ -4063,7 +4172,7 @@ class OwlDateTimeComponent extends OwlDateTime {
4063
4172
  return;
4064
4173
  }
4065
4174
  /**
4066
- * Open the picker as a dialog
4175
+ * Открывает компонент выбора в диалоговом окне
4067
4176
  */
4068
4177
  openAsDialog() {
4069
4178
  this.dialogRef = this.dialogService.open(OwlDateTimeContainerComponent, {
@@ -4077,17 +4186,16 @@ class OwlDateTimeComponent extends OwlDateTime {
4077
4186
  scrollStrategy: this.scrollStrategy || this.defaultScrollStrategy()
4078
4187
  });
4079
4188
  this.pickerContainer = untracked(this.dialogRef.componentInstance);
4080
- this.dialogRef.beforeOpen().subscribe(() => {
4189
+ this.pickerBeforeOpenedStreamSub = this.dialogRef.beforeOpen().subscribe(() => {
4081
4190
  this.beforePickerOpen.emit(null);
4082
4191
  });
4083
- this.dialogRef.afterOpen().subscribe(() => {
4192
+ this.pickerOpenedStreamSub = this.dialogRef.afterOpen().subscribe(() => {
4084
4193
  this.afterPickerOpen.emit(null);
4085
- this._opened = true;
4086
4194
  });
4087
- this.dialogRef.afterClosed().subscribe(() => this.close());
4195
+ this.dialogClosedStreamSub = this.dialogRef.afterClosed().subscribe(() => this.close());
4088
4196
  }
4089
4197
  /**
4090
- * Open the picker as popup
4198
+ * Открывает компонент выбора во всплывающем окне
4091
4199
  */
4092
4200
  openAsPopup() {
4093
4201
  if (!this.pickerContainerPortal) {
@@ -4099,24 +4207,26 @@ class OwlDateTimeComponent extends OwlDateTime {
4099
4207
  if (!this.popupRef.hasAttached()) {
4100
4208
  const componentRef = this.popupRef.attach(this.pickerContainerPortal);
4101
4209
  this.pickerContainer = componentRef.instance;
4102
- // Update the position once the calendar has rendered.
4103
- this.ngZone.onStable
4104
- .asObservable()
4105
- .pipe(take(1))
4106
- .subscribe(() => {
4107
- this.popupRef.updatePosition();
4108
- });
4210
+ // Обновляем положение после отрисовки календаря
4211
+ this.positionRenderRef?.destroy();
4212
+ this.positionRenderRef = afterNextRender({
4213
+ mixedReadWrite: () => {
4214
+ this.positionRenderRef = undefined;
4215
+ if (this.popupRef.hasAttached()) {
4216
+ this.popupRef.updatePosition();
4217
+ }
4218
+ }
4219
+ }, { injector: this.injector });
4109
4220
  this.pickerBeforeOpenedStreamSub = this.pickerContainer.beforePickerOpenedStream
4110
- .pipe(take(1))
4221
+ .pipe(take$1(1))
4111
4222
  .subscribe(() => {
4112
4223
  this.beforePickerOpen.emit(null);
4113
4224
  });
4114
- // emit open stream
4225
+ // Отправляем событие открытия
4115
4226
  this.pickerOpenedStreamSub = this.pickerContainer.pickerOpenedStream
4116
- .pipe(take(1))
4227
+ .pipe(take$1(1))
4117
4228
  .subscribe(() => {
4118
4229
  this.afterPickerOpen.emit(null);
4119
- this._opened = true;
4120
4230
  });
4121
4231
  }
4122
4232
  }
@@ -4140,7 +4250,7 @@ class OwlDateTimeComponent extends OwlDateTime {
4140
4250
  event.keyCode === UP_ARROW)))).subscribe(() => this.close());
4141
4251
  }
4142
4252
  /**
4143
- * Create the popup PositionStrategy.
4253
+ * Создаёт PositionStrategy всплывающего окна
4144
4254
  * */
4145
4255
  createPopupPositionStrategy() {
4146
4256
  return this.overlay
@@ -4261,21 +4371,22 @@ class OwlDateTimeInputDirective {
4261
4371
  return this._required;
4262
4372
  }
4263
4373
  set required(value) {
4264
- this._required = value === '' || value;
4374
+ this._required = coerceBooleanProperty(value);
4265
4375
  this.validatorOnChange();
4266
4376
  }
4267
4377
  /**
4268
- * The date time picker that this input is associated with.
4378
+ * Компонент выбора даты и времени, связанный с этим полем
4269
4379
  * */
4270
4380
  set owlDateTime(value) {
4271
4381
  this.registerDateTimePicker(value);
4272
4382
  }
4273
4383
  /**
4274
- * A function to filter date time
4384
+ * Функция фильтрации даты и времени
4275
4385
  */
4276
4386
  set owlDateTimeFilter(filter) {
4277
4387
  this._dateTimeFilter = filter;
4278
4388
  this.validatorOnChange();
4389
+ this.dtPicker?.refreshView();
4279
4390
  }
4280
4391
  get dateTimeFilter() {
4281
4392
  return this._dateTimeFilter;
@@ -4289,12 +4400,14 @@ class OwlDateTimeInputDirective {
4289
4400
  if (this._disabled !== newValue) {
4290
4401
  this._disabled = newValue;
4291
4402
  this.disabledChange.emit(newValue);
4403
+ this.changeDetector.markForCheck();
4404
+ this.dtPicker?.refreshView();
4292
4405
  }
4293
- // We need to null check the `blur` method, because it's undefined during SSR.
4406
+ // Проверяем наличие метода `blur`, поскольку при SSR он отсутствует
4294
4407
  if (newValue && element.blur) {
4295
- // Normally, native input elements automatically blur if they turn disabled. This behavior
4296
- // is problematic, because it would mean that it triggers another change detection cycle,
4297
- // which then causes a changed after checked error if the input element was focused before.
4408
+ // Обычно нативное поле ввода автоматически теряет фокус при отключении, что
4409
+ // запускает дополнительный цикл change detection и может вызвать ошибку
4410
+ // changed after checked, если поле ввода до этого находилось в фокусе
4298
4411
  element.blur();
4299
4412
  }
4300
4413
  }
@@ -4304,6 +4417,7 @@ class OwlDateTimeInputDirective {
4304
4417
  set min(value) {
4305
4418
  this._min = this.getValidDate(this.dateTimeAdapter.deserialize(value));
4306
4419
  this.validatorOnChange();
4420
+ this.dtPicker?.refreshView();
4307
4421
  }
4308
4422
  get max() {
4309
4423
  return this._max;
@@ -4311,6 +4425,7 @@ class OwlDateTimeInputDirective {
4311
4425
  set max(value) {
4312
4426
  this._max = this.getValidDate(this.dateTimeAdapter.deserialize(value));
4313
4427
  this.validatorOnChange();
4428
+ this.dtPicker?.refreshView();
4314
4429
  }
4315
4430
  get selectMode() {
4316
4431
  return this._selectMode;
@@ -4323,19 +4438,21 @@ class OwlDateTimeInputDirective {
4323
4438
  throw Error('OwlDateTime Error: invalid selectMode value!');
4324
4439
  }
4325
4440
  this._selectMode = mode;
4441
+ this.validatorOnChange();
4442
+ this.dtPicker?.refreshView();
4326
4443
  }
4327
4444
  get value() {
4328
4445
  return this._value;
4329
4446
  }
4330
4447
  set value(value) {
4331
4448
  value = this.dateTimeAdapter.deserialize(value);
4332
- this.lastValueValid = !value || this.dateTimeAdapter.isValid(value);
4449
+ this.lastValueValid = value == null || this.dateTimeAdapter.isValid(value);
4333
4450
  value = this.getValidDate(value);
4334
4451
  const oldDate = this._value;
4335
4452
  this._value = value;
4336
- // set the input property 'value'
4453
+ // Задаём свойство 'value' поля ввода
4337
4454
  this.formatNativeInputValue();
4338
- // check if the input value changed
4455
+ // Проверяем, изменилось ли значение поля ввода
4339
4456
  if (!this.dateTimeAdapter.isEqual(oldDate, value)) {
4340
4457
  this.valueChange.emit(value);
4341
4458
  }
@@ -4345,21 +4462,15 @@ class OwlDateTimeInputDirective {
4345
4462
  }
4346
4463
  set values(values) {
4347
4464
  if (values && values.length > 0) {
4348
- this._values = values.map(v => {
4349
- v = this.dateTimeAdapter.deserialize(v);
4350
- return this.getValidDate(v);
4351
- });
4352
- this.lastValueValid =
4353
- (!this._values[0] ||
4354
- this.dateTimeAdapter.isValid(this._values[0])) &&
4355
- (!this._values[1] ||
4356
- this.dateTimeAdapter.isValid(this._values[1]));
4465
+ const deserialized = values.map(v => this.dateTimeAdapter.deserialize(v));
4466
+ this.lastValueValid = deserialized.every(v => v == null || this.dateTimeAdapter.isValid(v));
4467
+ this._values = deserialized.map(v => this.getValidDate(v));
4357
4468
  }
4358
4469
  else {
4359
4470
  this._values = [];
4360
4471
  this.lastValueValid = true;
4361
4472
  }
4362
- // set the input property 'value'
4473
+ // Задаём свойство 'value' поля ввода
4363
4474
  this.formatNativeInputValue();
4364
4475
  this.valueChange.emit(this._values);
4365
4476
  }
@@ -4378,37 +4489,38 @@ class OwlDateTimeInputDirective {
4378
4489
  return true;
4379
4490
  }
4380
4491
  get owlDateTimeInputAriaOwns() {
4381
- return (this.dtPicker.opened && this.dtPicker.id) || null;
4492
+ return (this.dtPicker?.opened && this.dtPicker.id) || null;
4382
4493
  }
4383
4494
  get minIso8601() {
4384
- return this.min ? this.dateTimeAdapter.toIso8601(this.min) : null;
4495
+ return this.min != null ? this.dateTimeAdapter.toIso8601(this.min) : null;
4385
4496
  }
4386
4497
  get maxIso8601() {
4387
- return this.max ? this.dateTimeAdapter.toIso8601(this.max) : null;
4498
+ return this.max != null ? this.dateTimeAdapter.toIso8601(this.max) : null;
4388
4499
  }
4389
4500
  get owlDateTimeInputDisabled() {
4390
4501
  return this.disabled;
4391
4502
  }
4392
- constructor(elmRef, renderer, dateTimeAdapter, dateTimeFormats) {
4503
+ constructor(elmRef, renderer, dateTimeAdapter, dateTimeFormats, changeDetector) {
4393
4504
  this.elmRef = elmRef;
4394
4505
  this.renderer = renderer;
4395
4506
  this.dateTimeAdapter = dateTimeAdapter;
4396
4507
  this.dateTimeFormats = dateTimeFormats;
4508
+ this.changeDetector = changeDetector;
4397
4509
  /**
4398
- * The picker's select mode
4510
+ * Режим выбора даты
4399
4511
  */
4400
4512
  this._selectMode = 'single';
4401
4513
  /**
4402
- * The character to separate the 'from' and 'to' in input value
4514
+ * Символ, разделяющий начало ('from') и конец ('to') диапазона в поле ввода
4403
4515
  */
4404
4516
  this.rangeSeparator = '-';
4405
4517
  this._values = [];
4406
4518
  /**
4407
- * Callback to invoke when `change` event is fired on this `<input>`
4519
+ * Обработчик события `change` этого `<input>`
4408
4520
  * */
4409
4521
  this.dateTimeChange = new EventEmitter();
4410
4522
  /**
4411
- * Callback to invoke when an `input` event is fired on this `<input>`.
4523
+ * Обработчик события `input` этого `<input>`
4412
4524
  * */
4413
4525
  this.dateTimeInput = new EventEmitter();
4414
4526
  this.dtPickerSub = Subscription.EMPTY;
@@ -4417,18 +4529,18 @@ class OwlDateTimeInputDirective {
4417
4529
  this.onModelChange = () => { };
4418
4530
  this.onModelTouched = () => { };
4419
4531
  this.validatorOnChange = () => { };
4420
- /** The form control validator for whether the input parses. */
4532
+ /** Валидатор корректности разбора введённого значения */
4421
4533
  this.parseValidator = () => {
4422
4534
  return this.lastValueValid
4423
4535
  ? null
4424
4536
  : { owlDateTimeParse: { text: this.elmRef.nativeElement.value } };
4425
4537
  };
4426
- /** The form control validator for the min date. */
4538
+ /** Валидатор минимальной даты */
4427
4539
  this.minValidator = (control) => {
4428
4540
  if (this.isInSingleMode) {
4429
4541
  const controlValue = this.getValidDate(this.dateTimeAdapter.deserialize(control.value));
4430
- return !this.min ||
4431
- !controlValue ||
4542
+ return this.min == null ||
4543
+ controlValue == null ||
4432
4544
  this.dateTimeAdapter.compare(this.min, controlValue) <= 0
4433
4545
  ? null
4434
4546
  : { owlDateTimeMin: { min: this.min, actual: controlValue } };
@@ -4436,10 +4548,8 @@ class OwlDateTimeInputDirective {
4436
4548
  else if (this.isInRangeMode && control.value) {
4437
4549
  const controlValueFrom = this.getValidDate(this.dateTimeAdapter.deserialize(control.value[0]));
4438
4550
  const controlValueTo = this.getValidDate(this.dateTimeAdapter.deserialize(control.value[1]));
4439
- return !this.min ||
4440
- !controlValueFrom ||
4441
- !controlValueTo ||
4442
- this.dateTimeAdapter.compare(this.min, controlValueFrom) <= 0
4551
+ return this.min == null ||
4552
+ [controlValueFrom, controlValueTo].every(value => value == null || this.dateTimeAdapter.compare(this.min, value) <= 0)
4443
4553
  ? null
4444
4554
  : {
4445
4555
  owlDateTimeMin: {
@@ -4449,12 +4559,12 @@ class OwlDateTimeInputDirective {
4449
4559
  };
4450
4560
  }
4451
4561
  };
4452
- /** The form control validator for the max date. */
4562
+ /** Валидатор максимальной даты */
4453
4563
  this.maxValidator = (control) => {
4454
4564
  if (this.isInSingleMode) {
4455
4565
  const controlValue = this.getValidDate(this.dateTimeAdapter.deserialize(control.value));
4456
- return !this.max ||
4457
- !controlValue ||
4566
+ return this.max == null ||
4567
+ controlValue == null ||
4458
4568
  this.dateTimeAdapter.compare(this.max, controlValue) >= 0
4459
4569
  ? null
4460
4570
  : { owlDateTimeMax: { max: this.max, actual: controlValue } };
@@ -4462,10 +4572,8 @@ class OwlDateTimeInputDirective {
4462
4572
  else if (this.isInRangeMode && control.value) {
4463
4573
  const controlValueFrom = this.getValidDate(this.dateTimeAdapter.deserialize(control.value[0]));
4464
4574
  const controlValueTo = this.getValidDate(this.dateTimeAdapter.deserialize(control.value[1]));
4465
- return !this.max ||
4466
- !controlValueFrom ||
4467
- !controlValueTo ||
4468
- this.dateTimeAdapter.compare(this.max, controlValueTo) >= 0
4575
+ return this.max == null ||
4576
+ [controlValueFrom, controlValueTo].every(value => value == null || this.dateTimeAdapter.compare(this.max, value) >= 0)
4469
4577
  ? null
4470
4578
  : {
4471
4579
  owlDateTimeMax: {
@@ -4475,18 +4583,19 @@ class OwlDateTimeInputDirective {
4475
4583
  };
4476
4584
  }
4477
4585
  };
4478
- /** The form control validator for the date filter. */
4586
+ /** Валидатор соответствия фильтру дат */
4479
4587
  this.filterValidator = (control) => {
4480
- const controlValue = this.getValidDate(this.dateTimeAdapter.deserialize(control.value));
4481
- return !this._dateTimeFilter ||
4482
- !controlValue ||
4483
- this._dateTimeFilter(controlValue)
4484
- ? null
4485
- : { owlDateTimeFilter: true };
4588
+ const values = this.isInRangeMode && Array.isArray(control.value)
4589
+ ? control.value
4590
+ : [control.value];
4591
+ return !this._dateTimeFilter || values.every(value => {
4592
+ const date = this.getValidDate(this.dateTimeAdapter.deserialize(value));
4593
+ return date == null || this._dateTimeFilter(date);
4594
+ }) ? null : { owlDateTimeFilter: true };
4486
4595
  };
4487
4596
  /**
4488
- * The form control validator for the range.
4489
- * Check whether the 'before' value is before the 'to' value
4597
+ * Валидатор диапазона дат
4598
+ * Проверяет, что начало диапазона находится не позже конца ('to')
4490
4599
  * */
4491
4600
  this.rangeValidator = (control) => {
4492
4601
  if (this.isInSingleMode || !control.value) {
@@ -4494,15 +4603,15 @@ class OwlDateTimeInputDirective {
4494
4603
  }
4495
4604
  const controlValueFrom = this.getValidDate(this.dateTimeAdapter.deserialize(control.value[0]));
4496
4605
  const controlValueTo = this.getValidDate(this.dateTimeAdapter.deserialize(control.value[1]));
4497
- return !controlValueFrom ||
4498
- !controlValueTo ||
4606
+ return controlValueFrom == null ||
4607
+ controlValueTo == null ||
4499
4608
  this.dateTimeAdapter.compare(controlValueFrom, controlValueTo) <= 0
4500
4609
  ? null
4501
4610
  : { owlDateTimeRange: true };
4502
4611
  };
4503
4612
  /**
4504
- * The form control validator for the range when required.
4505
- * Check whether the 'before' and 'to' values are present
4613
+ * Валидатор обязательного диапазона дат
4614
+ * Проверяет наличие обеих границ диапазона
4506
4615
  * */
4507
4616
  this.requiredRangeValidator = (control) => {
4508
4617
  if (this.isInSingleMode || !control.value || !this.required) {
@@ -4510,12 +4619,12 @@ class OwlDateTimeInputDirective {
4510
4619
  }
4511
4620
  const controlValueFrom = this.getValidDate(this.dateTimeAdapter.deserialize(control.value[0]));
4512
4621
  const controlValueTo = this.getValidDate(this.dateTimeAdapter.deserialize(control.value[1]));
4513
- return !controlValueFrom ||
4514
- !controlValueTo
4622
+ return controlValueFrom == null ||
4623
+ controlValueTo == null
4515
4624
  ? { owlRequiredDateTimeRange: [controlValueFrom, controlValueTo] }
4516
4625
  : null;
4517
4626
  };
4518
- /** The combined form control validator for this input. */
4627
+ /** Объединённый валидатор этого поля ввода */
4519
4628
  this.validator = Validators.compose([
4520
4629
  this.parseValidator,
4521
4630
  this.minValidator,
@@ -4524,9 +4633,9 @@ class OwlDateTimeInputDirective {
4524
4633
  this.rangeValidator,
4525
4634
  this.requiredRangeValidator
4526
4635
  ]);
4527
- /** Emits when the value changes (either due to user input or programmatic change). */
4636
+ /** Событие изменения значения пользователем или программно */
4528
4637
  this.valueChange = new EventEmitter();
4529
- /** Emits when the disabled state has changed */
4638
+ /** Событие изменения состояния disabled */
4530
4639
  this.disabledChange = new EventEmitter();
4531
4640
  if (!this.dateTimeAdapter) {
4532
4641
  throw Error(`OwlDateTimePicker: No provider found for DateTimeAdapter. You must import ` +
@@ -4597,7 +4706,7 @@ class OwlDateTimeInputDirective {
4597
4706
  this.validatorOnChange = fn;
4598
4707
  }
4599
4708
  /**
4600
- * Open the picker when user hold alt + DOWN_ARROW
4709
+ * Открывает компонент выбора по сочетанию Alt + ArrowDown
4601
4710
  * */
4602
4711
  handleKeydownOnHost(event) {
4603
4712
  if (event.altKey && event.keyCode === DOWN_ARROW) {
@@ -4635,11 +4744,11 @@ class OwlDateTimeInputDirective {
4635
4744
  });
4636
4745
  }
4637
4746
  /**
4638
- * Set the native input property 'value'
4747
+ * Задаёт свойство 'value' нативного поля ввода
4639
4748
  */
4640
4749
  formatNativeInputValue() {
4641
4750
  if (this.isInSingleMode) {
4642
- this.renderer.setProperty(this.elmRef.nativeElement, 'value', this._value
4751
+ this.renderer.setProperty(this.elmRef.nativeElement, 'value', this._value != null
4643
4752
  ? this.dateTimeAdapter.format(this._value, this.dtPicker.formatString)
4644
4753
  : '');
4645
4754
  }
@@ -4647,10 +4756,10 @@ class OwlDateTimeInputDirective {
4647
4756
  if (this._values && this.values.length > 0) {
4648
4757
  const from = this._values[0];
4649
4758
  const to = this._values[1];
4650
- const fromFormatted = from
4759
+ const fromFormatted = from != null
4651
4760
  ? this.dateTimeAdapter.format(from, this.dtPicker.formatString)
4652
4761
  : '';
4653
- const toFormatted = to
4762
+ const toFormatted = to != null
4654
4763
  ? this.dateTimeAdapter.format(to, this.dtPicker.formatString)
4655
4764
  : '';
4656
4765
  if (!fromFormatted && !toFormatted) {
@@ -4679,7 +4788,7 @@ class OwlDateTimeInputDirective {
4679
4788
  return;
4680
4789
  }
4681
4790
  /**
4682
- * Register the relationship between this input and its picker component
4791
+ * Регистрирует связь между полем ввода и компонентом выбора
4683
4792
  */
4684
4793
  registerDateTimePicker(picker) {
4685
4794
  if (picker) {
@@ -4688,7 +4797,7 @@ class OwlDateTimeInputDirective {
4688
4797
  }
4689
4798
  }
4690
4799
  /**
4691
- * Convert a given obj to a valid date object
4800
+ * Преобразует указанный объект в корректный объект даты
4692
4801
  */
4693
4802
  getValidDate(obj) {
4694
4803
  return this.dateTimeAdapter.isDateInstance(obj) &&
@@ -4697,14 +4806,14 @@ class OwlDateTimeInputDirective {
4697
4806
  : null;
4698
4807
  }
4699
4808
  /**
4700
- * Convert a time string to a date-time string
4701
- * When pickerType is 'timer', the value in the picker's input is a time string.
4702
- * The dateTimeAdapter parse fn could not parse a time string to a Date Object.
4703
- * Therefore we need this fn to convert a time string to a date-time string.
4809
+ * Преобразует строку времени в строку даты и времени
4810
+ * При pickerType равном 'timer' поле ввода содержит строку времени
4811
+ * Метод parse адаптера dateTimeAdapter не может разобрать строку времени как объект даты
4812
+ * Поэтому эта функция преобразует строку времени в строку даты и времени
4704
4813
  */
4705
4814
  convertTimeStringToDateTimeString(timeString, dateTime) {
4706
4815
  if (timeString) {
4707
- const v = dateTime || this.dateTimeAdapter.now();
4816
+ const v = dateTime ?? this.dateTimeAdapter.now();
4708
4817
  const dateString = this.dateTimeAdapter.format(v, this.dateTimeFormats.datePickerInput);
4709
4818
  return dateString + ' ' + timeString;
4710
4819
  }
@@ -4713,7 +4822,7 @@ class OwlDateTimeInputDirective {
4713
4822
  }
4714
4823
  }
4715
4824
  /**
4716
- * Handle input change in single mode
4825
+ * Обрабатывает изменение поля ввода в режиме single
4717
4826
  */
4718
4827
  changeInputInSingleMode(inputValue) {
4719
4828
  let value = inputValue;
@@ -4721,10 +4830,10 @@ class OwlDateTimeInputDirective {
4721
4830
  value = this.convertTimeStringToDateTimeString(value, this.value);
4722
4831
  }
4723
4832
  let result = this.dateTimeAdapter.parse(value, this.dateTimeFormats.parseInput);
4724
- this.lastValueValid = !result || this.dateTimeAdapter.isValid(result);
4833
+ this.lastValueValid = result == null || this.dateTimeAdapter.isValid(result);
4725
4834
  result = this.getValidDate(result);
4726
- // if the newValue is the same as the oldValue, we intend to not fire the valueChange event
4727
- // result equals to null means there is input event, but the input value is invalid
4835
+ // Если newValue совпадает с oldValue, не отправляем событие valueChange
4836
+ // result равный null означает, что событие ввода произошло, но значение недопустимо
4728
4837
  if (!this.isSameValue(result, this._value) || result === null) {
4729
4838
  this._value = result;
4730
4839
  this.valueChange.emit(result);
@@ -4737,7 +4846,7 @@ class OwlDateTimeInputDirective {
4737
4846
  }
4738
4847
  }
4739
4848
  /**
4740
- * Handle input change in rangeFrom or rangeTo mode
4849
+ * Обрабатывает изменение поля ввода в режиме rangeFrom или rangeTo
4741
4850
  */
4742
4851
  changeInputInRangeFromToMode(inputValue) {
4743
4852
  const originalValue = this._selectMode === 'rangeFrom'
@@ -4747,9 +4856,9 @@ class OwlDateTimeInputDirective {
4747
4856
  inputValue = this.convertTimeStringToDateTimeString(inputValue, originalValue);
4748
4857
  }
4749
4858
  let result = this.dateTimeAdapter.parse(inputValue, this.dateTimeFormats.parseInput);
4750
- this.lastValueValid = !result || this.dateTimeAdapter.isValid(result);
4859
+ this.lastValueValid = result == null || this.dateTimeAdapter.isValid(result);
4751
4860
  result = this.getValidDate(result);
4752
- // if the newValue is the same as the oldValue, we intend to not fire the valueChange event
4861
+ // Если newValue совпадает с oldValue, не отправляем событие valueChange
4753
4862
  if ((this._selectMode === 'rangeFrom' &&
4754
4863
  this.isSameValue(result, this._values[0]) &&
4755
4864
  result) ||
@@ -4771,10 +4880,11 @@ class OwlDateTimeInputDirective {
4771
4880
  });
4772
4881
  }
4773
4882
  /**
4774
- * Handle input change in range mode
4883
+ * Обрабатывает изменение поля ввода в режиме range
4775
4884
  */
4776
4885
  changeInputInRangeMode(inputValue) {
4777
- const selecteds = inputValue.split(this.rangeSeparator);
4886
+ const wasValid = this.lastValueValid;
4887
+ const selecteds = inputValue.split(this.rangeSeparator).map(value => value.trim());
4778
4888
  let fromString = selecteds[0];
4779
4889
  let toString = selecteds[1];
4780
4890
  if (this.dtPicker.pickerType === 'timer') {
@@ -4784,13 +4894,14 @@ class OwlDateTimeInputDirective {
4784
4894
  let from = this.dateTimeAdapter.parse(fromString, this.dateTimeFormats.parseInput);
4785
4895
  let to = this.dateTimeAdapter.parse(toString, this.dateTimeFormats.parseInput);
4786
4896
  this.lastValueValid =
4787
- (!from || this.dateTimeAdapter.isValid(from)) &&
4788
- (!to || this.dateTimeAdapter.isValid(to));
4897
+ (from == null || this.dateTimeAdapter.isValid(from)) &&
4898
+ (to == null || this.dateTimeAdapter.isValid(to));
4789
4899
  from = this.getValidDate(from);
4790
4900
  to = this.getValidDate(to);
4791
- // if the newValue is the same as the oldValue, we intend to not fire the valueChange event
4901
+ // Если newValue совпадает с oldValue, не отправляем событие valueChange
4792
4902
  if (!this.isSameValue(from, this._values[0]) ||
4793
4903
  !this.isSameValue(to, this._values[1]) ||
4904
+ wasValid !== this.lastValueValid ||
4794
4905
  (from === null && to === null)) {
4795
4906
  this._values = [from, to];
4796
4907
  this.valueChange.emit(this._values);
@@ -4803,16 +4914,16 @@ class OwlDateTimeInputDirective {
4803
4914
  }
4804
4915
  }
4805
4916
  /**
4806
- * Check if the two value is the same
4917
+ * Проверяет равенство двух значений
4807
4918
  */
4808
4919
  isSameValue(first, second) {
4809
- if (first && second) {
4920
+ if (first != null && second != null) {
4810
4921
  return this.dateTimeAdapter.compare(first, second) === 0;
4811
4922
  }
4812
4923
  return first === second;
4813
4924
  }
4814
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlDateTimeInputDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DateTimeAdapter, optional: true }, { token: OWL_DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
4815
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: OwlDateTimeInputDirective, isStandalone: false, selector: "input[owlDateTime]", inputs: { required: "required", owlDateTime: "owlDateTime", owlDateTimeFilter: "owlDateTimeFilter", _disabled: "_disabled", min: "min", max: "max", selectMode: "selectMode", rangeSeparator: "rangeSeparator", value: "value", values: "values" }, outputs: { dateTimeChange: "dateTimeChange", dateTimeInput: "dateTimeInput" }, host: { listeners: { "keydown": "handleKeydownOnHost($event)", "blur": "handleBlurOnHost($event)", "input": "handleInputOnHost($event)", "change": "handleChangeOnHost($event)" }, properties: { "attr.aria-haspopup": "owlDateTimeInputAriaHaspopup", "attr.aria-owns": "owlDateTimeInputAriaOwns", "attr.min": "minIso8601", "attr.max": "maxIso8601", "disabled": "owlDateTimeInputDisabled" } }, providers: [
4925
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlDateTimeInputDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DateTimeAdapter, optional: true }, { token: OWL_DATE_TIME_FORMATS, optional: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
4926
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: OwlDateTimeInputDirective, isStandalone: false, selector: "input[owlDateTime]", inputs: { required: "required", owlDateTime: "owlDateTime", owlDateTimeFilter: "owlDateTimeFilter", disabled: "disabled", min: "min", max: "max", selectMode: "selectMode", rangeSeparator: "rangeSeparator", value: "value", values: "values" }, outputs: { dateTimeChange: "dateTimeChange", dateTimeInput: "dateTimeInput" }, host: { listeners: { "keydown": "handleKeydownOnHost($event)", "blur": "handleBlurOnHost($event)", "input": "handleInputOnHost($event)", "change": "handleChangeOnHost($event)" }, properties: { "attr.aria-haspopup": "owlDateTimeInputAriaHaspopup", "attr.aria-owns": "owlDateTimeInputAriaOwns", "attr.min": "minIso8601", "attr.max": "maxIso8601", "disabled": "owlDateTimeInputDisabled" } }, providers: [
4816
4927
  OWL_DATETIME_VALUE_ACCESSOR$1,
4817
4928
  OWL_DATETIME_VALIDATORS,
4818
4929
  ], exportAs: ["owlDateTimeInput"], ngImport: i0 }); }
@@ -4846,13 +4957,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
4846
4957
  }, {
4847
4958
  type: Inject,
4848
4959
  args: [OWL_DATE_TIME_FORMATS]
4849
- }] }], propDecorators: { required: [{
4960
+ }] }, { type: i0.ChangeDetectorRef }], propDecorators: { required: [{
4850
4961
  type: Input
4851
4962
  }], owlDateTime: [{
4852
4963
  type: Input
4853
4964
  }], owlDateTimeFilter: [{
4854
4965
  type: Input
4855
- }], _disabled: [{
4966
+ }], disabled: [{
4856
4967
  type: Input
4857
4968
  }], min: [{
4858
4969
  type: Input
@@ -4921,6 +5032,8 @@ class OwlDateTimeInlineComponent extends OwlDateTime {
4921
5032
  }
4922
5033
  set disabled(value) {
4923
5034
  this._disabled = coerceBooleanProperty(value);
5035
+ this.changeDetector.markForCheck();
5036
+ this.container?.refreshView();
4924
5037
  }
4925
5038
  get selectMode() {
4926
5039
  return this._selectMode;
@@ -4935,18 +5048,18 @@ class OwlDateTimeInlineComponent extends OwlDateTime {
4935
5048
  this._selectMode = mode;
4936
5049
  }
4937
5050
  get startAt() {
4938
- if (this._startAt) {
5051
+ if (this._startAt != null) {
4939
5052
  return this._startAt;
4940
5053
  }
4941
5054
  if (this.selectMode === 'single') {
4942
- return this.value || null;
5055
+ return this.value ?? null;
4943
5056
  }
4944
5057
  else if (this.selectMode === 'range' ||
4945
5058
  this.selectMode === 'rangeFrom') {
4946
- return this.values[0] || null;
5059
+ return this.values[0] ?? null;
4947
5060
  }
4948
5061
  else if (this.selectMode === 'rangeTo') {
4949
- return this.values[1] || null;
5062
+ return this.values[1] ?? null;
4950
5063
  }
4951
5064
  else {
4952
5065
  return null;
@@ -4956,15 +5069,15 @@ class OwlDateTimeInlineComponent extends OwlDateTime {
4956
5069
  this._startAt = this.getValidDate(this.dateTimeAdapter.deserialize(date));
4957
5070
  }
4958
5071
  get endAt() {
4959
- if (this._endAt) {
5072
+ if (this._endAt != null) {
4960
5073
  return this._endAt;
4961
5074
  }
4962
5075
  if (this.selectMode === 'single') {
4963
- return this.value || null;
5076
+ return this.value ?? null;
4964
5077
  }
4965
5078
  else if (this.selectMode === 'range' ||
4966
5079
  this.selectMode === 'rangeFrom') {
4967
- return this.values[1] || null;
5080
+ return this.values[1] ?? null;
4968
5081
  }
4969
5082
  else {
4970
5083
  return null;
@@ -4980,14 +5093,14 @@ class OwlDateTimeInlineComponent extends OwlDateTime {
4980
5093
  this._dateTimeFilter = filter;
4981
5094
  }
4982
5095
  get minDateTime() {
4983
- return this._min || null;
5096
+ return this._min ?? null;
4984
5097
  }
4985
5098
  set minDateTime(value) {
4986
5099
  this._min = this.getValidDate(this.dateTimeAdapter.deserialize(value));
4987
5100
  this.changeDetector.markForCheck();
4988
5101
  }
4989
5102
  get maxDateTime() {
4990
- return this._max || null;
5103
+ return this._max ?? null;
4991
5104
  }
4992
5105
  set maxDateTime(value) {
4993
5106
  this._max = this.getValidDate(this.dateTimeAdapter.deserialize(value));
@@ -5010,7 +5123,7 @@ class OwlDateTimeInlineComponent extends OwlDateTime {
5010
5123
  values = values.map(v => {
5011
5124
  v = this.dateTimeAdapter.deserialize(v);
5012
5125
  v = this.getValidDate(v);
5013
- return v ? this.dateTimeAdapter.clone(v) : null;
5126
+ return v != null ? this.dateTimeAdapter.clone(v) : null;
5014
5127
  });
5015
5128
  this._values = [...values];
5016
5129
  this.selecteds = [...values];
@@ -5057,27 +5170,27 @@ class OwlDateTimeInlineComponent extends OwlDateTime {
5057
5170
  this.dateTimeAdapter = dateTimeAdapter;
5058
5171
  this.dateTimeFormats = dateTimeFormats;
5059
5172
  /**
5060
- * Set the type of the dateTime picker
5061
- * 'both' -- show both calendar and timer
5062
- * 'calendar' -- show only calendar
5063
- * 'timer' -- show only timer
5173
+ * Задаёт тип компонента выбора даты и времени:
5174
+ * 'both' — календарь и выбор времени
5175
+ * 'calendar' — только календарь
5176
+ * 'timer' — только выбор времени
5064
5177
  */
5065
5178
  this._pickerType = 'both';
5066
5179
  this._disabled = false;
5067
5180
  this._selectMode = 'single';
5068
5181
  this._values = [];
5069
5182
  /**
5070
- * Emits selected year in multi-year view
5071
- * This doesn't imply a change on the selected date.
5183
+ * Передаёт выбранный год в представлении нескольких лет
5184
+ * При этом выбранная дата не изменяется
5072
5185
  * */
5073
5186
  this.yearSelected = new EventEmitter();
5074
5187
  /**
5075
- * Emits selected month in year view
5076
- * This doesn't imply a change on the selected date.
5188
+ * Передаёт выбранный месяц в представлении года
5189
+ * При этом выбранная дата не изменяется
5077
5190
  * */
5078
5191
  this.monthSelected = new EventEmitter();
5079
5192
  /**
5080
- * Emits selected date
5193
+ * Передаёт выбранную дату
5081
5194
  * */
5082
5195
  this.dateSelected = new EventEmitter();
5083
5196
  this._selecteds = [];
@@ -5120,30 +5233,31 @@ class OwlDateTimeInlineComponent extends OwlDateTime {
5120
5233
  this.onModelTouched();
5121
5234
  }
5122
5235
  /**
5123
- * Emits the selected year in multi-year view
5236
+ * Передаёт выбранный год в представлении нескольких лет
5124
5237
  * */
5125
5238
  selectYear(normalizedYear) {
5126
5239
  this.yearSelected.emit(normalizedYear);
5127
5240
  }
5128
5241
  /**
5129
- * Emits selected month in year view
5242
+ * Передаёт выбранный месяц в представлении года
5130
5243
  * */
5131
5244
  selectMonth(normalizedMonth) {
5132
5245
  this.monthSelected.emit(normalizedMonth);
5133
5246
  }
5134
5247
  /**
5135
- * Emits the selected date
5248
+ * Передаёт выбранную дату
5136
5249
  * */
5137
5250
  selectDate(normalizedDate) {
5138
5251
  this.dateSelected.emit(normalizedDate);
5139
5252
  }
5140
5253
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlDateTimeInlineComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: DateTimeAdapter, optional: true }, { token: OWL_DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
5141
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: OwlDateTimeInlineComponent, isStandalone: false, selector: "owl-date-time-inline", inputs: { pickerType: "pickerType", disabled: "disabled", selectMode: "selectMode", startAt: "startAt", endAt: "endAt", dateTimeFilter: ["owlDateTimeFilter", "dateTimeFilter"], minDateTime: ["min", "minDateTime"], maxDateTime: ["max", "maxDateTime"], value: "value", values: "values" }, outputs: { yearSelected: "yearSelected", monthSelected: "monthSelected", dateSelected: "dateSelected" }, host: { properties: { "class.owl-dt-inline": "owlDTInlineClass" } }, providers: [OWL_DATETIME_VALUE_ACCESSOR], viewQueries: [{ propertyName: "container", first: true, predicate: OwlDateTimeContainerComponent, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<owl-date-time-container></owl-date-time-container>", styles: [":host{--container-enter-animation-duration: 0;--container-leave-animation-duration: 0}\n"], dependencies: [{ kind: "component", type: OwlDateTimeContainerComponent, selector: "owl-date-time-container", exportAs: ["owlDateTimeContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5254
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: OwlDateTimeInlineComponent, isStandalone: false, selector: "owl-date-time-inline", inputs: { pickerType: "pickerType", disabled: "disabled", selectMode: "selectMode", startAt: "startAt", endAt: "endAt", dateTimeFilter: ["owlDateTimeFilter", "dateTimeFilter"], minDateTime: ["min", "minDateTime"], maxDateTime: ["max", "maxDateTime"], value: "value", values: "values" }, outputs: { yearSelected: "yearSelected", monthSelected: "monthSelected", dateSelected: "dateSelected" }, host: { properties: { "class.owl-dt-inline": "owlDTInlineClass", "attr.aria-disabled": "disabled || null" } }, providers: [OWL_DATETIME_VALUE_ACCESSOR], viewQueries: [{ propertyName: "container", first: true, predicate: OwlDateTimeContainerComponent, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<owl-date-time-container></owl-date-time-container>", styles: [":host{--container-enter-animation-duration: 0;--container-leave-animation-duration: 0}\n"], dependencies: [{ kind: "component", type: OwlDateTimeContainerComponent, selector: "owl-date-time-container", exportAs: ["owlDateTimeContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5142
5255
  }
5143
5256
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: OwlDateTimeInlineComponent, decorators: [{
5144
5257
  type: Component,
5145
5258
  args: [{ selector: 'owl-date-time-inline', host: {
5146
- '[class.owl-dt-inline]': 'owlDTInlineClass'
5259
+ '[class.owl-dt-inline]': 'owlDTInlineClass',
5260
+ '[attr.aria-disabled]': 'disabled || null'
5147
5261
  }, standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, providers: [OWL_DATETIME_VALUE_ACCESSOR], template: "<owl-date-time-container></owl-date-time-container>", styles: [":host{--container-enter-animation-duration: 0;--container-leave-animation-duration: 0}\n"] }]
5148
5262
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: DateTimeAdapter, decorators: [{
5149
5263
  type: Optional
@@ -5291,10 +5405,10 @@ class LuxonDateTimeAdapter extends DateTimeAdapter {
5291
5405
  this.owlDateTimeLocale = owlDateTimeLocale;
5292
5406
  this.firstMonthOfTheYear = 0;
5293
5407
  /**
5294
- * 0 - Sunday
5295
- * 1 - Monday
5408
+ * 0 - воскресенье
5409
+ * 1 - понедельник
5296
5410
  * ...
5297
- * 6 - Saturday
5411
+ * 6 - суббота
5298
5412
  */
5299
5413
  this.firstDayOfTheWeek = 0;
5300
5414
  this.setLocale(owlDateTimeLocale || Settings.defaultLocale || 'ru');
@@ -5303,25 +5417,25 @@ class LuxonDateTimeAdapter extends DateTimeAdapter {
5303
5417
  return date.year;
5304
5418
  }
5305
5419
  /**
5306
- * Picker expects month index:
5307
- * 0 - January
5308
- * 11 - December
5420
+ * Компонент выбора даты ожидает индекс месяца:
5421
+ * 0 - январь
5422
+ * 11 - декабрь
5309
5423
  *
5310
- * Luxon uses:
5311
- * 1 - January
5312
- * 12 - December
5424
+ * Luxon использует:
5425
+ * 1 - январь
5426
+ * 12 - декабрь
5313
5427
  */
5314
5428
  getMonth(date) {
5315
5429
  return date.month - 1;
5316
5430
  }
5317
5431
  /**
5318
- * Picker expects:
5319
- * 0 - Sunday
5320
- * 6 - Saturday
5432
+ * Компонент выбора даты ожидает:
5433
+ * 0 - воскресенье
5434
+ * 6 - суббота
5321
5435
  *
5322
- * Luxon weekday:
5323
- * 1 - Monday
5324
- * 7 - Sunday
5436
+ * День недели в Luxon:
5437
+ * 1 - понедельник
5438
+ * 7 - воскресенье
5325
5439
  */
5326
5440
  getDay(date) {
5327
5441
  return date.weekday % 7;
@@ -5346,9 +5460,9 @@ class LuxonDateTimeAdapter extends DateTimeAdapter {
5346
5460
  }
5347
5461
  differenceInCalendarDays(dateLeft, dateRight) {
5348
5462
  if (this.isValid(dateLeft) && this.isValid(dateRight)) {
5349
- return Math.round(dateLeft.startOf('day').diff(dateRight.startOf('day'), 'days').days);
5463
+ return Math.round(DateTime.utc(dateLeft.year, dateLeft.month, dateLeft.day).diff(DateTime.utc(dateRight.year, dateRight.month, dateRight.day), 'days').days);
5350
5464
  }
5351
- return null;
5465
+ return Number.NaN;
5352
5466
  }
5353
5467
  getYearName(date) {
5354
5468
  return date.setLocale(this.locale).toFormat('yyyy');
@@ -5358,8 +5472,8 @@ class LuxonDateTimeAdapter extends DateTimeAdapter {
5358
5472
  }
5359
5473
  getDayOfWeekNames(style) {
5360
5474
  const weekdays = Info.weekdays(style, { locale: this.locale });
5361
- // Luxon returns Monday..Sunday.
5362
- // Existing picker expects Sunday..Saturday.
5475
+ // Luxon возвращает дни недели от понедельника до воскресенья
5476
+ // Компонент выбора даты ожидает порядок от воскресенья до субботы
5363
5477
  return [
5364
5478
  weekdays[6],
5365
5479
  ...weekdays.slice(0, 6),
@@ -5413,6 +5527,9 @@ class LuxonDateTimeAdapter extends DateTimeAdapter {
5413
5527
  return date.set({ second: amount });
5414
5528
  }
5415
5529
  createDate(year, month, date, hours = 0, minutes = 0, seconds = 0) {
5530
+ if (hours < 0 || hours > 23) {
5531
+ throw Error(`LuxonDateTimeAdapter: Invalid hours "${hours}". Hours must be between 0 and 23.`);
5532
+ }
5416
5533
  const result = DateTime.local(year, month + 1, date, hours, minutes, seconds, 0).setLocale(this.locale);
5417
5534
  if (!result.isValid) {
5418
5535
  throw Error(`LuxonDateTimeAdapter: Invalid date "${date}" for month with index "${month}".`);
@@ -5452,7 +5569,7 @@ class LuxonDateTimeAdapter extends DateTimeAdapter {
5452
5569
  if (typeof value !== 'string') {
5453
5570
  return this.invalid();
5454
5571
  }
5455
- const formats = Array.isArray(parseFormat) ? parseFormat : [parseFormat];
5572
+ const formats = Array.isArray(parseFormat) ? parseFormat : parseFormat ? [parseFormat] : [];
5456
5573
  for (const format of formats) {
5457
5574
  const parsed = DateTime.fromFormat(value, format, {
5458
5575
  locale: this.locale,
@@ -5570,11 +5687,11 @@ class UnixTimestampDateTimeAdapter extends DateTimeAdapter {
5570
5687
  this.owlDateTimeLocale = owlDateTimeLocale;
5571
5688
  this.firstMonthOfTheYear = 0;
5572
5689
  /**
5573
- * Picker expects:
5574
- * 0 - Sunday
5575
- * 1 - Monday
5690
+ * Компонент выбора даты ожидает:
5691
+ * 0 - воскресенье
5692
+ * 1 - понедельник
5576
5693
  * ...
5577
- * 6 - Saturday
5694
+ * 6 - суббота
5578
5695
  */
5579
5696
  this.firstDayOfTheWeek = 0;
5580
5697
  this.setLocale(owlDateTimeLocale || Settings.defaultLocale || 'ru');
@@ -5583,25 +5700,25 @@ class UnixTimestampDateTimeAdapter extends DateTimeAdapter {
5583
5700
  return this.fromTimestamp(date).year;
5584
5701
  }
5585
5702
  /**
5586
- * Picker expects:
5587
- * 0 - January
5588
- * 11 - December
5703
+ * Компонент выбора даты ожидает:
5704
+ * 0 - январь
5705
+ * 11 - декабрь
5589
5706
  *
5590
- * Luxon uses:
5591
- * 1 - January
5592
- * 12 - December
5707
+ * Luxon использует:
5708
+ * 1 - январь
5709
+ * 12 - декабрь
5593
5710
  */
5594
5711
  getMonth(date) {
5595
5712
  return this.fromTimestamp(date).month - 1;
5596
5713
  }
5597
5714
  /**
5598
- * Picker expects:
5599
- * 0 - Sunday
5600
- * 6 - Saturday
5715
+ * Компонент выбора даты ожидает:
5716
+ * 0 - воскресенье
5717
+ * 6 - суббота
5601
5718
  *
5602
- * Luxon weekday:
5603
- * 1 - Monday
5604
- * 7 - Sunday
5719
+ * День недели в Luxon:
5720
+ * 1 - понедельник
5721
+ * 7 - воскресенье
5605
5722
  */
5606
5723
  getDay(date) {
5607
5724
  return this.fromTimestamp(date).weekday % 7;
@@ -5640,8 +5757,8 @@ class UnixTimestampDateTimeAdapter extends DateTimeAdapter {
5640
5757
  }
5641
5758
  getDayOfWeekNames(style) {
5642
5759
  const weekdays = Info.weekdays(style, { locale: this.locale });
5643
- // Luxon returns Monday..Sunday.
5644
- // Existing picker expects Sunday..Saturday.
5760
+ // Luxon возвращает дни недели от понедельника до воскресенья
5761
+ // Компонент выбора даты ожидает порядок от воскресенья до субботы
5645
5762
  return [
5646
5763
  weekdays[6],
5647
5764
  ...weekdays.slice(0, 6),
@@ -5666,7 +5783,7 @@ class UnixTimestampDateTimeAdapter extends DateTimeAdapter {
5666
5783
  return this.fromTimestamp(dateLeft).hasSame(this.fromTimestamp(dateRight), 'day');
5667
5784
  }
5668
5785
  isValid(date) {
5669
- return typeof date === 'number' && !Number.isNaN(date);
5786
+ return typeof date === 'number' && Number.isFinite(date) && this.fromTimestamp(date).isValid;
5670
5787
  }
5671
5788
  invalid() {
5672
5789
  return NaN;
@@ -5705,6 +5822,9 @@ class UnixTimestampDateTimeAdapter extends DateTimeAdapter {
5705
5822
  .toMillis();
5706
5823
  }
5707
5824
  createDate(year, month, date, hours = 0, minutes = 0, seconds = 0) {
5825
+ if (hours < 0 || hours > 23) {
5826
+ throw Error(`UnixTimestampDateTimeAdapter: Invalid hours "${hours}". Hours must be between 0 and 23.`);
5827
+ }
5708
5828
  const result = DateTime.local(year, month + 1, date, hours, minutes, seconds, 0).setLocale(this.locale);
5709
5829
  if (!result.isValid) {
5710
5830
  throw Error(`UnixTimestampDateTimeAdapter: Invalid date "${date}" for month with index "${month}".`);
@@ -5720,9 +5840,9 @@ class UnixTimestampDateTimeAdapter extends DateTimeAdapter {
5720
5840
  .toMillis();
5721
5841
  }
5722
5842
  /**
5723
- * Hybrid formatter:
5724
- * - string => Luxon format, e.g. 'dd.MM.yyyy HH:mm'
5725
- * - Intl.DateTimeFormatOptions => old adapter-compatible formatting
5843
+ * Форматирование с поддержкой двух видов формата:
5844
+ * - string => формат Luxon, например 'dd.MM.yyyy HH:mm'
5845
+ * - Intl.DateTimeFormatOptions => форматирование, совместимое с прежним адаптером
5726
5846
  */
5727
5847
  format(date, displayFormat) {
5728
5848
  if (!this.isValid(date)) {