@netwin/angular-datetime-picker
Version:
Angular Date Time Picker
1 lines • 271 kB
Source Map (JSON)
{"version":3,"file":"netwin-angular-datetime-picker.mjs","sources":["../../../projects/picker/src/lib/date-time/adapter/date-time-adapter.class.ts","../../../projects/picker/src/lib/date-time/adapter/date-time-format.class.ts","../../../projects/picker/src/lib/utils/array.utils.ts","../../../projects/picker/src/lib/utils/constants.ts","../../../projects/picker/src/lib/utils/date.utils.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/calendar-body.component.ts","../../../projects/picker/src/lib/date-time/calendar-body.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/date-time-picker-intl.service.ts","../../../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/date-time.class.ts","../../../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-container.component.ts","../../../projects/picker/src/lib/date-time/date-time-picker-container.component.html","../../../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/date-time/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/netwin-angular-datetime-picker.ts"],"sourcesContent":["/**\n * date-time-adapter.class\n */\nimport { InjectionToken, LOCALE_ID, inject } from '@angular/core';\nimport { Subject } from 'rxjs';\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>('OWL_DATE_TIME_LOCALE', {\n providedIn: 'root',\n factory: OWL_DATE_TIME_LOCALE_FACTORY\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: string;\n\n /** A stream that emits when the locale changes. */\n protected _localeChanges = new Subject<string>();\n public localeChanges = this._localeChanges.asObservable();\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 public abstract getYear(date: T): number;\n\n /**\n * Get the month of the given date\n * 0 -- January\n * 11 -- December\n */\n public 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 public abstract getDay(date: T): number;\n\n /**\n * Get the day num of the given date\n */\n public abstract getDate(date: T): number;\n\n /**\n * Get the hours of the given date\n */\n public abstract getHours(date: T): number;\n\n /**\n * Get the minutes of the given date\n */\n public abstract getMinutes(date: T): number;\n\n /**\n * Get the seconds of the given date\n */\n public abstract getSeconds(date: T): number;\n\n /**\n * Get the milliseconds timestamp of the given date\n */\n public abstract getTime(date: T): number;\n\n /**\n * Gets the number of days in the month of the given date.\n */\n public 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 public abstract differenceInCalendarDays(dateLeft: T, dateRight: T): number;\n\n /**\n * Gets the name for the year of the given date.\n */\n public abstract getYearName(date: T): string;\n\n /**\n * Get a list of month names\n */\n public abstract getMonthNames(style: Intl.DateTimeFormatOptions['month']): Array<string>;\n\n /**\n * Get a list of week names\n */\n public abstract getDayOfWeekNames(style: Intl.DateTimeFormatOptions['weekday']): Array<string>;\n\n /**\n * Gets a list of names for the dates of the month.\n */\n public abstract getDateNames(): Array<string>;\n\n /**\n * Return a Date object as a string, using the ISO standard\n */\n public abstract toIso8601(date: T): string;\n\n /**\n * Check if the give dates are equal\n */\n public abstract isEqual(dateLeft: T, dateRight: T): boolean;\n\n /**\n * Check if the give dates are the same day\n */\n public abstract isSameDay(dateLeft: T, dateRight: T): boolean;\n\n /**\n * Checks whether the given date is valid.\n */\n public abstract isValid(date: T): boolean;\n\n /**\n * Gets date instance that is not valid.\n */\n public abstract invalid(): T;\n\n /**\n * Checks whether the given object is considered a date instance by this DateTimeAdapter.\n */\n public abstract isDateInstance(obj: unknown): obj is T;\n\n /**\n * Add the specified number of years to the given date\n */\n public abstract addCalendarYears(date: T, amount: number): T;\n\n /**\n * Add the specified number of months to the given date\n */\n public abstract addCalendarMonths(date: T, amount: number): T;\n\n /**\n * Add the specified number of days to the given date\n */\n public abstract addCalendarDays(date: T, amount: number): T;\n\n /**\n * Set the hours to the given date.\n */\n public abstract setHours(date: T, amount: number): T;\n\n /**\n * Set the minutes to the given date.\n */\n public abstract setMinutes(date: T, amount: number): T;\n\n /**\n * Set the seconds to the given date.\n */\n public 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 public abstract createDate(year: number, month: number, date: number): T;\n public 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 public abstract clone(date: T): T;\n\n /**\n * Get a new moment\n */\n public abstract now(): T;\n\n /**\n * Formats a date as a string according to the given format.\n */\n public abstract format(date: T, displayFormat: Intl.DateTimeFormatOptions): string;\n\n /**\n * Parse a user-provided value to a Date Object\n */\n public abstract parse(value: unknown): 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 public 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 public 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 public deserialize(value: T | null): T | null {\n if (value == null || (this.isDateInstance(value) && this.isValid(value))) {\n return value;\n }\n return this.invalid();\n }\n\n /**\n * Sets the locale used for all dates.\n */\n public setLocale(locale: string): void {\n this.locale = locale;\n this._localeChanges.next(locale);\n }\n\n /**\n * Get the locale used for all dates.\n */\n public getLocale(): string {\n return this.locale;\n }\n\n /**\n * Clamp the given date between min and max dates.\n */\n public 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-format.class\n */\n\nimport { InjectionToken } from '@angular/core';\n\nexport type OwlDateTimeFormats = {\n fullPickerInput: Partial<Intl.DateTimeFormatOptions>;\n datePickerInput: Partial<Intl.DateTimeFormatOptions>;\n timePickerInput: Partial<Intl.DateTimeFormatOptions>;\n monthYearLabel: Partial<Intl.DateTimeFormatOptions>;\n dateA11yLabel: Partial<Intl.DateTimeFormatOptions>;\n monthYearA11yLabel: Partial<Intl.DateTimeFormatOptions>;\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","/** Creates an array and fills it with values. */\nexport function range<T>(length: number, valueFunction: (index: number) => T): Array<T> {\n return new Array<T>(length).fill(null).map((_, index) => valueFunction(index));\n}\n","import { range } from './array.utils';\n\n/** Whether the browser supports the Intl API. */\nexport const SUPPORTS_INTL_API = typeof Intl !== 'undefined';\n\n/** The default month names to use if Intl API is not available. */\nexport const DEFAULT_MONTH_NAMES = {\n long: [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December'\n ],\n short: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n narrow: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D']\n};\n\n/** The default day of the week names to use if Intl API is not available. */\nexport const DEFAULT_DAY_OF_WEEK_NAMES = {\n long: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],\n short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n narrow: ['S', 'M', 'T', 'W', 'T', 'F', 'S']\n};\n\n/** The default date names to use if Intl API is not available. */\nexport const DEFAULT_DATE_NAMES = range(31, (i) => String(i + 1));\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 */\nexport function createDate(\n year: number,\n month: number,\n date: number,\n hours: number = 0,\n minutes: number = 0,\n seconds: number = 0\n): Date {\n if (month < 0 || month > 11) {\n throw Error(`Invalid month index \"${month}\". Month index has to be between 0 and 11.`);\n }\n\n if (date < 1) {\n throw Error(`Invalid date \"${date}\". Date has to be greater than 0.`);\n }\n\n if (hours < 0 || hours > 23) {\n throw Error(`Invalid hours \"${hours}\". Hours has to be between 0 and 23.`);\n }\n\n if (minutes < 0 || minutes > 59) {\n throw Error(`Invalid minutes \"${minutes}\". Minutes has to between 0 and 59.`);\n }\n\n if (seconds < 0 || seconds > 59) {\n throw Error(`Invalid seconds \"${seconds}\". Seconds has to be between 0 and 59.`);\n }\n\n const result = createDateWithOverflow(year, month, date, hours, minutes, seconds);\n\n // Check that the date wasn't above the upper bound for the month, causing the month to overflow\n // For example, createDate(2017, 1, 31) would try to create a date 2017/02/31 which is invalid\n if (result.getMonth() !== month) {\n throw Error(`Invalid date \"${date}\" for month with index \"${month}\".`);\n }\n\n return result;\n}\n\n/**\n * Gets the number of days in the month of the given date.\n */\nexport function getNumDaysInMonth(date: Date): number {\n const lastDateOfMonth = createDateWithOverflow(date.getFullYear(), date.getMonth() + 1, 0);\n\n return lastDateOfMonth.getDate();\n}\n\n/**\n * Creates a date but allows the month and date to overflow.\n */\nfunction createDateWithOverflow(\n year: number,\n month: number,\n date: number,\n hours: number = 0,\n minutes: number = 0,\n seconds: number = 0\n): Date {\n const result = new Date(year, month, date, hours, minutes, seconds);\n\n if (year >= 0 && year < 100) {\n result.setFullYear(result.getFullYear() - 1900);\n }\n return result;\n}\n","/**\n * native-date-time-adapter.class\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { inject, Injectable } from '@angular/core';\nimport { range } from '../../utils/array.utils';\nimport {\n DEFAULT_DATE_NAMES,\n DEFAULT_DAY_OF_WEEK_NAMES,\n DEFAULT_MONTH_NAMES,\n SUPPORTS_INTL_API\n} from '../../utils/constants';\nimport { createDate, getNumDaysInMonth } from '../../utils/date.utils';\nimport { DateTimeAdapter, OWL_DATE_TIME_LOCALE } from './date-time-adapter.class';\n\n/**\n * Matches strings that have the form of a valid RFC 3339 string\n * (https://tools.ietf.org/html/rfc3339). Note that the string may not actually be a valid date\n * because the regex will match strings an with out of bounds month, date, etc.\n */\nconst ISO_8601_REGEX = /^\\d{4}-\\d{2}-\\d{2}(?:T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|(?:[+-]\\d{2}:\\d{2}))?)?$/;\n\n@Injectable()\nexport class NativeDateTimeAdapter extends DateTimeAdapter<Date> {\n private readonly owlDateTimeLocale = inject(OWL_DATE_TIME_LOCALE, { optional: true });\n private readonly platform = inject(Platform);\n\n /** Whether to clamp the date between 1 and 9999 to avoid IE and Edge errors. */\n private readonly _clampDate: boolean;\n\n /**\n * Whether to use `timeZone: 'utc'` with `Intl.DateTimeFormat` when formatting dates.\n * Without this `Intl.DateTimeFormat` sometimes chooses the wrong timeZone, which can throw off\n * the result. (e.g. in the en-US locale `new Date(1800, 7, 14).toLocaleDateString()`\n * will produce `'8/13/1800'`.\n */\n public useUtcForDisplay: boolean;\n\n constructor() {\n super();\n super.setLocale(this.owlDateTimeLocale);\n\n // IE does its own time zone correction, so we disable this on IE.\n this.useUtcForDisplay = !this.platform.TRIDENT;\n this._clampDate = this.platform.TRIDENT || this.platform.EDGE;\n }\n\n public getYear(date: Date): number {\n return date.getFullYear();\n }\n\n public getMonth(date: Date): number {\n return date.getMonth();\n }\n\n public getDay(date: Date): number {\n return date.getDay();\n }\n\n public getDate(date: Date): number {\n return date.getDate();\n }\n\n public getHours(date: Date): number {\n return date.getHours();\n }\n\n public getMinutes(date: Date): number {\n return date.getMinutes();\n }\n\n public getSeconds(date: Date): number {\n return date.getSeconds();\n }\n\n public getTime(date: Date): number {\n return date.getTime();\n }\n\n public getNumDaysInMonth(date: Date): number {\n return getNumDaysInMonth(date);\n }\n\n public differenceInCalendarDays(dateLeft: Date, dateRight: Date): number {\n if (this.isValid(dateLeft) && this.isValid(dateRight)) {\n const dateLeftStartOfDay = this.createDate(\n this.getYear(dateLeft),\n this.getMonth(dateLeft),\n this.getDate(dateLeft)\n );\n const dateRightStartOfDay = this.createDate(\n this.getYear(dateRight),\n this.getMonth(dateRight),\n this.getDate(dateRight)\n );\n\n const timeStampLeft =\n this.getTime(dateLeftStartOfDay) - dateLeftStartOfDay.getTimezoneOffset() * this.milliseondsInMinute;\n const timeStampRight =\n this.getTime(dateRightStartOfDay) - dateRightStartOfDay.getTimezoneOffset() * this.milliseondsInMinute;\n return Math.round((timeStampLeft - timeStampRight) / this.millisecondsInDay);\n } else {\n return null;\n }\n }\n\n public getYearName(date: Date): string {\n if (SUPPORTS_INTL_API) {\n const dtf = new Intl.DateTimeFormat(this.getLocale(), {\n year: 'numeric',\n timeZone: 'utc'\n });\n return this.stripDirectionalityCharacters(this._format(dtf, date));\n }\n return String(this.getYear(date));\n }\n\n public getMonthNames(style: Intl.DateTimeFormatOptions['month']): Array<string> {\n if (SUPPORTS_INTL_API) {\n const dtf = new Intl.DateTimeFormat(this.getLocale(), { month: style, timeZone: 'utc' });\n return range(12, (i) => this.stripDirectionalityCharacters(this._format(dtf, new Date(2017, i, 1))));\n }\n return DEFAULT_MONTH_NAMES[style];\n }\n\n public getDayOfWeekNames(style: Intl.DateTimeFormatOptions['weekday']): Array<string> {\n if (SUPPORTS_INTL_API) {\n const dtf = new Intl.DateTimeFormat(this.getLocale(), { weekday: style, timeZone: 'utc' });\n return range(7, (i) => this.stripDirectionalityCharacters(this._format(dtf, new Date(2017, 0, i + 1))));\n }\n\n return DEFAULT_DAY_OF_WEEK_NAMES[style];\n }\n\n public getDateNames(): Array<string> {\n if (SUPPORTS_INTL_API) {\n const dtf = new Intl.DateTimeFormat(this.getLocale(), { day: 'numeric', timeZone: 'utc' });\n return range(31, (i) => this.stripDirectionalityCharacters(this._format(dtf, new Date(2017, 0, i + 1))));\n }\n return DEFAULT_DATE_NAMES;\n }\n\n public toIso8601(date: Date): string {\n return date.toISOString();\n }\n\n public isEqual(dateLeft: Date, dateRight: Date): boolean {\n if (this.isValid(dateLeft) && this.isValid(dateRight)) {\n return dateLeft.getTime() === dateRight.getTime();\n }\n return false;\n }\n\n public isSameDay(dateLeft: Date, dateRight: Date): boolean {\n if (this.isValid(dateLeft) && this.isValid(dateRight)) {\n const dateLeftStartOfDay = this.clone(dateLeft);\n const dateRightStartOfDay = this.clone(dateRight);\n dateLeftStartOfDay.setHours(0, 0, 0, 0);\n dateRightStartOfDay.setHours(0, 0, 0, 0);\n return dateLeftStartOfDay.getTime() === dateRightStartOfDay.getTime();\n }\n return false;\n }\n\n public isValid(date: Date): boolean {\n return date && !isNaN(date.getTime());\n }\n\n public invalid(): Date {\n return new Date(NaN);\n }\n\n public isDateInstance(obj: unknown): obj is Date {\n return obj instanceof Date;\n }\n\n public addCalendarYears(date: Date, amount: number): Date {\n return this.addCalendarMonths(date, amount * 12);\n }\n\n public addCalendarMonths(date: Date, amount: number): Date {\n const result = this.clone(date);\n amount = Number(amount);\n\n const desiredMonth = result.getMonth() + amount;\n const dateWithDesiredMonth = new Date(0);\n dateWithDesiredMonth.setFullYear(result.getFullYear(), desiredMonth, 1);\n dateWithDesiredMonth.setHours(0, 0, 0, 0);\n\n const daysInMonth = this.getNumDaysInMonth(dateWithDesiredMonth);\n // Set the last day of the new month\n // if the original date was the last day of the longer month\n result.setMonth(desiredMonth, Math.min(daysInMonth, result.getDate()));\n return result;\n }\n\n public addCalendarDays(date: Date, amount: number): Date {\n const result = this.clone(date);\n amount = Number(amount);\n result.setDate(result.getDate() + amount);\n return result;\n }\n\n public setHours(date: Date, amount: number): Date {\n const result = this.clone(date);\n result.setHours(amount);\n return result;\n }\n\n public setMinutes(date: Date, amount: number): Date {\n const result = this.clone(date);\n result.setMinutes(amount);\n return result;\n }\n\n public setSeconds(date: Date, amount: number): Date {\n const result = this.clone(date);\n result.setSeconds(amount);\n return result;\n }\n\n public createDate(\n year: number,\n month: number,\n date: number,\n hours: number = 0,\n minutes: number = 0,\n seconds: number = 0\n ): Date {\n return createDate(year, month, date, hours, minutes, seconds);\n }\n\n public clone(date: Date): Date {\n return this.createDate(\n this.getYear(date),\n this.getMonth(date),\n this.getDate(date),\n this.getHours(date),\n this.getMinutes(date),\n this.getSeconds(date)\n );\n }\n\n public now(): Date {\n return new Date();\n }\n\n public format(date: Date, displayFormat: Intl.DateTimeFormatOptions): string {\n if (!this.isValid(date)) {\n throw Error('JSNativeDate: Cannot format invalid date.');\n }\n\n if (SUPPORTS_INTL_API) {\n if (this._clampDate && (date.getFullYear() < 1 || date.getFullYear() > 9999)) {\n date = this.clone(date);\n date.setFullYear(Math.max(1, Math.min(9999, date.getFullYear())));\n }\n\n displayFormat = { ...displayFormat, timeZone: 'utc' };\n const dtf = new Intl.DateTimeFormat(this.getLocale(), displayFormat);\n return this.stripDirectionalityCharacters(this._format(dtf, date));\n }\n\n return this.stripDirectionalityCharacters(date.toDateString());\n }\n\n public parse(value: number | string): Date | null {\n // There is no way using the native JS Date to set the parse format or locale\n if (typeof value === 'number') {\n return new Date(value);\n }\n return value ? new Date(Date.parse(value)) : null;\n }\n\n /**\n * Returns the given value if given a valid Date or null. Deserializes valid ISO 8601 strings\n * (https://www.ietf.org/rfc/rfc3339.txt) into valid Dates and empty string into null. Returns an\n * invalid date for all other values.\n */\n public override deserialize(value: Date | null): Date | null {\n if (typeof value === 'string') {\n if (!value) {\n return null;\n }\n // The `Date` constructor accepts formats other than ISO 8601, so we need to make sure the\n // string is the right format first.\n if (ISO_8601_REGEX.test(value)) {\n const date = new Date(value);\n if (this.isValid(date)) {\n return date;\n }\n }\n }\n return super.deserialize(value);\n }\n\n /**\n * Strip out unicode LTR and RTL characters. Edge and IE insert these into formatted dates while\n * other browsers do not. We remove them to make output consistent and because they interfere with\n * date parsing.\n */\n private stripDirectionalityCharacters(str: string): string {\n return str.replace(/[\\u200e\\u200f]/g, '');\n }\n\n /**\n * When converting Date object to string, javascript built-in functions may return wrong\n * results because it applies its internal DST rules. The DST rules around the world change\n * very frequently, and the current valid rule is not always valid in previous years though.\n * We work around this problem building a new Date object which has its internal UTC\n * representation with the local date and time.\n */\n private _format(dtf: Intl.DateTimeFormat, date: Date): string {\n const d = new Date(\n Date.UTC(\n date.getFullYear(),\n date.getMonth(),\n date.getDate(),\n date.getHours(),\n date.getMinutes(),\n date.getSeconds(),\n date.getMilliseconds()\n )\n );\n return dtf.format(d);\n }\n}\n","/**\n * native-date-time-format.class\n */\nimport { OwlDateTimeFormats } from './date-time-format.class';\n\nexport const OWL_NATIVE_DATE_TIME_FORMATS: OwlDateTimeFormats = {\n fullPickerInput: {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric'\n },\n datePickerInput: { year: 'numeric', month: 'numeric', day: 'numeric' },\n timePickerInput: { hour: 'numeric', minute: 'numeric' },\n monthYearLabel: { year: 'numeric', month: 'short' },\n dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },\n monthYearA11yLabel: { year: 'numeric', month: 'long' }\n};\n","/**\n * native-date-time.module\n */\n\nimport { PlatformModule } from '@angular/cdk/platform';\nimport { NgModule } from '@angular/core';\nimport { DateTimeAdapter } from './date-time-adapter.class';\nimport { OWL_DATE_TIME_FORMATS } from './date-time-format.class';\nimport { NativeDateTimeAdapter } from './native-date-time-adapter.class';\nimport { OWL_NATIVE_DATE_TIME_FORMATS } from './native-date-time-format.class';\n\n@NgModule({\n imports: [PlatformModule],\n providers: [{ provide: DateTimeAdapter, useClass: NativeDateTimeAdapter }]\n})\nexport class NativeDateTimeModule {}\n\n@NgModule({\n imports: [NativeDateTimeModule],\n providers: [\n {\n provide: OWL_DATE_TIME_FORMATS,\n useValue: OWL_NATIVE_DATE_TIME_FORMATS\n }\n ]\n})\nexport class OwlNativeDateTimeModule {}\n","import { ChangeDetectionStrategy, Component, ElementRef, inject, Input, NgZone, output } from '@angular/core';\nimport { take } from 'rxjs/operators';\nimport { SelectMode } from './date-time.class';\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 host: { 'class': 'owl-dt-calendar-body' },\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OwlCalendarBodyComponent {\n private readonly elmRef = inject(ElementRef);\n private readonly ngZone = inject(NgZone);\n\n /**\n * The cell number of the active cell in the table.\n */\n @Input()\n public activeCell = 0;\n\n /**\n * The cells to display in the table.\n */\n @Input()\n public rows: Array<Array<CalendarCell>>;\n\n /**\n * The number of columns in the table.\n */\n @Input()\n public numCols = 7;\n\n /**\n * The ratio (width / height) to use for the cells in the table.\n */\n @Input()\n public cellRatio = 1;\n\n /**\n * The value in the table that corresponds to today.\n */\n @Input()\n public todayValue: number;\n\n /**\n * The value in the table that is currently selected.\n */\n @Input()\n public selectedValues: Array<number>;\n\n /**\n * Current picker select mode\n */\n @Input()\n public selectMode: SelectMode;\n\n /**\n * Emit when a calendar cell is selected\n */\n public readonly selectCell = output<CalendarCell>();\n\n protected handleSelect(cell: CalendarCell): void {\n this.selectCell.emit(cell);\n }\n\n protected get isInSingleMode(): boolean {\n return this.selectMode === 'single';\n }\n\n protected get isInRangeMode(): boolean {\n return this.selectMode === 'range' || this.selectMode === 'rangeFrom' || this.selectMode === 'rangeTo';\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 return false;\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 return false;\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 return false;\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 return false;\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.querySelector('.owl-dt-calendar-cell-active').focus();\n });\n });\n }\n}\n","@for (row of rows; track rowIndex; let rowIndex = $index) {\n <tr role=\"row\">\n @for (item of row; track colIndex; let colIndex = $index) {\n <td\n [attr.aria-current]=\"item.value === todayValue ? 'date' : null\"\n [attr.aria-disabled]=\"!item.enabled || null\"\n [attr.aria-label]=\"item.ariaLabel\"\n [attr.aria-selected]=\"isSelected(item.value)\"\n [class]=\"item.cellClass\"\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 [style.paddingBottom.%]=\"(50 * cellRatio) / numCols\"\n [style.paddingTop.%]=\"(50 * cellRatio) / numCols\"\n [style.width.%]=\"100 / numCols\"\n [tabindex]=\"isActiveCell(rowIndex, colIndex) ? 0 : -1\"\n (click)=\"handleSelect(item)\"\n class=\"owl-dt-calendar-cell\">\n <span\n [class.owl-dt-calendar-cell-out]=\"item.out\"\n [class.owl-dt-calendar-cell-selected]=\"isSelected(item.value)\"\n [class.owl-dt-calendar-cell-today]=\"item.value === todayValue\"\n class=\"owl-dt-calendar-cell-content\">\n {{ item.displayValue }}\n </span>\n </td>\n }\n </tr>\n}\n","import {\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 { getLocaleFirstDayOfWeek } from '@angular/common';\nimport {\n AfterContentInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n Input,\n OnDestroy,\n OnInit,\n ViewChild,\n inject,\n output\n} from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { DateTimeAdapter } from './adapter/date-time-adapter.class';\nimport { OWL_DATE_TIME_FORMATS } from './adapter/date-time-format.class';\nimport { CalendarCell, OwlCalendarBodyComponent } from './calendar-body.component';\nimport { SelectMode } from './date-time.class';\n\nconst DAYS_PER_WEEK = 7;\nconst WEEKS_PER_VIEW = 6;\n\n@Component({\n selector: 'owl-date-time-month-view',\n exportAs: 'owlYearView',\n templateUrl: './calendar-month-view.component.html',\n imports: [OwlCalendarBodyComponent],\n host: { 'class': 'owl-dt-calendar-view' },\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OwlMonthViewComponent<T> implements OnInit, AfterContentInit, OnDestroy {\n private readonly cdRef = inject(ChangeDetectorRef);\n private readonly dateTimeAdapter = inject(DateTimeAdapter<T>, { optional: true });\n private readonly dateTimeFormats = inject(OWL_DATE_TIME_FORMATS, { optional: true });\n\n /**\n * Whether to hide dates in other months at the start or end of the current month.\n */\n @Input()\n public hideOtherMonths = false;\n\n private isDefaultFirstDayOfWeek = true;\n\n /**\n * Define the first day of a week\n * Sunday: 0 - Saturday: 6\n */\n private _firstDayOfWeek: number;\n\n @Input()\n public get firstDayOfWeek(): number {\n return this._firstDayOfWeek;\n }\n\n public set firstDayOfWeek(val: number) {\n if (val >= 0 && val <= 6 && val !== this._firstDayOfWeek) {\n this._firstDayOfWeek = val;\n this.isDefaultFirstDayOfWeek = false;\n\n if (this.initiated) {\n this.generateWeekDays();\n this.generateCalendar();\n this.cdRef.markForCheck();\n }\n }\n }\n\n /**\n * The select mode of the picker;\n */\n private _selectMode: SelectMode = 'single';\n @Input()\n public get selectMode(): SelectMode {\n return this._selectMode;\n }\n\n public set selectMode(val: SelectMode) {\n this._selectMode = val;\n if (this.initiated) {\n this.generateCalendar();\n this.cdRef.markForCheck();\n }\n }\n\n /** The currently selected date. */\n private _selected: T | null;\n @Input()\n public get selected(): T | null {\n return this._selected;\n }\n\n public 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.setSelectedDates();\n }\n }\n\n private _selecteds: Array<T> = [];\n @Input()\n public get selecteds(): Array<T> {\n return this._selecteds;\n }\n\n public set selecteds(values: Array<T>) {\n this._selecteds = values.map((v) => {\n v = this.dateTimeAdapter.deserialize(v);\n return this.getValidDate(v);\n });\n this.setSelectedDates();\n }\n\n private _pickerMoment: T;\n @Input()\n public get pickerMoment(): T {\n return this._pickerMoment;\n }\n\n public 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 this.firstDateOfMonth = this.dateTimeAdapter.createDate(\n this.dateTimeAdapter.getYear(this._pickerMoment),\n this.dateTimeAdapter.getMonth(this._pickerMoment),\n 1\n );\n\n if (!this.isSameMonth(oldMoment, this._pickerMoment) && this.initiated) {\n this.generateCalendar();\n }\n }\n\n /**\n * A function used to filter which dates are selectable\n */\n private _dateFilter: (date: T) => boolean;\n @Input()\n public get dateFilter(): (date: T) => boolean {\n return this._dateFilter;\n }\n\n public set dateFilter(filter: (date: T) => boolean) {\n this._dateFilter = filter;\n if (this.initiated) {\n this.generateCalendar();\n this.cdRef.markForCheck();\n }\n }\n\n /** The minimum selectable date. */\n private _minDate: T | null;\n @Input()\n public get minDate(): T | null {\n return this._minDate;\n }\n\n public set minDate(value: T | null) {\n value = this.dateTimeAdapter.deserialize(value);\n this._minDate = this.getValidDate(value);\n if (this.initiated) {\n this.generateCalendar();\n this.cdRef.markForCheck();\n }\n }\n\n /** The maximum selectable date. */\n private _maxDate: T | null;\n @Input()\n public get maxDate(): T | null {\n return this._maxDate;\n }\n\n public set maxDate(value: T | null) {\n value = this.dateTimeAdapter.deserialize(value);\n this._maxDate = this.getValidDate(value);\n\n if (this.initiated) {\n this.generateCalendar();\n this.cdRef.markForCheck();\n }\n }\n\n private _weekdays: Array<Record<Intl.DateTimeFormatOptions['weekday'], string>>;\n get weekdays(): Array<Record<Intl.DateTimeFormatOptions['weekday'], string>> {\n return this._weekdays;\n }\n\n private _days: Array<Array<CalendarCell>>;\n get days(): Array<Array<CalendarCell>> {\n return this._days;\n }\n\n get activeCell(): number {\n if (this.pickerMoment) {\n return this.dateTimeAdapter.getDate(this.pickerMoment) + this.firstRowOffset - 1;\n }\n return undefined;\n }\n\n get isInSingleMode(): boolean {\n return this.selectMode === 'single';\n }\n\n get isInRangeMode(): boolean {\n return this.selectMode === 'range' || this.selectMode === 'rangeFrom' || this.selectMode === 'rangeTo';\n }\n\n private firstDateOfMonth: T;\n\n private localeSub: Subscription = Subscription.EMPTY;\n\n private initiated = false;\n\n private dateNames: Array<string>;\n\n /**\n * The date of the month that today falls on.\n */\n public todayDate: number | null;\n\n /**\n * An array to hold all selectedDates' value\n * the value is the day number in current month\n */\n public selectedDates: Array<number> = [];\n\n // the index of cell that contains the first date of the month\n public firstRowOffset: number;\n\n /**\n * Callback to invoke when a new date is selected\n */\n public readonly selectedChange = output<T | null>();\n\n /**\n * Callback to invoke when any date is selected.\n */\n public readonly userSelection = output<void>();\n\n /** Emits when any date is activated. */\n public readonly pickerMomentChange = output<T>();\n\n /** The body of calendar table */\n @ViewChild(OwlCalendarBodyComponent, { static: true })\n calendarBodyElm: OwlCalendarBodyComponent;\n\n public ngOnInit(): void {\n this.updateFirstDayOfWeek(this.dateTimeAdapter.getLocale());\n this.generateWeekDays();\n\n this.localeSub = this.dateTimeAdapter.localeChanges.subscribe((locale) => {\n this.updateFirstDayOfWeek(locale);\n this.generateWeekDays();\n this.generateCalendar();\n this.cdRef.markForCheck();\n });\n }\n\n public ngAfterContentInit(): void {\n this.generateCalendar();\n this.initiated = true;\n }\n\n public ngOnDestroy(): void {\n this.localeSub.unsubscribe();\n }\n\n /**\n * Handle a calendarCell selected\n */\n public selectCalendarCell(cell: CalendarCell): void {\n // Cases in which the date would not be selected\n // 1, the calendar cell is NOT enabled (is NOT valid)\n // 2, the selected date is NOT in current picker's month and the hideOtherMonths is enabled\n if (!cell.enabled || (this.hideOtherMonths && cell.out)) {\n return;\n }\n\n this.selectDate(cell.value);\n }\n\n /**\n * Handle a new date selected\n */\n private selectDate(date: number): void {\n const daysDiff = date - 1;\n const selected = this.dateTimeAdapter.addCalendarDays(this.firstDateOfMonth, daysDiff);\n\n this.selectedChange.emit(selected);\n this.userSelection.emit();\n }\n\n /**\n * Handle keydown event on calendar body\n */\n public handleCalendarKeydown(event: KeyboardEvent): void {\n let moment;\n switch (event.keyCode) {\n // minus 1 day\n case LEFT_ARROW:\n moment = this.dateTimeAdapter.addCalendarDays(this.pickerMoment, -1);\n this.pickerMomentChange.emit(moment);\n break;\n\n // add 1 day\n case RIGHT_ARROW:\n moment = this.dateTimeAdapter.addCalendarDays(this.pickerMoment, 1);\n this.pickerMomentChange.emit(moment);\n break;\n\n // minus 1 week\n case UP_ARROW:\n moment = this.dateTimeAdapter.addCalendarDays(this.pickerMoment, -7);\n this.pickerMomentChange.emit(moment);\n break;\n\n // add 1 week\n case DOWN_ARROW:\n moment = this.dateTimeAdapter.addCalendarDays(this.pickerMoment, 7);\n this.pickerMomentChange.emit(moment);\n break;\n\n // move to first day of current month\n case HOME:\n moment = this.dateTimeAdapter.addCalendarDays(\n this.pickerMoment,\n 1 - this.dateTimeAdapter.getDate(this.pickerMoment)\n );\n this.pickerMomentChange.emit(moment);\n break;\n\n // move to last day of current month\n case END:\n moment = this.dateTimeAdapter.addCalendarDays(\n this.pickerMoment,\n this.dateTimeAdapter.getNumDaysInMonth(this.pickerMoment) - this.dateTimeAdapter.getDate(this.pickerMoment)\n );\n this.pickerMomentChange.emit(moment);\n break;\n\n // minus 1 month (or 1 year)\n case PAGE_UP:\n moment =\n event.altKey ?\n this.dateTimeAdapter.addCalendarYears(this.pickerMoment, -1)\n : this.dateTimeAdapter.addCalendarMonths(this.pickerMoment, -1);\n this.pickerMomentChange.emit(moment);\n break;\n\n // add 1 month (or 1 year)\n case PAGE_DOWN:\n moment =\n event.altKey ?\n this.dateTimeAdapter.addCalendarYears(this.pickerMoment, 1)\n : this.dateTimeAdapter.addCalendarMonths(this.pickerMoment, 1);\n this.pickerMomentChange.emit(moment);\n break;\n\n // select the pickerMoment\n case ENTER:\n if (!this.dateFilter || this.dateFilter(this.pickerMoment)) {\n this.selectDate(this.dateTimeAdapter.getDate(this.pickerMoment));\n }\n break;\n default:\n return;\n }\n\n this.focusActiveCell();\n event.preventDefault();\n }\n\n /**\n * Generate the calendar weekdays array\n */\n private generateWeekDays(): void {\n const longWeekdays = this.dateTimeAdapter.getDayOfWeekNames('long');\n const shortWeekdays = this.dateTimeAdapter.getDayOfWeekNames('short');\n const narrowWeekdays = this.dateTimeAdapter.getDayOfWeekNames('narrow');\n const firstDayOfWeek = this.firstDayOfWeek;\n\n const weekdays = longWeekdays.map((long, i) => {\n return { long, short: shortWeekdays[i], narrow: narrowWeekdays[i] };\n });\n\n this._weekdays = weekdays.slice(firstDayOfWeek).concat(weekdays.slice(0, firstDayOfWeek));\n\n this.dateNames = this.dateTimeAdapter.getDateNames();\n\n return;\n }\n\n /**\n * Generate the calendar days array\n */\n private generateCalendar(): void {\n if (!this.pickerMoment) {\n return;\n }\n\n this.todayDate = null;\n\n // the first weekday of the month\n const startWeekdayOfMonth = this.dateTimeAdapter.getDay(this.firstDateOfMonth);\n const firstDayOfWeek = this.firstDayOfWeek;\n\n // the amount of days from the first date of the month\n // if it is < 0, it means the date is in previous month\n let daysDiff = 0 - ((startWeekdayOfMonth + (DAYS_PER_WEEK - firstDayOfWeek)) % DAYS_PER_WEEK);\n\n // the index of cell that contains the first date of the month\n this.firstRowOffset = Math.abs(daysDiff);\n\n this._days = [];\n for (let i = 0; i < WEEKS_PER_VIEW; i++) {\n const week = [];\n for (let j = 0; j < DAYS_PER_WEEK; j++) {\n const date = this.dateTimeAdapter.addCalendarDays(this.firstDateOfMonth, daysDiff);\n const dateCell = this.createDateCell(date, daysDiff);\n\n // check if the date is today\n if (this.dateTimeAdapter.isSameDay(this.dateTimeAdapter.now(), date)) {\n this.todayDate = daysDiff + 1;\n }\n\n week.push(dateCell);\n daysDiff += 1;\n }\n this._days.push(week);\n }\n\n this.setSelectedDates();\n }\n\n private updateFirstDayOfWeek(locale: string): void {\n if (this.isDefaultFirstDayOfWeek) {\n try {\n this._firstDayOfWeek = getLocaleFirstDayOfWeek(locale);\n } catch {\n this._firstDayOfWeek = 0;\n }\n }\n }\n\n /**\n * Creates CalendarCell for days.\n */\n private createDateCell(date: T, daysDiff: number): CalendarCell {\n // total days of the month\n const daysInMonth = this.dateTimeAdapter.getNumDaysInMonth(this.pickerMoment);\n const dateNum = this.dateTimeAdapter.getDate(date);\n // const dateName = this.dateNames[dateNum - 1];\n const dateName = dateNum.toString();\n const ariaLabel = this.dateTimeAdapter.format(date, this.dateTimeFormats.dateA11yLabel);\n\n // check if the date if selectable\n const enabled = this.isDateEnabled(date);\n\n // check if date is not in current month\n const dayValue = daysDiff + 1;\n const out = dayValue < 1 || dayValue > daysInMonth;\n const cellClass = `owl-dt-day-${this.dateTimeAdapter.getDay(date)}`;\n\n return new CalendarCell(dayValue, dateName, ariaLabel, enabled, out, cellClass);\n }\n\n /**\n * Check if the date is valid\n */\n private isDateEnabled(date: T): boolean {\n return (\n !!date &&\n (!this.dateFilter || this.dateFilter(date)) &&\n (!this.minDate || this.dateTimeAdapter.compare(date, this.minDate) >= 0) &&\n (!this.maxDate || this.dateTimeAdapter.compare(date, this.maxDate) <= 0)\n );\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 /**\n * Check if the give dates are none-null and in the same month\n */\n public isSameMonth(dateLeft: T, dateRight: T): boolean {\n return !!(\n dateLeft &&\n dateRight &&\n this.dateTimeAdapter.isValid(dateLeft) &&\n this.dateTimeAdapter.isValid(dateRight) &&\n this.dateTimeAdapter.getYear(dateLeft) === this.dateTimeAdapter.getYear(dateRight) &&\n this.dateTimeAdapter.getMonth(dateLeft) === this.dateTimeAdapter.getMonth(dateRight)\n );\n }\n\n /**\n * Set the selectedDates value.\n * In single mode, it has only one value which represent the selected date\n * In range mode, it would has two values, one for the fromValue and the other for the toValue\n */\n private setSelectedDates(): void {\n this.selectedDates = [];\n\n if (!this.firstDateOfMonth) {\n return;\n }\n\n if (this.isInSingleMode && this.selected) {\n const dayDiff = this.dateTimeAdapter.differenceInCalendarDays(this.selected, this.firstDateOfMonth);\n this.selectedDates[0] = dayDiff + 1;\n return;\n }\n\n if (this.isInRangeMode && this.selecteds) {\n this.selectedDates = this.selecteds.map((selected) => {\n if (this.dateTimeAdapter.isValid(selected)) {\n const dayDiff = this.dateTimeAdapter.differenceInCalendarDays(selected, this.firstDateOfMonth);\n return dayDiff + 1;\n } else {\n return null;\n }\n });\n }\n }\n\n private focusActiveCell(): void {\n this.calendarBodyElm.focusActiveCell();\n }\n}\n","<table\n [class.owl-dt-calendar-only-current-month]=\"hideOtherMonths\"\n class=\"owl-dt-calendar-table owl-dt-calendar-month-table\">\n <thead class=\"owl-dt-calendar-header\">\n <tr class=\"owl-dt-weekdays\">\n @for (weekday of weekdays; track weekday.short) {\n <th\n [attr.aria-label]=\"weekday.long\"\n class=\"owl-dt-weekday\"\n scope=\"col\">\n <span>{{ weekday.short }}</span>\n </th>\n }\n </tr>\n <tr>\n <th\n aria-hidden=\"true\"\n class=\"owl-dt-calendar-table-divider\"\n colspan=\"7\"></th>\n </tr>\n </thead>\n <tbody\n [activeCell]=\"activeCell\"\n [rows]=\"days\"\n [selectMode]=\"selectMode\"\n [selectedValues]=\"selectedDates\"\n [todayValue]=\"todayDate\"\n (keydown)=\"handleCalendarKeydown($event)\"\n (selectCell)=\"selectCalendarCell($event)\"\n owl-date-time-calendar-body\n role=\"grid\"></tbody>\n</table>\n","import { Injectable } from '@angular/core';\nimport { Subject } from 'rxjs';\n\n@Injectable({ providedIn: 'root' })\nexport class OwlDateTimeIntl {\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 public readonly changes: Subject<void> = new Subject<void>();\n\n /** A label for