UNPKG

@danielmoncada/angular-datetime-picker

Version:
1,047 lines (1,037 loc) 284 kB
import * as i0 from '@angular/core'; import { Directive, Input, InjectionToken, inject, LOCALE_ID, Optional, Inject, Injectable, EventEmitter, Component, ChangeDetectionStrategy, Output, ViewChild, TemplateRef, SkipSelf, forwardRef, Pipe, NgModule } from '@angular/core'; import * as i3 from '@angular/common'; import { getLocaleFirstDayOfWeek, DOCUMENT, CommonModule } from '@angular/common'; import * as i4 from '@angular/cdk/a11y'; import { A11yModule } from '@angular/cdk/a11y'; import * as i1 from '@angular/cdk/overlay'; import { NoopScrollStrategy, Overlay, OverlayConfig, OverlayModule } from '@angular/cdk/overlay'; import { Subscription, of, merge, Subject, filter, take as take$1, defer } from 'rxjs'; import * as i2 from '@angular/cdk/portal'; import { BasePortalOutlet, CdkPortalOutlet, ComponentPortal, PortalInjector, PortalModule } from '@angular/cdk/portal'; import { ENTER, PAGE_DOWN, PAGE_UP, END, HOME, DOWN_ARROW, UP_ARROW, RIGHT_ARROW, LEFT_ARROW, SPACE, ESCAPE } from '@angular/cdk/keycodes'; import { coerceBooleanProperty, coerceNumberProperty, coerceArray } from '@angular/cdk/coercion'; import { take, debounceTime, startWith, filter as filter$1 } from 'rxjs/operators'; import { trigger, state, style, transition, group, query, animateChild, animate, keyframes } from '@angular/animations'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS, Validators } from '@angular/forms'; import * as i1$1 from '@angular/cdk/platform'; import { PlatformModule } from '@angular/cdk/platform'; /** * date-time-picker-trigger.directive */ class OwlDateTimeTriggerDirective { get disabled() { return this._disabled === undefined ? this.dtPicker.disabled : !!this._disabled; } set disabled(value) { this._disabled = value; } get owlDTTriggerDisabledClass() { return this.disabled; } constructor(changeDetector) { this.changeDetector = changeDetector; this.stateChanges = Subscription.EMPTY; } ngOnInit() { } ngOnChanges(changes) { if (changes.datepicker) { this.watchStateChanges(); } } ngAfterContentInit() { this.watchStateChanges(); } ngOnDestroy() { this.stateChanges.unsubscribe(); } handleClickOnHost(event) { if (this.dtPicker) { this.dtPicker.open(); event.stopPropagation(); } } watchStateChanges() { this.stateChanges.unsubscribe(); const inputDisabled = this.dtPicker && this.dtPicker.dtInput ? this.dtPicker.dtInput.disabledChange : of(); const pickerDisabled = this.dtPicker ? this.dtPicker.disabledChange : of(); this.stateChanges = merge([pickerDisabled, inputDisabled]) .subscribe(() => { this.changeDetector.markForCheck(); }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlDateTimeTriggerDirective, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.5", type: OwlDateTimeTriggerDirective, selector: "[owlDateTimeTrigger]", inputs: { dtPicker: ["owlDateTimeTrigger", "dtPicker"], disabled: "disabled" }, host: { listeners: { "click": "handleClickOnHost($event)" }, properties: { "class.owl-dt-trigger-disabled": "owlDTTriggerDisabledClass" } }, usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlDateTimeTriggerDirective, decorators: [{ type: Directive, args: [{ selector: '[owlDateTimeTrigger]', standalone: false, host: { '(click)': 'handleClickOnHost($event)', '[class.owl-dt-trigger-disabled]': 'owlDTTriggerDisabledClass' } }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { dtPicker: [{ type: Input, args: ['owlDateTimeTrigger'] }], disabled: [{ type: Input }] } }); /** * date-time-format.class */ /** InjectionToken for date time picker that can be used to override default format. */ const OWL_DATE_TIME_FORMATS = new InjectionToken('OWL_DATE_TIME_FORMATS'); /** * date-time-adapter.class */ /** InjectionToken for date time picker that can be used to override default locale code. */ const OWL_DATE_TIME_LOCALE = new InjectionToken('OWL_DATE_TIME_LOCALE', { providedIn: 'root', factory: OWL_DATE_TIME_LOCALE_FACTORY }); /** @docs-private */ function OWL_DATE_TIME_LOCALE_FACTORY() { return inject(LOCALE_ID); } /** Provider for OWL_DATE_TIME_LOCALE injection token. */ const OWL_DATE_TIME_LOCALE_PROVIDER = { provide: OWL_DATE_TIME_LOCALE, useExisting: LOCALE_ID }; class DateTimeAdapter { constructor() { /** A stream that emits when the locale changes. */ this._localeChanges = new Subject(); this.firstMonthOfTheYear = 0; this.firstDayOfTheWeek = 0; /** total milliseconds in a day. */ this.millisecondsInDay = 86400000; /** total milliseconds in a minute. */ this.milliseondsInMinute = 60000; } get localeChanges() { return this._localeChanges; } /** * Compare two given dates * 1 if the first date is after the second, * -1 if the first date is before the second * 0 if dates are equal. * */ compare(first, second) { if (!this.isValid(first) || !this.isValid(second)) { throw Error('JSNativeDate: Cannot compare invalid dates.'); } const dateFirst = this.clone(first); const dateSecond = this.clone(second); const diff = this.getTime(dateFirst) - this.getTime(dateSecond); if (diff < 0) { return -1; } else if (diff > 0) { return 1; } else { // Return 0 if diff is 0; return NaN if diff is NaN return diff; } } /** * Check if two given dates are in the same year * 1 if the first date's year is after the second, * -1 if the first date's year is before the second * 0 if two given dates are in the same year * */ compareYear(first, second) { if (!this.isValid(first) || !this.isValid(second)) { throw Error('JSNativeDate: Cannot compare invalid dates.'); } const yearLeft = this.getYear(first); const yearRight = this.getYear(second); const diff = yearLeft - yearRight; if (diff < 0) { return -1; } else if (diff > 0) { return 1; } else { return 0; } } /** * Attempts to deserialize a value to a valid date object. This is different from parsing in that * deserialize should only accept non-ambiguous, locale-independent formats (e.g. a ISO 8601 * string). The default implementation does not allow any deserialization, it simply checks that * the given value is already a valid date object or null. The `<mat-datepicker>` will call this * method on all of it's `@Input()` properties that accept dates. It is therefore possible to * support passing values from your backend directly to these properties by overriding this method * to also deserialize the format used by your backend. */ deserialize(value) { if (value == null || (this.isDateInstance(value) && this.isValid(value))) { return value; } return this.invalid(); } /** * Sets the locale used for all dates. */ setLocale(locale) { this.locale = locale; this._localeChanges.next(locale); } /** * Get the locale used for all dates. * */ getLocale() { return this.locale; } /** * Clamp the given date between min and max dates. */ clampDate(date, min, max) { if (min && this.compare(date, min) < 0) { return min; } if (max && this.compare(date, max) > 0) { return max; } return date; } } /** * date-time.class */ let nextUniqueId = 0; var DateView; (function (DateView) { DateView["MONTH"] = "month"; DateView["YEAR"] = "year"; DateView["MULTI_YEARS"] = "multi-years"; })(DateView || (DateView = {})); class OwlDateTime { get showSecondsTimer() { return this._showSecondsTimer; } set showSecondsTimer(val) { this._showSecondsTimer = coerceBooleanProperty(val); } get hour12Timer() { return this._hour12Timer; } set hour12Timer(val) { this._hour12Timer = coerceBooleanProperty(val); } get stepHour() { return this._stepHour; } set stepHour(val) { this._stepHour = coerceNumberProperty(val, 1); } get stepMinute() { return this._stepMinute; } set stepMinute(val) { this._stepMinute = coerceNumberProperty(val, 1); } get stepSecond() { return this._stepSecond; } set stepSecond(val) { this._stepSecond = coerceNumberProperty(val, 1); } get firstDayOfWeek() { return this._firstDayOfWeek; } set firstDayOfWeek(value) { value = coerceNumberProperty(value); if (value > 6 || value < 0) { this._firstDayOfWeek = undefined; } else { this._firstDayOfWeek = value; } } get hideOtherMonths() { return this._hideOtherMonths; } set hideOtherMonths(val) { this._hideOtherMonths = coerceBooleanProperty(val); } get id() { return this._id; } get formatString() { return this.pickerType === 'both' ? this.dateTimeFormats.fullPickerInput : this.pickerType === 'calendar' ? this.dateTimeFormats.datePickerInput : this.dateTimeFormats.timePickerInput; } get disabled() { return false; } constructor(dateTimeAdapter, dateTimeFormats) { this.dateTimeAdapter = dateTimeAdapter; this.dateTimeFormats = dateTimeFormats; /** * Whether to show the second's timer */ this._showSecondsTimer = false; /** * Whether the timer is in hour12 format */ this._hour12Timer = false; /** * The view that the calendar should start in. */ this.startView = DateView.MONTH; /** * Whether to show calendar weeks in the calendar * */ this.showCalendarWeeks = false; /** * Whether to should only the year and multi-year views. */ this.yearOnly = false; /** * Whether to should only the multi-year view. */ this.multiyearOnly = false; /** * Hours to change per step */ this._stepHour = 1; /** * Minutes to change per step */ this._stepMinute = 1; /** * Seconds to change per step */ this._stepSecond = 1; /** * Whether to hide dates in other months at the start or end of the current month. */ this._hideOtherMonths = false; /** * Date Time Checker to check if the give dateTime is selectable */ this.dateTimeChecker = (dateTime) => { return (!!dateTime && (!this.dateTimeFilter || this.dateTimeFilter(dateTime)) && (!this.minDateTime || this.dateTimeAdapter.compare(dateTime, this.minDateTime) >= 0) && (!this.maxDateTime || this.dateTimeAdapter.compare(dateTime, this.maxDateTime) <= 0)); }; if (!this.dateTimeAdapter) { throw Error(`OwlDateTimePicker: No provider found for DateTimeAdapter. You must import one of the following ` + `modules at your application root: OwlNativeDateTimeModule, OwlMomentDateTimeModule, or provide a ` + `custom implementation.`); } if (!this.dateTimeFormats) { throw Error(`OwlDateTimePicker: No provider found for OWL_DATE_TIME_FORMATS. You must import one of the following ` + `modules at your application root: OwlNativeDateTimeModule, OwlMomentDateTimeModule, or provide a ` + `custom implementation.`); } this._id = `owl-dt-picker-${nextUniqueId++}`; } getValidDate(obj) { return this.dateTimeAdapter.isDateInstance(obj) && this.dateTimeAdapter.isValid(obj) ? obj : null; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlDateTime, deps: [{ token: DateTimeAdapter, optional: true }, { token: OWL_DATE_TIME_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.5", type: OwlDateTime, inputs: { showSecondsTimer: "showSecondsTimer", hour12Timer: "hour12Timer", startView: "startView", showCalendarWeeks: "showCalendarWeeks", yearOnly: "yearOnly", multiyearOnly: "multiyearOnly", stepHour: "stepHour", stepMinute: "stepMinute", stepSecond: "stepSecond", firstDayOfWeek: "firstDayOfWeek", hideOtherMonths: "hideOtherMonths" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlDateTime, decorators: [{ type: Directive }], ctorParameters: () => [{ type: DateTimeAdapter, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [OWL_DATE_TIME_FORMATS] }] }], propDecorators: { showSecondsTimer: [{ type: Input }], hour12Timer: [{ type: Input }], startView: [{ type: Input }], showCalendarWeeks: [{ type: Input }], yearOnly: [{ type: Input }], multiyearOnly: [{ type: Input }], stepHour: [{ type: Input }], stepMinute: [{ type: Input }], stepSecond: [{ type: Input }], firstDayOfWeek: [{ type: Input }], hideOtherMonths: [{ type: Input }] } }); /** * date-time-picker-intl.service */ class OwlDateTimeIntl { constructor() { /** * Stream that emits whenever the labels here are changed. Use this to notify * components if the labels have changed after initialization. */ this.changes = new Subject(); /** A label for the up second button (used by screen readers). */ this.upSecondLabel = 'Add a second'; /** A label for the down second button (used by screen readers). */ this.downSecondLabel = 'Minus a second'; /** A label for the up minute button (used by screen readers). */ this.upMinuteLabel = 'Add a minute'; /** A label for the down minute button (used by screen readers). */ this.downMinuteLabel = 'Minus a minute'; /** A label for the up hour button (used by screen readers). */ this.upHourLabel = 'Add a hour'; /** A label for the down hour button (used by screen readers). */ this.downHourLabel = 'Minus a hour'; /** A label for the previous month button (used by screen readers). */ this.prevMonthLabel = 'Previous month'; /** A label for the next month button (used by screen readers). */ this.nextMonthLabel = 'Next month'; /** A label for the previous year button (used by screen readers). */ this.prevYearLabel = 'Previous year'; /** A label for the next year button (used by screen readers). */ this.nextYearLabel = 'Next year'; /** A label for the previous multi-year button (used by screen readers). */ this.prevMultiYearLabel = 'Previous 21 years'; /** A label for the next multi-year button (used by screen readers). */ this.nextMultiYearLabel = 'Next 21 years'; /** A label for the 'switch to month view' button (used by screen readers). */ this.switchToMonthViewLabel = 'Change to month view'; /** A label for the 'switch to year view' button (used by screen readers). */ this.switchToMultiYearViewLabel = 'Choose month and year'; /** A label for the cancel button */ this.cancelBtnLabel = 'Cancel'; /** A label for the set button */ this.setBtnLabel = 'Set'; /** A label for the range 'from' in picker info */ this.rangeFromLabel = 'From'; /** A label for the range 'to' in picker info */ this.rangeToLabel = 'To'; /** A label for the hour12 button (AM) */ this.hour12AMLabel = 'AM'; /** A label for the hour12 button (PM) */ this.hour12PMLabel = 'PM'; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlDateTimeIntl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlDateTimeIntl, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlDateTimeIntl, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * calendar-body.component */ class CalendarCell { constructor(value, displayValue, ariaLabel, enabled, out = false, cellClass = '') { this.value = value; this.displayValue = displayValue; this.ariaLabel = ariaLabel; this.enabled = enabled; this.out = out; this.cellClass = cellClass; } } class OwlCalendarBodyComponent { get owlDTCalendarBodyClass() { return true; } get isInSingleMode() { return this.selectMode === 'single'; } get isInRangeMode() { return (this.selectMode === 'range' || this.selectMode === 'rangeFrom' || this.selectMode === 'rangeTo'); } constructor(elmRef, ngZone) { this.elmRef = elmRef; this.ngZone = ngZone; /** * The cell number of the active cell in the table. */ this.activeCell = 0; /** * The number of columns in the table. * */ this.numCols = 7; /** * The ratio (width / height) to use for the cells in the table. */ this.cellRatio = 1; /** * Emit when a calendar cell is selected * */ this.select = new EventEmitter(); } ngOnInit() { } selectCell(cell) { this.select.emit(cell); } isActiveCell(rowIndex, colIndex) { const cellNumber = rowIndex * this.numCols + colIndex; return cellNumber === this.activeCell; } /** * Check if the cell is selected */ isSelected(value) { if (!this.selectedValues || this.selectedValues.length === 0) { return false; } if (this.isInSingleMode) { return value === this.selectedValues[0]; } if (this.isInRangeMode) { const fromValue = this.selectedValues[0]; const toValue = this.selectedValues[1]; return value === fromValue || value === toValue; } } /** * Check if the cell in the range * */ isInRange(value) { if (this.isInRangeMode) { const fromValue = this.selectedValues[0]; const toValue = this.selectedValues[1]; if (fromValue !== null && toValue !== null) { return value >= fromValue && value <= toValue; } else { return value === fromValue || value === toValue; } } } /** * Check if the cell is the range from * */ isRangeFrom(value) { if (this.isInRangeMode) { const fromValue = this.selectedValues[0]; return fromValue !== null && value === fromValue; } } /** * Check if the cell is the range to * */ isRangeTo(value) { if (this.isInRangeMode) { const toValue = this.selectedValues[1]; return toValue !== null && value === toValue; } } /** * Focus to a active cell * */ focusActiveCell() { this.ngZone.runOutsideAngular(() => { this.ngZone.onStable .asObservable() .pipe(take(1)) .subscribe(() => { this.elmRef.nativeElement .querySelector('.owl-dt-calendar-cell-active') .focus(); }); }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlCalendarBodyComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.5", type: OwlCalendarBodyComponent, 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: "<tr *ngFor=\"let row of rows; let rowIndex = index\" role=\"row\">\n <td *ngFor=\"let item of row; let colIndex = index\"\n class=\"owl-dt-calendar-cell {{item.cellClass}}\"\n [tabindex]=\"isActiveCell(rowIndex, colIndex) ? 0 : -1\"\n [class.owl-dt-calendar-cell-active]=\"isActiveCell(rowIndex, colIndex)\"\n [class.owl-dt-calendar-cell-disabled]=\"!item.enabled\"\n [class.owl-dt-calendar-cell-in-range]=\"isInRange(item.value)\"\n [class.owl-dt-calendar-cell-range-from]=\"isRangeFrom(item.value)\"\n [class.owl-dt-calendar-cell-range-to]=\"isRangeTo(item.value)\"\n [attr.aria-label]=\"item.ariaLabel\"\n [attr.aria-disabled]=\"!item.enabled || null\"\n [attr.aria-current]=\"item.value === todayValue ? 'date' : null\"\n [attr.aria-selected]=\"isSelected(item.value)\"\n [style.width.%]=\"100 / numCols\"\n [style.paddingTop.%]=\"50 * cellRatio / numCols\"\n [style.paddingBottom.%]=\"50 * cellRatio / numCols\"\n (click)=\"selectCell(item)\">\n <span class=\"owl-dt-calendar-cell-content\"\n [ngClass]=\"{\n 'owl-dt-calendar-cell-out': item.out,\n 'owl-dt-calendar-cell-today': item.value === todayValue,\n 'owl-dt-calendar-cell-selected': isSelected(item.value)\n }\">\n {{item.displayValue}}\n </span>\n </td>\n</tr>\n", styles: [""], dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlCalendarBodyComponent, decorators: [{ type: Component, args: [{ selector: '[owl-date-time-calendar-body]', exportAs: 'owlDateTimeCalendarBody', host: { '[class.owl-dt-calendar-body]': 'owlDTCalendarBodyClass' }, preserveWhitespaces: false, standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<tr *ngFor=\"let row of rows; let rowIndex = index\" role=\"row\">\n <td *ngFor=\"let item of row; let colIndex = index\"\n class=\"owl-dt-calendar-cell {{item.cellClass}}\"\n [tabindex]=\"isActiveCell(rowIndex, colIndex) ? 0 : -1\"\n [class.owl-dt-calendar-cell-active]=\"isActiveCell(rowIndex, colIndex)\"\n [class.owl-dt-calendar-cell-disabled]=\"!item.enabled\"\n [class.owl-dt-calendar-cell-in-range]=\"isInRange(item.value)\"\n [class.owl-dt-calendar-cell-range-from]=\"isRangeFrom(item.value)\"\n [class.owl-dt-calendar-cell-range-to]=\"isRangeTo(item.value)\"\n [attr.aria-label]=\"item.ariaLabel\"\n [attr.aria-disabled]=\"!item.enabled || null\"\n [attr.aria-current]=\"item.value === todayValue ? 'date' : null\"\n [attr.aria-selected]=\"isSelected(item.value)\"\n [style.width.%]=\"100 / numCols\"\n [style.paddingTop.%]=\"50 * cellRatio / numCols\"\n [style.paddingBottom.%]=\"50 * cellRatio / numCols\"\n (click)=\"selectCell(item)\">\n <span class=\"owl-dt-calendar-cell-content\"\n [ngClass]=\"{\n 'owl-dt-calendar-cell-out': item.out,\n 'owl-dt-calendar-cell-today': item.value === todayValue,\n 'owl-dt-calendar-cell-selected': isSelected(item.value)\n }\">\n {{item.displayValue}}\n </span>\n </td>\n</tr>\n" }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { activeCell: [{ type: Input }], rows: [{ type: Input }], numCols: [{ type: Input }], cellRatio: [{ type: Input }], todayValue: [{ type: Input }], selectedValues: [{ type: Input }], selectMode: [{ type: Input }], select: [{ type: Output }] } }); function defaultOptionsFactory() { return DefaultOptions.create(); } function multiYearOptionsFactory(options) { return options.multiYear; } class DefaultOptions { static create() { // Always return new instance return { multiYear: { yearRows: 7, yearsPerRow: 3 } }; } } class OptionsTokens { static { this.all = new InjectionToken('All options token'); } static { this.multiYear = new InjectionToken('Grid view options token'); } } const optionsProviders = [ { provide: OptionsTokens.all, useFactory: defaultOptionsFactory, }, { provide: OptionsTokens.multiYear, useFactory: multiYearOptionsFactory, deps: [OptionsTokens.all], }, ]; /** * calendar-multi-year-view.component */ class OwlMultiYearViewComponent { get selectMode() { return this._selectMode; } set selectMode(val) { this._selectMode = val; if (this.initiated) { this.setSelectedYears(); this.cdRef.markForCheck(); } } get selected() { return this._selected; } set selected(value) { const oldSelected = this._selected; value = this.dateTimeAdapter.deserialize(value); this._selected = this.getValidDate(value); if (!this.dateTimeAdapter.isSameDay(oldSelected, this._selected)) { this.setSelectedYears(); } } get selecteds() { return this._selecteds; } set selecteds(values) { this._selecteds = values.map((v) => { v = this.dateTimeAdapter.deserialize(v); return this.getValidDate(v); }); this.setSelectedYears(); } get pickerMoment() { return this._pickerMoment; } set pickerMoment(value) { const oldMoment = this._pickerMoment; value = this.dateTimeAdapter.deserialize(value); this._pickerMoment = this.getValidDate(value) || this.dateTimeAdapter.now(); if (oldMoment && this._pickerMoment && !this.isSameYearList(oldMoment, this._pickerMoment)) { this.generateYearList(); } } get dateFilter() { return this._dateFilter; } set dateFilter(filter) { this._dateFilter = filter; if (this.initiated) { this.generateYearList(); } } get minDate() { return this._minDate; } set minDate(value) { value = this.dateTimeAdapter.deserialize(value); this._minDate = this.getValidDate(value); if (this.initiated) { this.generateYearList(); } } get maxDate() { return this._maxDate; } set maxDate(value) { value = this.dateTimeAdapter.deserialize(value); this._maxDate = this.getValidDate(value); if (this.initiated) { this.generateYearList(); } } get todayYear() { return this._todayYear; } get years() { return this._years; } get selectedYears() { return this._selectedYears; } get isInSingleMode() { return this.selectMode === 'single'; } get isInRangeMode() { return this.selectMode === 'range' || this.selectMode === 'rangeFrom' || this.selectMode === 'rangeTo'; } get activeCell() { if (this._pickerMoment) { return this.dateTimeAdapter.getYear(this._pickerMoment) % (this.options.yearsPerRow * this.options.yearRows); } } get tableHeader() { if (this._years && this._years.length > 0) { return `${this._years[0][0].displayValue} - ${this._years[this.options.yearRows - 1][this.options.yearsPerRow - 1].displayValue}`; } } get prevButtonLabel() { return this.pickerIntl.prevMultiYearLabel; } get nextButtonLabel() { return this.pickerIntl.nextMultiYearLabel; } get owlDTCalendarView() { return true; } get owlDTCalendarMultiYearView() { return true; } constructor(cdRef, pickerIntl, dateTimeAdapter, options) { this.cdRef = cdRef; this.pickerIntl = pickerIntl; this.dateTimeAdapter = dateTimeAdapter; this.options = options; /** * The select mode of the picker; * */ this._selectMode = 'single'; this._selecteds = []; this.initiated = false; /** * Callback to invoke when a new month is selected * */ this.change = new EventEmitter(); /** * Emits the selected year. This doesn't imply a change on the selected date * */ this.yearSelected = new EventEmitter(); /** Emits when any date is activated. */ this.pickerMomentChange = new EventEmitter(); /** Emits when use keyboard enter to select a calendar cell */ this.keyboardEnter = new EventEmitter(); } ngOnInit() { } ngAfterContentInit() { this._todayYear = this.dateTimeAdapter.getYear(this.dateTimeAdapter.now()); this.generateYearList(); this.initiated = true; } /** * Handle a calendarCell selected */ selectCalendarCell(cell) { this.selectYear(cell.value); } selectYear(year) { this.yearSelected.emit(this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1)); const firstDateOfMonth = this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.getMonth(this.pickerMoment), 1); const daysInMonth = this.dateTimeAdapter.getNumDaysInMonth(firstDateOfMonth); const selected = this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.getMonth(this.pickerMoment), Math.min(daysInMonth, this.dateTimeAdapter.getDate(this.pickerMoment)), this.dateTimeAdapter.getHours(this.pickerMoment), this.dateTimeAdapter.getMinutes(this.pickerMoment), this.dateTimeAdapter.getSeconds(this.pickerMoment)); this.change.emit(selected); } /** * Generate the previous year list * */ prevYearList(event) { this._pickerMoment = this.dateTimeAdapter.addCalendarYears(this.pickerMoment, -1 * this.options.yearsPerRow * this.options.yearRows); this.generateYearList(); event.preventDefault(); } /** * Generate the next year list * */ nextYearList(event) { this._pickerMoment = this.dateTimeAdapter.addCalendarYears(this.pickerMoment, this.options.yearsPerRow * this.options.yearRows); this.generateYearList(); event.preventDefault(); } generateYearList() { this._years = []; const pickerMomentYear = this.dateTimeAdapter.getYear(this._pickerMoment); const offset = pickerMomentYear % (this.options.yearsPerRow * this.options.yearRows); for (let i = 0; i < this.options.yearRows; i++) { const row = []; for (let j = 0; j < this.options.yearsPerRow; j++) { const year = pickerMomentYear - offset + (j + i * this.options.yearsPerRow); const yearCell = this.createYearCell(year); row.push(yearCell); } this._years.push(row); } return; } /** Whether the previous period button is enabled. */ previousEnabled() { if (!this.minDate) { return true; } return !this.minDate || !this.isSameYearList(this._pickerMoment, this.minDate); } /** Whether the next period button is enabled. */ nextEnabled() { return !this.maxDate || !this.isSameYearList(this._pickerMoment, this.maxDate); } handleCalendarKeydown(event) { let moment; switch (event.keyCode) { // minus 1 year case LEFT_ARROW: moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, -1); this.pickerMomentChange.emit(moment); break; // add 1 year case RIGHT_ARROW: moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, 1); this.pickerMomentChange.emit(moment); break; // minus 3 years case UP_ARROW: moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, -1 * this.options.yearsPerRow); this.pickerMomentChange.emit(moment); break; // add 3 years case DOWN_ARROW: moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, this.options.yearsPerRow); this.pickerMomentChange.emit(moment); break; // go to the first year of the year page case HOME: moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, -this.dateTimeAdapter.getYear(this._pickerMoment) % (this.options.yearsPerRow * this.options.yearRows)); this.pickerMomentChange.emit(moment); break; // go to the last year of the year page case END: moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, (this.options.yearsPerRow * this.options.yearRows) - this.dateTimeAdapter.getYear(this._pickerMoment) % (this.options.yearsPerRow * this.options.yearRows) - 1); this.pickerMomentChange.emit(moment); break; // minus 1 year page (or 10 year pages) case PAGE_UP: moment = this.dateTimeAdapter.addCalendarYears(this.pickerMoment, event.altKey ? -10 * (this.options.yearsPerRow * this.options.yearRows) : -1 * (this.options.yearsPerRow * this.options.yearRows)); this.pickerMomentChange.emit(moment); break; // add 1 year page (or 10 year pages) case PAGE_DOWN: moment = this.dateTimeAdapter.addCalendarYears(this.pickerMoment, event.altKey ? 10 * (this.options.yearsPerRow * this.options.yearRows) : (this.options.yearsPerRow * this.options.yearRows)); this.pickerMomentChange.emit(moment); break; case ENTER: this.selectYear(this.dateTimeAdapter.getYear(this._pickerMoment)); this.keyboardEnter.emit(); break; default: return; } this.focusActiveCell(); event.preventDefault(); } /** * Creates an CalendarCell for the given year. */ createYearCell(year) { const startDateOfYear = this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1); const ariaLabel = this.dateTimeAdapter.getYearName(startDateOfYear); const cellClass = 'owl-dt-year-' + year; return new CalendarCell(year, year.toString(), ariaLabel, this.isYearEnabled(year), false, cellClass); } setSelectedYears() { this._selectedYears = []; if (this.isInSingleMode && this.selected) { this._selectedYears[0] = this.dateTimeAdapter.getYear(this.selected); } if (this.isInRangeMode && this.selecteds) { this._selectedYears = this.selecteds.map((selected) => { if (this.dateTimeAdapter.isValid(selected)) { return this.dateTimeAdapter.getYear(selected); } else { return null; } }); } } /** Whether the given year is enabled. */ isYearEnabled(year) { // disable if the year is greater than maxDate lower than minDate if (year === undefined || year === null || (this.maxDate && year > this.dateTimeAdapter.getYear(this.maxDate)) || (this.minDate && year < this.dateTimeAdapter.getYear(this.minDate))) { return false; } // enable if it reaches here and there's no filter defined if (!this.dateFilter) { return true; } const firstOfYear = this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1); // If any date in the year is enabled count the year as enabled. for (let date = firstOfYear; this.dateTimeAdapter.getYear(date) === year; date = this.dateTimeAdapter.addCalendarDays(date, 1)) { if (this.dateFilter(date)) { return true; } } return false; } isSameYearList(date1, date2) { return Math.floor(this.dateTimeAdapter.getYear(date1) / (this.options.yearsPerRow * this.options.yearRows)) === Math.floor(this.dateTimeAdapter.getYear(date2) / (this.options.yearsPerRow * this.options.yearRows)); } /** * Get a valid date object */ getValidDate(obj) { return (this.dateTimeAdapter.isDateInstance(obj) && this.dateTimeAdapter.isValid(obj)) ? obj : null; } focusActiveCell() { this.calendarBodyElm.focusActiveCell(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlMultiYearViewComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: OwlDateTimeIntl }, { token: DateTimeAdapter, optional: true }, { token: OptionsTokens.multiYear }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.5", type: OwlMultiYearViewComponent, selector: "owl-date-time-multi-year-view", inputs: { selectMode: "selectMode", selected: "selected", selecteds: "selecteds", pickerMoment: "pickerMoment", dateFilter: "dateFilter", minDate: "minDate", maxDate: "maxDate" }, outputs: { change: "change", yearSelected: "yearSelected", pickerMomentChange: "pickerMomentChange", 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\"\n [disabled]=\"!previousEnabled()\" [attr.aria-label]=\"prevButtonLabel\"\n type=\"button\" tabindex=\"0\" (click)=\"prevYearList($event)\">\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\n <!-- <editor-fold desc=\"SVG Arrow Left\"> -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n version=\"1.1\" x=\"0px\" y=\"0px\" viewBox=\"0 0 250.738 250.738\"\n style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\"\n width=\"100%\" height=\"100%\">\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\"/>\n </svg>\n <!-- </editor-fold> -->\n </span>\n</button>\n<table class=\"owl-dt-calendar-table owl-dt-calendar-multi-year-table\">\n <thead class=\"owl-dt-calendar-header\">\n <tr>\n <th colspan=\"3\">{{tableHeader}}</th>\n </tr>\n </thead>\n <tbody owl-date-time-calendar-body role=\"grid\"\n [rows]=\"years\" [numCols]=\"3\" [cellRatio]=\"3 / 7\"\n [activeCell]=\"activeCell\"\n [todayValue]=\"todayYear\"\n [selectedValues]=\"selectedYears\"\n [selectMode]=\"selectMode\"\n (keydown)=\"handleCalendarKeydown($event)\"\n (select)=\"selectCalendarCell($event)\"></tbody>\n</table>\n<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\n [disabled]=\"!nextEnabled()\" [attr.aria-label]=\"nextButtonLabel\"\n type=\"button\" tabindex=\"0\" (click)=\"nextYearList($event)\">\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\n <!-- <editor-fold desc=\"SVG Arrow Right\"> -->\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n viewBox=\"0 0 250.738 250.738\" style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\">\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\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\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\n C197.237,120.447,195.534,115.448,191.75,111.689z\"/>\n </svg>\n <!-- </editor-fold> -->\n </span>\n</button>\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 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: OwlMultiYearViewComponent, decorators: [{ type: Component, args: [{ selector: 'owl-date-time-multi-year-view', host: { '[class.owl-dt-calendar-view]': 'owlDTCalendarView', '[class.owl-dt-calendar-multi-year-view]': 'owlDTCalendarMultiYearView' }, standalone: false, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\n [disabled]=\"!previousEnabled()\" [attr.aria-label]=\"prevButtonLabel\"\n type=\"button\" tabindex=\"0\" (click)=\"prevYearList($event)\">\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\n <!-- <editor-fold desc=\"SVG Arrow Left\"> -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n version=\"1.1\" x=\"0px\" y=\"0px\" viewBox=\"0 0 250.738 250.738\"\n style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\"\n width=\"100%\" height=\"100%\">\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\"/>\n </svg>\n <!-- </editor-fold> -->\n </span>\n</button>\n<table class=\"owl-dt-calendar-table owl-dt-calendar-multi-year-table\">\n <thead class=\"owl-dt-calendar-header\">\n <tr>\n <th colspan=\"3\">{{tableHeader}}</th>\n </tr>\n </thead>\n <tbody owl-date-time-calendar-body role=\"grid\"\n [rows]=\"years\" [numCols]=\"3\" [cellRatio]=\"3 / 7\"\n [activeCell]=\"activeCell\"\n [todayValue]=\"todayYear\"\n [selectedValues]=\"selectedYears\"\n [selectMode]=\"selectMode\"\n (keydown)=\"handleCalendarKeydown($event)\"\n (select)=\"selectCalendarCell($event)\"></tbody>\n</table>\n<button class=\"owl-dt-control-button owl-dt-control-arrow-button\"\n [disabled]=\"!nextEnabled()\" [attr.aria-label]=\"nextButtonLabel\"\n type=\"button\" tabindex=\"0\" (click)=\"nextYearList($event)\">\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\n <!-- <editor-fold desc=\"SVG Arrow Right\"> -->\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n viewBox=\"0 0 250.738 250.738\" style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\">\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\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\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\n C197.237,120.447,195.534,115.448,191.75,111.689z\"/>\n </svg>\n <!-- </editor-fold> -->\n </span>\n</button>\n" }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: OwlDateTimeIntl }, { type: DateTimeAdapter, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Inject, args: [OptionsTokens.multiYear] }] }], propDecorators: { selectMode: [{ type: Input }], selected: [{ type: Input }], selecteds: [{ type: Input }], pickerMoment: [{ type: Input }], dateFilter: [{ type: Input }], minDate: [{ type: Input }], maxDate: [{ type: Input }], change: [{ type: Output }], yearSelected: [{ type: Output }], pickerMomentChange: [{ type: Output }], keyboardEnter: [{ type: Output }], calendarBodyElm: [{ type: ViewChild, args: [OwlCalendarBodyComponent, { static: true }] }] } }); /** * calendar-year-view.component */ const MONTHS_PER_YEAR = 12; const MONTHS_PER_ROW = 3; class OwlYearViewComponent { get selectMode() { return this._selectMode; } set selectMode(val) { this._selectMode = val; if (this.initiated) { this.generateMonthList(); this.cdRef.markForCheck(); } } get selected() { return this._selected; } set selected(value) { value = this.dateTimeAdapter.deserialize(value); this._selected = this.getValidDate(value); this.setSelectedMonths(); } get selecteds() { return this._selecteds; } set selecteds(values) { this._selecteds = []; for (let i = 0; i < values.length; i++) { const value = this.dateTimeAdapter.deserialize(values[i]); this._selecteds.push(this.getValidDate(value)); } this.setSelectedMonths(); } get pickerMoment() { return this._pickerMoment; } set pickerMoment(value) { const oldMoment = this._pickerMoment; value = this.dateTimeAdapter.deserialize(value); this._pickerMoment = this.getValidDate(value) || this.dateTimeAdapter.now(); if (!this.hasSameYear(oldMoment, this._pickerMoment) && this.initiated) { this.generateMonthList(); } } get dateFilter() { return this._dateFilter; } set dateFilter(filter) { this._dateFilter = filter; if (this.initiated) { this.generateMonthList(); } } get minDate() { return this._minDate; } set minDate(value) { value = this.dateTimeAdapter.deserialize(value); this._minDate = this.getValidDate(value); if (this.initiated) {