UNPKG

@danielmoncada/angular-datetime-picker

Version:
1 lines 465 kB
{"version":3,"file":"danielmoncada-angular-datetime-picker.mjs","sources":["../../../projects/picker/src/lib/date-time/date-time-picker-trigger.directive.ts","../../../projects/picker/src/lib/date-time/adapter/date-time-format.class.ts","../../../projects/picker/src/lib/date-time/adapter/date-time-adapter.class.ts","../../../projects/picker/src/lib/date-time/date-time.class.ts","../../../projects/picker/src/lib/date-time/date-time-picker-intl.service.ts","../../../projects/picker/src/lib/date-time/calendar-body.component.ts","../../../projects/picker/src/lib/date-time/calendar-body.component.html","../../../projects/picker/src/lib/date-time/options-provider.ts","../../../projects/picker/src/lib/date-time/calendar-multi-year-view.component.ts","../../../projects/picker/src/lib/date-time/calendar-multi-year-view.component.html","../../../projects/picker/src/lib/date-time/calendar-year-view.component.ts","../../../projects/picker/src/lib/date-time/calendar-year-view.component.html","../../../projects/picker/src/lib/date-time/calendar-month-view.component.ts","../../../projects/picker/src/lib/date-time/calendar-month-view.component.html","../../../projects/picker/src/lib/date-time/calendar.component.ts","../../../projects/picker/src/lib/date-time/calendar.component.html","../../../projects/picker/src/lib/date-time/timer-box.component.ts","../../../projects/picker/src/lib/date-time/timer-box.component.html","../../../projects/picker/src/lib/date-time/timer.component.ts","../../../projects/picker/src/lib/date-time/timer.component.html","../../../projects/picker/src/lib/date-time/date-time-picker.animations.ts","../../../projects/picker/src/lib/date-time/date-time-picker-container.component.ts","../../../projects/picker/src/lib/date-time/date-time-picker-container.component.html","../../../projects/picker/src/lib/dialog/dialog-config.class.ts","../../../projects/picker/src/lib/dialog/dialog-ref.class.ts","../../../projects/picker/src/lib/dialog/dialog-container.component.ts","../../../projects/picker/src/lib/dialog/dialog-container.component.html","../../../projects/picker/src/lib/utils/object.utils.ts","../../../projects/picker/src/lib/utils/index.ts","../../../projects/picker/src/lib/dialog/dialog.service.ts","../../../projects/picker/src/lib/date-time/date-time-picker.component.ts","../../../projects/picker/src/lib/date-time/date-time-picker.component.html","../../../projects/picker/src/lib/date-time/date-time-picker-input.directive.ts","../../../projects/picker/src/lib/date-time/numberedFixLen.pipe.ts","../../../projects/picker/src/lib/date-time/date-time-inline.component.ts","../../../projects/picker/src/lib/date-time/date-time-inline.component.html","../../../projects/picker/src/lib/dialog/dialog.module.ts","../../../projects/picker/src/lib/date-time/date-time.module.ts","../../../projects/picker/src/lib/utils/array.utils.ts","../../../projects/picker/src/lib/utils/date.utils.ts","../../../projects/picker/src/lib/utils/constants.ts","../../../projects/picker/src/lib/date-time/adapter/native-date-time-adapter.class.ts","../../../projects/picker/src/lib/date-time/adapter/native-date-time-format.class.ts","../../../projects/picker/src/lib/date-time/adapter/native-date-time.module.ts","../../../projects/picker/src/lib/date-time/adapter/unix-timestamp-adapter/unix-timestamp-date-time-adapter.class.ts","../../../projects/picker/src/lib/date-time/adapter/unix-timestamp-adapter/unix-timestamp-date-time-format.class.ts","../../../projects/picker/src/public_api.ts","../../../projects/picker/src/danielmoncada-angular-datetime-picker.ts"],"sourcesContent":["/**\n * date-time-picker-trigger.directive\n */\n\n\nimport {\n AfterContentInit,\n ChangeDetectorRef,\n Directive,\n Input,\n OnChanges,\n OnDestroy,\n OnInit,\n SimpleChanges\n} from '@angular/core';\nimport { OwlDateTimeComponent } from './date-time-picker.component';\nimport { merge, of as observableOf, Subscription } from 'rxjs';\n\n@Directive({\n selector: '[owlDateTimeTrigger]',\n standalone: false,\n host: {\n '(click)': 'handleClickOnHost($event)',\n '[class.owl-dt-trigger-disabled]': 'owlDTTriggerDisabledClass'\n }\n})\nexport class OwlDateTimeTriggerDirective<T> implements OnInit, OnChanges, AfterContentInit, OnDestroy {\n\n @Input('owlDateTimeTrigger') dtPicker: OwlDateTimeComponent<T>;\n\n private _disabled: boolean;\n @Input()\n get disabled(): boolean {\n return this._disabled === undefined ? this.dtPicker.disabled : !!this._disabled;\n }\n\n set disabled( value: boolean ) {\n this._disabled = value;\n }\n\n get owlDTTriggerDisabledClass(): boolean {\n return this.disabled;\n }\n\n private stateChanges = Subscription.EMPTY;\n\n constructor( protected changeDetector: ChangeDetectorRef ) {\n }\n\n public ngOnInit(): void {\n }\n\n public ngOnChanges( changes: SimpleChanges ) {\n if (changes.datepicker) {\n this.watchStateChanges();\n }\n }\n\n public ngAfterContentInit() {\n this.watchStateChanges();\n }\n\n public ngOnDestroy(): void {\n this.stateChanges.unsubscribe();\n }\n\n public handleClickOnHost( event: Event ): void {\n if (this.dtPicker) {\n this.dtPicker.open();\n event.stopPropagation();\n }\n }\n\n private watchStateChanges(): void {\n this.stateChanges.unsubscribe();\n\n const inputDisabled = this.dtPicker && this.dtPicker.dtInput ?\n this.dtPicker.dtInput.disabledChange : observableOf();\n\n const pickerDisabled = this.dtPicker ?\n this.dtPicker.disabledChange : observableOf();\n\n this.stateChanges = merge([pickerDisabled, inputDisabled])\n .subscribe(() => {\n this.changeDetector.markForCheck();\n });\n }\n}\n","/**\n * date-time-format.class\n */\n\nimport { InjectionToken } from '@angular/core';\n\nexport interface OwlDateTimeFormats {\n parseInput: any;\n fullPickerInput: any;\n datePickerInput: any;\n timePickerInput: any;\n monthYearLabel: any;\n dateA11yLabel: any;\n monthYearA11yLabel: any;\n}\n\n/** InjectionToken for date time picker that can be used to override default format. */\nexport const OWL_DATE_TIME_FORMATS = new InjectionToken<OwlDateTimeFormats>('OWL_DATE_TIME_FORMATS');\n","/**\n * date-time-adapter.class\n */\nimport { Observable, Subject } from 'rxjs';\nimport { inject, InjectionToken, LOCALE_ID } from '@angular/core';\n\n/** InjectionToken for date time picker that can be used to override default locale code. */\nexport const OWL_DATE_TIME_LOCALE = new InjectionToken<string>(\n 'OWL_DATE_TIME_LOCALE',\n {\n providedIn: 'root',\n factory: OWL_DATE_TIME_LOCALE_FACTORY\n }\n);\n\n/** @docs-private */\nexport function OWL_DATE_TIME_LOCALE_FACTORY(): string {\n return inject(LOCALE_ID);\n}\n\n/** Provider for OWL_DATE_TIME_LOCALE injection token. */\nexport const OWL_DATE_TIME_LOCALE_PROVIDER = {\n provide: OWL_DATE_TIME_LOCALE,\n useExisting: LOCALE_ID\n};\n\nexport abstract class DateTimeAdapter<T> {\n /** The locale to use for all dates. */\n protected locale: any;\n\n /** A stream that emits when the locale changes. */\n protected _localeChanges = new Subject<string>();\n get localeChanges(): Observable<string> {\n return this._localeChanges;\n }\n\n\tpublic firstMonthOfTheYear: number = 0;\n\tpublic firstDayOfTheWeek: number = 0;\n \n /** total milliseconds in a day. */\n protected readonly millisecondsInDay = 86400000;\n\n /** total milliseconds in a minute. */\n protected readonly milliseondsInMinute = 60000;\n\n /**\n * Get the year of the given date\n */\n abstract getYear(date: T): number;\n\n /**\n * Get the month of the given date\n * 0 -- January\n * 11 -- December\n * */\n abstract getMonth(date: T): number;\n\n /**\n * Get the day of the week of the given date\n * 0 -- Sunday\n * 6 -- Saturday\n * */\n abstract getDay(date: T): number;\n\n /**\n * Get the day num of the given date\n */\n abstract getDate(date: T): number;\n\n /**\n * Get the hours of the given date\n */\n abstract getHours(date: T): number;\n\n /**\n * Get the minutes of the given date\n */\n abstract getMinutes(date: T): number;\n\n /**\n * Get the seconds of the given date\n */\n abstract getSeconds(date: T): number;\n\n /**\n * Get the milliseconds timestamp of the given date\n */\n abstract getTime(date: T): number;\n\n /**\n * Gets the number of days in the month of the given date.\n */\n abstract getNumDaysInMonth(date: T): number;\n\n /**\n * Get the number of calendar days between the given dates.\n * If dateLeft is before dateRight, it would return positive value\n * If dateLeft is after dateRight, it would return negative value\n */\n abstract differenceInCalendarDays(dateLeft: T, dateRight: T): number;\n\n /**\n * Gets the name for the year of the given date.\n */\n abstract getYearName(date: T): string;\n\n /**\n * Get a list of month names\n */\n abstract getMonthNames(style: 'long' | 'short' | 'narrow'): string[];\n\n /**\n * Get a list of week names\n */\n abstract getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[];\n\n /**\n * Gets a list of names for the dates of the month.\n */\n abstract getDateNames(): string[];\n\n /**\n * Return a Date object as a string, using the ISO standard\n */\n abstract toIso8601(date: T): string;\n\n /**\n * Check if the give dates are equal\n */\n abstract isEqual(dateLeft: T, dateRight: T): boolean;\n\n /**\n * Check if the give dates are the same day\n */\n abstract isSameDay(dateLeft: T, dateRight: T): boolean;\n\n /**\n * Checks whether the given date is valid.\n */\n abstract isValid(date: T): boolean;\n\n /**\n * Gets date instance that is not valid.\n */\n abstract invalid(): T;\n\n /**\n * Checks whether the given object is considered a date instance by this DateTimeAdapter.\n */\n abstract isDateInstance(obj: any): boolean;\n\n /**\n * Add the specified number of years to the given date\n */\n abstract addCalendarYears(date: T, amount: number): T;\n\n /**\n * Add the specified number of months to the given date\n */\n abstract addCalendarMonths(date: T, amount: number): T;\n\n /**\n * Add the specified number of days to the given date\n */\n abstract addCalendarDays(date: T, amount: number): T;\n\n /**\n * Set the hours to the given date.\n */\n abstract setHours(date: T, amount: number): T;\n\n /**\n * Set the minutes to the given date.\n */\n abstract setMinutes(date: T, amount: number): T;\n\n /**\n * Set the seconds to the given date.\n */\n abstract setSeconds(date: T, amount: number): T;\n\n /**\n * Creates a date with the given year, month, date, hour, minute and second. Does not allow over/under-flow of the\n * month and date.\n */\n abstract createDate(year: number, month: number, date: number): T;\n abstract createDate(\n year: number,\n month: number,\n date: number,\n hours: number,\n minutes: number,\n seconds: number\n ): T;\n\n /**\n * Clone the given date\n */\n abstract clone(date: T): T;\n\n /**\n * Get a new moment\n * */\n abstract now(): T;\n\n /**\n * Formats a date as a string according to the given format.\n */\n abstract format(date: T, displayFormat: any): string;\n\n /**\n * Parse a user-provided value to a Date Object\n */\n abstract parse(value: any, parseFormat: any): T | null;\n\n /**\n * Compare two given dates\n * 1 if the first date is after the second,\n * -1 if the first date is before the second\n * 0 if dates are equal.\n * */\n compare(first: T, second: T): number {\n if (!this.isValid(first) || !this.isValid(second)) {\n throw Error('JSNativeDate: Cannot compare invalid dates.');\n }\n\n const dateFirst = this.clone(first);\n const dateSecond = this.clone(second);\n\n const diff = this.getTime(dateFirst) - this.getTime(dateSecond);\n\n if (diff < 0) {\n return -1;\n } else if (diff > 0) {\n return 1;\n } else {\n // Return 0 if diff is 0; return NaN if diff is NaN\n return diff;\n }\n }\n\n /**\n * Check if two given dates are in the same year\n * 1 if the first date's year is after the second,\n * -1 if the first date's year is before the second\n * 0 if two given dates are in the same year\n * */\n compareYear(first: T, second: T): number {\n if (!this.isValid(first) || !this.isValid(second)) {\n throw Error('JSNativeDate: Cannot compare invalid dates.');\n }\n\n const yearLeft = this.getYear(first);\n const yearRight = this.getYear(second);\n\n const diff = yearLeft - yearRight;\n\n if (diff < 0) {\n return -1;\n } else if (diff > 0) {\n return 1;\n } else {\n return 0;\n }\n }\n\n /**\n * Attempts to deserialize a value to a valid date object. This is different from parsing in that\n * deserialize should only accept non-ambiguous, locale-independent formats (e.g. a ISO 8601\n * string). The default implementation does not allow any deserialization, it simply checks that\n * the given value is already a valid date object or null. The `<mat-datepicker>` will call this\n * method on all of it's `@Input()` properties that accept dates. It is therefore possible to\n * support passing values from your backend directly to these properties by overriding this method\n * to also deserialize the format used by your backend.\n */\n deserialize(value: any): T | null {\n if (\n value == null ||\n (this.isDateInstance(value) && this.isValid(value))\n ) {\n return value;\n }\n return this.invalid();\n }\n\n /**\n * Sets the locale used for all dates.\n */\n setLocale(locale: string) {\n this.locale = locale;\n this._localeChanges.next(locale);\n }\n\n /**\n * Get the locale used for all dates.\n * */\n getLocale() {\n return this.locale;\n }\n\n /**\n * Clamp the given date between min and max dates.\n */\n clampDate(date: T, min?: T | null, max?: T | null): T {\n if (min && this.compare(date, min) < 0) {\n return min;\n }\n if (max && this.compare(date, max) > 0) {\n return max;\n }\n return date;\n }\n}\n","/**\n * date-time.class\n */\nimport {EventEmitter, Inject, Input, Optional, Directive} from '@angular/core';\nimport {\n coerceBooleanProperty,\n coerceNumberProperty\n} from '@angular/cdk/coercion';\nimport {DateTimeAdapter} from './adapter/date-time-adapter.class';\nimport {\n OWL_DATE_TIME_FORMATS,\n OwlDateTimeFormats\n} from './adapter/date-time-format.class';\n\nlet nextUniqueId = 0;\n\nexport type PickerType = 'both' | 'calendar' | 'timer';\n\nexport type PickerMode = 'popup' | 'dialog' | 'inline';\n\nexport type SelectMode = 'single' | 'range' | 'rangeFrom' | 'rangeTo';\n\nexport enum DateView {\n MONTH = 'month',\n YEAR = 'year',\n MULTI_YEARS = 'multi-years'\n}\n\nexport type DateViewType = DateView.MONTH | DateView.YEAR | DateView.MULTI_YEARS;\n\n@Directive()\nexport abstract class OwlDateTime<T> {\n /**\n * Whether to show the second's timer\n */\n private _showSecondsTimer = false;\n @Input()\n get showSecondsTimer(): boolean {\n return this._showSecondsTimer;\n }\n\n set showSecondsTimer(val: boolean) {\n this._showSecondsTimer = coerceBooleanProperty(val);\n }\n\n /**\n * Whether the timer is in hour12 format\n */\n private _hour12Timer = false;\n @Input()\n get hour12Timer(): boolean {\n return this._hour12Timer;\n }\n\n set hour12Timer(val: boolean) {\n this._hour12Timer = coerceBooleanProperty(val);\n }\n\n /**\n * The view that the calendar should start in.\n */\n @Input()\n startView: DateViewType = DateView.MONTH;\n\n /**\n * Whether to show calendar weeks in the calendar\n * */\n @Input()\n showCalendarWeeks = false;\n\n /**\n * Whether to should only the year and multi-year views.\n */\n @Input()\n yearOnly = false;\n\n /**\n * Whether to should only the multi-year view.\n */\n @Input()\n multiyearOnly = false;\n\n /**\n * Hours to change per step\n */\n private _stepHour = 1;\n @Input()\n get stepHour(): number {\n return this._stepHour;\n }\n\n set stepHour(val: number) {\n this._stepHour = coerceNumberProperty(val, 1);\n }\n\n /**\n * Minutes to change per step\n */\n private _stepMinute = 1;\n @Input()\n get stepMinute(): number {\n return this._stepMinute;\n }\n\n set stepMinute(val: number) {\n this._stepMinute = coerceNumberProperty(val, 1);\n }\n\n /**\n * Seconds to change per step\n */\n private _stepSecond = 1;\n @Input()\n get stepSecond(): number {\n return this._stepSecond;\n }\n\n set stepSecond(val: number) {\n this._stepSecond = coerceNumberProperty(val, 1);\n }\n\n /**\n * Set the first day of week\n */\n private _firstDayOfWeek: number;\n @Input()\n get firstDayOfWeek() {\n return this._firstDayOfWeek;\n }\n\n set firstDayOfWeek(value: number) {\n value = coerceNumberProperty(value);\n if (value > 6 || value < 0) {\n this._firstDayOfWeek = undefined;\n } else {\n this._firstDayOfWeek = value;\n }\n }\n\n /**\n * Whether to hide dates in other months at the start or end of the current month.\n */\n private _hideOtherMonths = false;\n @Input()\n get hideOtherMonths(): boolean {\n return this._hideOtherMonths;\n }\n\n set hideOtherMonths(val: boolean) {\n this._hideOtherMonths = coerceBooleanProperty(val);\n }\n\n private readonly _id: string;\n get id(): string {\n return this._id;\n }\n\n abstract get selected(): T | null;\n\n abstract get selecteds(): T[] | null;\n\n abstract get dateTimeFilter(): (date: T | null) => boolean;\n\n abstract get maxDateTime(): T | null;\n\n abstract get minDateTime(): T | null;\n\n abstract get selectMode(): SelectMode;\n\n abstract get startAt(): T | null;\n\n abstract get endAt(): T | null;\n\n abstract get opened(): boolean;\n\n abstract get pickerMode(): PickerMode;\n\n abstract get pickerType(): PickerType;\n\n abstract get isInSingleMode(): boolean;\n\n abstract get isInRangeMode(): boolean;\n\n abstract select(date: T | T[]): void;\n\n abstract yearSelected: EventEmitter<T>;\n\n abstract monthSelected: EventEmitter<T>;\n\n abstract dateSelected: EventEmitter<T>;\n\n abstract selectYear(normalizedYear: T): void;\n\n abstract selectMonth(normalizedMonth: T): void;\n\n abstract selectDate(normalizedDate: T): void;\n\n get formatString(): string {\n return this.pickerType === 'both'\n ? this.dateTimeFormats.fullPickerInput\n : this.pickerType === 'calendar'\n ? this.dateTimeFormats.datePickerInput\n : this.dateTimeFormats.timePickerInput;\n }\n\n /**\n * Date Time Checker to check if the give dateTime is selectable\n */\n public dateTimeChecker = (dateTime: T) => {\n return (\n !!dateTime &&\n (!this.dateTimeFilter || this.dateTimeFilter(dateTime)) &&\n (!this.minDateTime ||\n this.dateTimeAdapter.compare(dateTime, this.minDateTime) >=\n 0) &&\n (!this.maxDateTime ||\n this.dateTimeAdapter.compare(dateTime, this.maxDateTime) <= 0)\n );\n };\n\n get disabled(): boolean {\n return false;\n }\n\n protected constructor(\n @Optional() protected dateTimeAdapter: DateTimeAdapter<T>,\n @Optional()\n @Inject(OWL_DATE_TIME_FORMATS)\n protected dateTimeFormats: OwlDateTimeFormats\n ) {\n if (!this.dateTimeAdapter) {\n throw Error(\n `OwlDateTimePicker: No provider found for DateTimeAdapter. You must import one of the following ` +\n `modules at your application root: OwlNativeDateTimeModule, OwlMomentDateTimeModule, or provide a ` +\n `custom implementation.`\n );\n }\n\n if (!this.dateTimeFormats) {\n throw Error(\n `OwlDateTimePicker: No provider found for OWL_DATE_TIME_FORMATS. You must import one of the following ` +\n `modules at your application root: OwlNativeDateTimeModule, OwlMomentDateTimeModule, or provide a ` +\n `custom implementation.`\n );\n }\n\n this._id = `owl-dt-picker-${nextUniqueId++}`;\n }\n\n protected getValidDate(obj: any): T | null {\n return this.dateTimeAdapter.isDateInstance(obj) &&\n this.dateTimeAdapter.isValid(obj)\n ? obj\n : null;\n }\n}\n","/**\n * date-time-picker-intl.service\n */\n\nimport { Injectable } from '@angular/core';\nimport { Subject } from 'rxjs';\n\n@Injectable({providedIn: 'root'})\nexport class OwlDateTimeIntl {\n\n /**\n * Stream that emits whenever the labels here are changed. Use this to notify\n * components if the labels have changed after initialization.\n */\n readonly changes: Subject<void> = new Subject<void>();\n\n /** A label for the up second button (used by screen readers). */\n upSecondLabel = 'Add a second';\n\n /** A label for the down second button (used by screen readers). */\n downSecondLabel = 'Minus a second';\n\n /** A label for the up minute button (used by screen readers). */\n upMinuteLabel = 'Add a minute';\n\n /** A label for the down minute button (used by screen readers). */\n downMinuteLabel = 'Minus a minute';\n\n /** A label for the up hour button (used by screen readers). */\n upHourLabel = 'Add a hour';\n\n /** A label for the down hour button (used by screen readers). */\n downHourLabel = 'Minus a hour';\n\n /** A label for the previous month button (used by screen readers). */\n prevMonthLabel = 'Previous month';\n\n /** A label for the next month button (used by screen readers). */\n nextMonthLabel = 'Next month';\n\n /** A label for the previous year button (used by screen readers). */\n prevYearLabel = 'Previous year';\n\n /** A label for the next year button (used by screen readers). */\n nextYearLabel = 'Next year';\n\n /** A label for the previous multi-year button (used by screen readers). */\n prevMultiYearLabel = 'Previous 21 years';\n\n /** A label for the next multi-year button (used by screen readers). */\n nextMultiYearLabel = 'Next 21 years';\n\n /** A label for the 'switch to month view' button (used by screen readers). */\n switchToMonthViewLabel = 'Change to month view';\n\n /** A label for the 'switch to year view' button (used by screen readers). */\n switchToMultiYearViewLabel = 'Choose month and year';\n\n /** A label for the cancel button */\n cancelBtnLabel = 'Cancel';\n\n /** A label for the set button */\n setBtnLabel = 'Set';\n\n /** A label for the range 'from' in picker info */\n rangeFromLabel = 'From';\n\n /** A label for the range 'to' in picker info */\n rangeToLabel = 'To';\n\n /** A label for the hour12 button (AM) */\n hour12AMLabel = 'AM';\n\n /** A label for the hour12 button (PM) */\n hour12PMLabel = 'PM';\n}\n","/**\n * calendar-body.component\n */\n\nimport {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n NgZone,\n OnInit,\n Output\n} from '@angular/core';\nimport { SelectMode } from './date-time.class';\nimport { take } from 'rxjs/operators';\n\nexport class CalendarCell {\n constructor(\n public value: number,\n public displayValue: string,\n public ariaLabel: string,\n public enabled: boolean,\n public out: boolean = false,\n public cellClass: string = ''\n ) {}\n}\n\n@Component({\n selector: '[owl-date-time-calendar-body]',\n exportAs: 'owlDateTimeCalendarBody',\n templateUrl: './calendar-body.component.html',\n styleUrls: ['./calendar-body.component.scss'],\n host: {\n '[class.owl-dt-calendar-body]': 'owlDTCalendarBodyClass'\n },\n preserveWhitespaces: false,\n standalone: false,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OwlCalendarBodyComponent implements OnInit {\n /**\n * The cell number of the active cell in the table.\n */\n @Input()\n activeCell = 0;\n\n /**\n * The cells to display in the table.\n * */\n @Input()\n rows: CalendarCell[][];\n\n /**\n * The number of columns in the table.\n * */\n @Input()\n numCols = 7;\n\n /**\n * The ratio (width / height) to use for the cells in the table.\n */\n @Input()\n cellRatio = 1;\n\n /**\n * The value in the table that corresponds to today.\n * */\n @Input()\n todayValue: number;\n\n /**\n * The value in the table that is currently selected.\n * */\n @Input()\n selectedValues: number[];\n\n /**\n * Current picker select mode\n */\n @Input()\n selectMode: SelectMode;\n\n /**\n * Emit when a calendar cell is selected\n * */\n @Output()\n public readonly select = new EventEmitter<CalendarCell>();\n\n get owlDTCalendarBodyClass(): boolean {\n return true;\n }\n\n get isInSingleMode(): boolean {\n return this.selectMode === 'single';\n }\n\n get isInRangeMode(): boolean {\n return (\n this.selectMode === 'range' ||\n this.selectMode === 'rangeFrom' ||\n this.selectMode === 'rangeTo'\n );\n }\n\n constructor(private elmRef: ElementRef, private ngZone: NgZone) {}\n\n public ngOnInit() {}\n\n public selectCell(cell: CalendarCell): void {\n this.select.emit(cell);\n }\n\n public isActiveCell(rowIndex: number, colIndex: number): boolean {\n const cellNumber = rowIndex * this.numCols + colIndex;\n return cellNumber === this.activeCell;\n }\n\n /**\n * Check if the cell is selected\n */\n public isSelected(value: number): boolean {\n if (!this.selectedValues || this.selectedValues.length === 0) {\n return false;\n }\n\n if (this.isInSingleMode) {\n return value === this.selectedValues[0];\n }\n\n if (this.isInRangeMode) {\n const fromValue = this.selectedValues[0];\n const toValue = this.selectedValues[1];\n\n return value === fromValue || value === toValue;\n }\n }\n\n /**\n * Check if the cell in the range\n * */\n public isInRange(value: number): boolean {\n if (this.isInRangeMode) {\n const fromValue = this.selectedValues[0];\n const toValue = this.selectedValues[1];\n\n if (fromValue !== null && toValue !== null) {\n return value >= fromValue && value <= toValue;\n } else {\n return value === fromValue || value === toValue;\n }\n }\n }\n\n /**\n * Check if the cell is the range from\n * */\n public isRangeFrom(value: number): boolean {\n if (this.isInRangeMode) {\n const fromValue = this.selectedValues[0];\n return fromValue !== null && value === fromValue;\n }\n }\n\n /**\n * Check if the cell is the range to\n * */\n public isRangeTo(value: number): boolean {\n if (this.isInRangeMode) {\n const toValue = this.selectedValues[1];\n return toValue !== null && value === toValue;\n }\n }\n\n /**\n * Focus to a active cell\n * */\n public focusActiveCell(): void {\n this.ngZone.runOutsideAngular(() => {\n this.ngZone.onStable\n .asObservable()\n .pipe(take(1))\n .subscribe(() => {\n this.elmRef.nativeElement\n .querySelector('.owl-dt-calendar-cell-active')\n .focus();\n });\n });\n }\n}\n","<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","import { InjectionToken, Provider } from '@angular/core';\r\n\r\nexport function defaultOptionsFactory() {\r\n return DefaultOptions.create();\r\n\r\n}\r\nexport function multiYearOptionsFactory(options: Options) {\r\n return options.multiYear;\r\n }\r\n\r\nexport interface Options {\r\n multiYear: {\r\n yearsPerRow: number,\r\n yearRows: number\r\n };\r\n}\r\nexport class DefaultOptions {\r\n public static create(): Options {\r\n // Always return new instance\r\n return {\r\n multiYear: {\r\n yearRows: 7,\r\n yearsPerRow: 3\r\n }\r\n };\r\n }\r\n}\r\n\r\nexport abstract class OptionsTokens {\r\n public static all = new InjectionToken<Options>('All options token');\r\n public static multiYear = new InjectionToken<Options['multiYear']>('Grid view options token');\r\n}\r\n\r\nexport const optionsProviders: Provider[] = [\r\n {\r\n provide: OptionsTokens.all,\r\n useFactory: defaultOptionsFactory,\r\n },\r\n {\r\n provide: OptionsTokens.multiYear,\r\n useFactory: multiYearOptionsFactory,\r\n deps: [OptionsTokens.all],\r\n },\r\n];\r\n","/**\n * calendar-multi-year-view.component\n */\n\nimport {\n AfterContentInit,\n ChangeDetectionStrategy, ChangeDetectorRef,\n Component,\n EventEmitter,\n Inject,\n Input,\n OnInit,\n Optional,\n Output,\n ViewChild\n} from '@angular/core';\nimport { DateTimeAdapter } from './adapter/date-time-adapter.class';\nimport { CalendarCell, OwlCalendarBodyComponent } from './calendar-body.component';\nimport { SelectMode } from './date-time.class';\nimport {\n DOWN_ARROW,\n END,\n ENTER,\n HOME,\n LEFT_ARROW,\n PAGE_DOWN,\n PAGE_UP,\n RIGHT_ARROW,\n UP_ARROW\n} from '@angular/cdk/keycodes';\nimport { OwlDateTimeIntl } from './date-time-picker-intl.service';\nimport { OptionsTokens, Options } from './options-provider';\n\n@Component({\n selector: 'owl-date-time-multi-year-view',\n templateUrl: './calendar-multi-year-view.component.html',\n styleUrls: ['./calendar-multi-year-view.component.scss'],\n host: {\n '[class.owl-dt-calendar-view]': 'owlDTCalendarView',\n '[class.owl-dt-calendar-multi-year-view]': 'owlDTCalendarMultiYearView'\n },\n standalone: false,\n preserveWhitespaces: false,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n\nexport class OwlMultiYearViewComponent<T> implements OnInit, AfterContentInit {\n\n /**\n * The select mode of the picker;\n * */\n private _selectMode: SelectMode = 'single';\n @Input()\n get selectMode(): SelectMode {\n return this._selectMode;\n }\n\n set selectMode( val: SelectMode ) {\n this._selectMode = val;\n if (this.initiated) {\n this.setSelectedYears();\n this.cdRef.markForCheck();\n }\n }\n\n /** The currently selected date. */\n private _selected: T | null;\n @Input()\n get selected(): T | null {\n return this._selected;\n }\n\n set selected( value: T | null ) {\n const oldSelected = this._selected;\n value = this.dateTimeAdapter.deserialize(value);\n this._selected = this.getValidDate(value);\n\n if (!this.dateTimeAdapter.isSameDay(oldSelected, this._selected)) {\n this.setSelectedYears();\n }\n }\n\n private _selecteds: T[] = [];\n @Input()\n get selecteds(): T[] {\n return this._selecteds;\n }\n\n set selecteds( values: T[] ) {\n this._selecteds = values.map(( v ) => {\n v = this.dateTimeAdapter.deserialize(v);\n return this.getValidDate(v);\n });\n this.setSelectedYears();\n }\n\n private _pickerMoment: T | null;\n @Input()\n get pickerMoment() {\n return this._pickerMoment;\n }\n\n set pickerMoment( value: T ) {\n const oldMoment = this._pickerMoment;\n value = this.dateTimeAdapter.deserialize(value);\n this._pickerMoment = this.getValidDate(value) || this.dateTimeAdapter.now();\n\n if (oldMoment && this._pickerMoment &&\n !this.isSameYearList(oldMoment, this._pickerMoment)) {\n this.generateYearList();\n }\n }\n\n /**\n * A function used to filter which dates are selectable\n * */\n private _dateFilter: ( date: T ) => boolean;\n @Input()\n get dateFilter() {\n return this._dateFilter;\n }\n\n set dateFilter( filter: ( date: T ) => boolean ) {\n this._dateFilter = filter;\n if (this.initiated) {\n this.generateYearList();\n }\n }\n\n /** The minimum selectable date. */\n private _minDate: T | null;\n @Input()\n get minDate(): T | null {\n return this._minDate;\n }\n\n set minDate( value: T | null ) {\n value = this.dateTimeAdapter.deserialize(value);\n this._minDate = this.getValidDate(value);\n if (this.initiated) {\n this.generateYearList();\n }\n }\n\n /** The maximum selectable date. */\n private _maxDate: T | null;\n @Input()\n get maxDate(): T | null {\n return this._maxDate;\n }\n\n set maxDate( value: T | null ) {\n value = this.dateTimeAdapter.deserialize(value);\n this._maxDate = this.getValidDate(value);\n if (this.initiated) {\n this.generateYearList();\n }\n }\n\n private _todayYear: number;\n get todayYear(): number {\n return this._todayYear;\n }\n\n private _years: CalendarCell[][];\n get years() {\n return this._years;\n }\n\n private _selectedYears: number[];\n get selectedYears(): number[] {\n return this._selectedYears;\n }\n\n private initiated = false;\n\n get isInSingleMode(): boolean {\n return this.selectMode === 'single';\n }\n\n get isInRangeMode(): boolean {\n return this.selectMode === 'range' || this.selectMode === 'rangeFrom'\n || this.selectMode === 'rangeTo';\n }\n\n get activeCell(): number {\n if (this._pickerMoment) {\n return this.dateTimeAdapter.getYear(this._pickerMoment) % (this.options.yearsPerRow * this.options.yearRows);\n }\n }\n\n get tableHeader(): string {\n if (this._years && this._years.length > 0) {\n return `${this._years[0][0].displayValue} - ${this._years[this.options.yearRows - 1][this.options.yearsPerRow - 1].displayValue}`;\n }\n }\n\n get prevButtonLabel(): string {\n return this.pickerIntl.prevMultiYearLabel;\n }\n\n get nextButtonLabel(): string {\n return this.pickerIntl.nextMultiYearLabel;\n }\n\n /**\n * Callback to invoke when a new month is selected\n * */\n @Output() readonly change = new EventEmitter<T>();\n\n /**\n * Emits the selected year. This doesn't imply a change on the selected date\n * */\n @Output() readonly yearSelected = new EventEmitter<T>();\n\n /** Emits when any date is activated. */\n @Output() readonly pickerMomentChange: EventEmitter<T> = new EventEmitter<T>();\n\n /** Emits when use keyboard enter to select a calendar cell */\n @Output() readonly keyboardEnter: EventEmitter<any> = new EventEmitter<any>();\n\n /** The body of calendar table */\n @ViewChild(OwlCalendarBodyComponent, { static: true }) calendarBodyElm: OwlCalendarBodyComponent;\n\n get owlDTCalendarView(): boolean {\n return true;\n }\n\n get owlDTCalendarMultiYearView(): boolean {\n return true;\n }\n\n constructor( private cdRef: ChangeDetectorRef,\n private pickerIntl: OwlDateTimeIntl,\n @Optional() private dateTimeAdapter: DateTimeAdapter<T>,\n @Inject(OptionsTokens.multiYear) private options: any) {\n }\n\n public ngOnInit() {\n }\n\n public ngAfterContentInit(): void {\n this._todayYear = this.dateTimeAdapter.getYear(this.dateTimeAdapter.now());\n this.generateYearList();\n this.initiated = true;\n }\n\n /**\n * Handle a calendarCell selected\n */\n public selectCalendarCell( cell: CalendarCell ): void {\n this.selectYear(cell.value);\n }\n\n private selectYear( year: number ): void {\n this.yearSelected.emit(this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1));\n const firstDateOfMonth = this.dateTimeAdapter.createDate(\n year,\n this.dateTimeAdapter.getMonth(this.pickerMoment),\n 1\n );\n const daysInMonth = this.dateTimeAdapter.getNumDaysInMonth(firstDateOfMonth);\n const selected = this.dateTimeAdapter.createDate(\n year,\n this.dateTimeAdapter.getMonth(this.pickerMoment),\n Math.min(daysInMonth, this.dateTimeAdapter.getDate(this.pickerMoment)),\n this.dateTimeAdapter.getHours(this.pickerMoment),\n this.dateTimeAdapter.getMinutes(this.pickerMoment),\n this.dateTimeAdapter.getSeconds(this.pickerMoment),\n );\n\n this.change.emit(selected);\n }\n\n /**\n * Generate the previous year list\n * */\n public prevYearList( event: any ): void {\n this._pickerMoment = this.dateTimeAdapter.addCalendarYears(this.pickerMoment, -1 * this.options.yearsPerRow * this.options.yearRows);\n this.generateYearList();\n event.preventDefault();\n }\n\n /**\n * Generate the next year list\n * */\n public nextYearList( event: any ): void {\n this._pickerMoment = this.dateTimeAdapter.addCalendarYears(this.pickerMoment, this.options.yearsPerRow * this.options.yearRows);\n this.generateYearList();\n event.preventDefault();\n }\n\n public generateYearList(): void {\n this._years = [];\n\n const pickerMomentYear = this.dateTimeAdapter.getYear(this._pickerMoment);\n const offset = pickerMomentYear % (this.options.yearsPerRow * this.options.yearRows);\n\n for (let i = 0; i < this.options.yearRows; i++) {\n const row = [];\n\n for (let j = 0; j < this.options.yearsPerRow; j++) {\n const year = pickerMomentYear - offset + (j + i * this.options.yearsPerRow);\n const yearCell = this.createYearCell(year);\n row.push(yearCell);\n }\n\n this._years.push(row);\n }\n\n return;\n\n }\n\n /** Whether the previous period button is enabled. */\n public previousEnabled(): boolean {\n if (!this.minDate) {\n return true;\n }\n return !this.minDate || !this.isSameYearList(this._pickerMoment, this.minDate);\n }\n\n /** Whether the next period button is enabled. */\n public nextEnabled(): boolean {\n return !this.maxDate || !this.isSameYearList(this._pickerMoment, this.maxDate);\n }\n\n public handleCalendarKeydown( event: KeyboardEvent ): void {\n let moment;\n switch (event.keyCode) {\n // minus 1 year\n case LEFT_ARROW:\n moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, -1);\n this.pickerMomentChange.emit(moment);\n break;\n\n // add 1 year\n case RIGHT_ARROW:\n moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, 1);\n this.pickerMomentChange.emit(moment);\n break;\n\n // minus 3 years\n case UP_ARROW:\n moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, -1 * this.options.yearsPerRow);\n this.pickerMomentChange.emit(moment);\n break;\n\n // add 3 years\n case DOWN_ARROW:\n moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment, this.options.yearsPerRow);\n this.pickerMomentChange.emit(moment);\n break;\n\n // go to the first year of the year page\n case HOME:\n moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment,\n -this.dateTimeAdapter.getYear(this._pickerMoment) % (this.options.yearsPerRow * this.options.yearRows));\n this.pickerMomentChange.emit(moment);\n break;\n\n // go to the last year of the year page\n case END:\n moment = this.dateTimeAdapter.addCalendarYears(this._pickerMoment,\n (this.options.yearsPerRow * this.options.yearRows) - this.dateTimeAdapter.getYear(this._pickerMoment) % (this.options.yearsPerRow * this.options.yearRows) - 1);\n this.pickerMomentChange.emit(moment);\n break;\n\n // minus 1 year page (or 10 year pages)\n case PAGE_UP:\n moment = this.dateTimeAdapter.addCalendarYears(this.pickerMoment, event.altKey ? -10 * (this.options.yearsPerRow * this.options.yearRows) : -1 * (this.options.yearsPerRow * this.options.yearRows));\n this.pickerMomentChange.emit(moment);\n break;\n\n // add 1 year page (or 10 year pages)\n case PAGE_DOWN:\n moment = this.dateTimeAdapter.addCalendarYears(this.pickerMoment, event.altKey ? 10 * (this.options.yearsPerRow * this.options.yearRows) : (this.options.yearsPerRow * this.options.yearRows));\n this.pickerMomentChange.emit(moment);\n break;\n\n case ENTER:\n this.selectYear(this.dateTimeAdapter.getYear(this._pickerMoment));\n this.keyboardEnter.emit();\n break;\n\n default:\n return;\n }\n\n this.focusActiveCell();\n event.preventDefault();\n }\n\n /**\n * Creates an CalendarCell for the given year.\n */\n private createYearCell( year: number ): CalendarCell {\n const startDateOfYear = this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1);\n const ariaLabel = this.dateTimeAdapter.getYearName(startDateOfYear);\n const cellClass = 'owl-dt-year-' + year;\n return new CalendarCell(year, year.toString(), ariaLabel, this.isYearEnabled(year), false, cellClass);\n }\n\n private setSelectedYears(): void {\n\n this._selectedYears = [];\n\n if (this.isInSingleMode && this.selected) {\n this._selectedYears[0] = this.dateTimeAdapter.getYear(this.selected);\n }\n\n if (this.isInRangeMode && this.selecteds) {\n this._selectedYears = this.selecteds.map(( selected ) => {\n if (this.dateTimeAdapter.isValid(selected)) {\n return this.dateTimeAdapter.getYear(selected);\n } else {\n return null;\n }\n });\n }\n }\n\n /** Whether the given year is enabled. */\n private isYearEnabled( year: number ) {\n // disable if the year is greater than maxDate lower than minDate\n if (year === undefined || year === null ||\n (this.maxDate && year > this.dateTimeAdapter.getYear(this.maxDate)) ||\n (this.minDate && year < this.dateTimeAdapter.getYear(this.minDate))) {\n return false;\n }\n\n // enable if it reaches here and there's no filter defined\n if (!this.dateFilter) {\n return true;\n }\n\n const firstOfYear = this.dateTimeAdapter.createDate(year, this.dateTimeAdapter.firstMonthOfTheYear, 1);\n\n // If any date in the year is enabled count the year as enabled.\n for (let date = firstOfYear; this.dateTimeAdapter.getYear(date) === year;\n date = this.dateTimeAdapter.addCalendarDays(date, 1)) {\n if (this.dateFilter(date)) {\n return true;\n }\n }\n\n return false;\n }\n\n private isSameYearList( date1: T, date2: T ): boolean {\n return Math.floor(this.dateTimeAdapter.getYear(date1) / (this.options.yearsPerRow * this.options.yearRows)) ===\n Math.floor(this.dateTimeAdapter.getYear(date2) / (this.options.yearsPerRow * this.options.yearRows));\n }\n\n /**\n * Get a valid date object\n */\n private getValidDate( obj: any ): T | null {\n return (this.dateTimeAdapter.isDateInstance(obj) && this.dateTimeAdapter.isValid(obj)) ? obj : null;\n }\n\n private focusActiveCell() {\n this.calendarBodyElm.focusActiveCell();\n }\n}\n","<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,11