UNPKG

ngx-material-timepicker

Version:
891 lines (872 loc) 148 kB
import * as i0 from '@angular/core'; import { Injectable, InjectionToken, Directive, Input, HostListener, Component, Pipe, Inject, Optional, EventEmitter, ViewChild, Output, ChangeDetectionStrategy, ContentChild, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { DOCUMENT, CommonModule } from '@angular/common'; import { BehaviorSubject, Subject, merge } from 'rxjs'; import { shareReplay, tap, debounceTime, distinctUntilChanged, filter, takeUntil, map } from 'rxjs/operators'; import { trigger, transition, style, animate, sequence } from '@angular/animations'; import { DateTime, Info } from 'luxon'; import * as i4 from '@angular/forms'; import { FormControl, NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms'; var TimeUnit; (function (TimeUnit) { TimeUnit[TimeUnit["HOUR"] = 0] = "HOUR"; TimeUnit[TimeUnit["MINUTE"] = 1] = "MINUTE"; })(TimeUnit || (TimeUnit = {})); var TimePeriod; (function (TimePeriod) { TimePeriod["AM"] = "AM"; TimePeriod["PM"] = "PM"; })(TimePeriod || (TimePeriod = {})); var TimeFormat; (function (TimeFormat) { TimeFormat["TWELVE"] = "hh:mm a"; TimeFormat["TWELVE_SHORT"] = "h:m a"; TimeFormat["TWENTY_FOUR"] = "HH:mm"; TimeFormat["TWENTY_FOUR_SHORT"] = "H:m"; })(TimeFormat || (TimeFormat = {})); function isSameOrAfter(time, compareWith, unit = 'minutes') { if (unit === 'hours') { return time.hour >= compareWith.hour; } if (unit === 'minutes') { return time.hasSame(compareWith, unit) || time.valueOf() > compareWith.valueOf(); } } function isSameOrBefore(time, compareWith, unit = 'minutes') { if (unit === 'hours') { return time.hour <= compareWith.hour; } if (unit === 'minutes') { return time.hasSame(compareWith, unit) || time.valueOf() <= compareWith.valueOf(); } } function isBetween(time, before, after, unit = 'minutes') { if (unit === 'hours') { return isSameOrBefore(time, after, unit) && isSameOrAfter(time, before, unit); } if (unit === 'minutes') { return isSameOrBefore(time, after) && isSameOrAfter(time, before); } } function isDigit(e) { // Allow: backspace, delete, tab, escape, enter if ([46, 8, 9, 27, 13].some(n => n === e.keyCode) || // Allow: Ctrl/cmd+A (e.keyCode == 65 && (e.ctrlKey === true || e.metaKey === true)) || // Allow: Ctrl/cmd+C (e.keyCode == 67 && (e.ctrlKey === true || e.metaKey === true)) || // Allow: Ctrl/cmd+X (e.keyCode == 88 && (e.ctrlKey === true || e.metaKey === true)) || // Allow: home, end, left, right, up, down (e.keyCode >= 35 && e.keyCode <= 40)) { return true; } return !((e.keyCode < 48 || e.keyCode > 57) && (e.keyCode < 96 || e.keyCode > 105)); } // @dynamic class TimeAdapter { static parseTime(time, opts) { const { numberingSystem, locale } = TimeAdapter.getLocaleOptionsByTime(time, opts); const isPeriodExist = time.split(' ').length === 2; const timeMask = isPeriodExist ? TimeFormat.TWELVE_SHORT : TimeFormat.TWENTY_FOUR_SHORT; return DateTime.fromFormat(time, timeMask, { numberingSystem, locale }); } static formatTime(time, opts) { if (!time) { return 'Invalid Time'; } const { format } = opts; const parsedTime = TimeAdapter.parseTime(time, opts).setLocale(TimeAdapter.DEFAULT_LOCALE); if (!parsedTime.isValid) { return null; } if (format !== 24) { return parsedTime.toLocaleString(Object.assign(Object.assign({}, DateTime.TIME_SIMPLE), { hour12: format !== 24, numberingSystem: TimeAdapter.DEFAULT_NUMBERING_SYSTEM })).replace(/\u200E/g, '').replace(/\u202F/g, ' '); } return parsedTime.toISOTime({ includeOffset: false, suppressMilliseconds: true, suppressSeconds: true }).replace(/\u200E/g, '').replace(/\u202F/g, ' '); } static toLocaleTimeString(time, opts = {}) { const { format = TimeAdapter.DEFAULT_FORMAT, locale = TimeAdapter.DEFAULT_LOCALE } = opts; const hourCycle = format === 24 ? 'h23' : 'h12'; const timeFormat = Object.assign(Object.assign({}, DateTime.TIME_SIMPLE), { hourCycle }); const timeMask = (format === 24) ? TimeFormat.TWENTY_FOUR_SHORT : TimeFormat.TWELVE_SHORT; const localOpts = Object.assign({ locale: opts.locale, numberingSystem: opts.numberingSystem }, timeFormat); return DateTime.fromFormat(time, timeMask).setLocale(locale).toLocaleString(localOpts).replace(/\u202F/g, ' '); } static isTimeAvailable(time, min, max, granularity, minutesGap, format) { if (!time) { return; } const convertedTime = this.parseTime(time, { format }); const minutes = convertedTime.minute; if (minutesGap && minutes === minutes && minutes % minutesGap !== 0) { throw new Error(`Your minutes - ${minutes} doesn\'t match your minutesGap - ${minutesGap}`); } const isAfter = (min && !max) && isSameOrAfter(convertedTime, min, granularity); const isBefore = (max && !min) && isSameOrBefore(convertedTime, max, granularity); const between = (min && max) && isBetween(convertedTime, min, max, granularity); const isAvailable = !min && !max; return isAfter || isBefore || between || isAvailable; } /*** * Format hour according to time format (12 or 24) */ static formatHour(currentHour, format, period) { if (format === 24) { return currentHour; } const hour = period === TimePeriod.AM ? currentHour : currentHour + 12; if (period === TimePeriod.AM && hour === 12) { return 0; } else if (period === TimePeriod.PM && hour === 24) { return 12; } return hour; } static fromDateTimeToString(time, format) { const timeFormat = format === 24 ? TimeFormat.TWENTY_FOUR : TimeFormat.TWELVE; return time.reconfigure({ numberingSystem: TimeAdapter.DEFAULT_NUMBERING_SYSTEM, locale: TimeAdapter.DEFAULT_LOCALE }).toFormat(timeFormat).replace(/\u202F/g, ' '); } static getLocaleOptionsByTime(time, opts) { const localeConfig = { numberingSystem: opts.numberingSystem, locale: opts.locale }; const defaultConfig = { numberingSystem: TimeAdapter.DEFAULT_NUMBERING_SYSTEM, locale: TimeAdapter.DEFAULT_LOCALE }; return isNaN(parseInt(time, 10)) ? localeConfig : defaultConfig; } } TimeAdapter.DEFAULT_FORMAT = 12; TimeAdapter.DEFAULT_LOCALE = 'en-US'; TimeAdapter.DEFAULT_NUMBERING_SYSTEM = 'latn'; const DEFAULT_HOUR = { time: 12, angle: 360 }; const DEFAULT_MINUTE = { time: 0, angle: 360 }; class NgxMaterialTimepickerService { constructor() { this.hourSubject = new BehaviorSubject(DEFAULT_HOUR); this.minuteSubject = new BehaviorSubject(DEFAULT_MINUTE); this.periodSubject = new BehaviorSubject(TimePeriod.AM); } set hour(hour) { this.hourSubject.next(hour); } get selectedHour() { return this.hourSubject.asObservable(); } set minute(minute) { this.minuteSubject.next(minute); } get selectedMinute() { return this.minuteSubject.asObservable(); } set period(period) { const isPeriodValid = (period === TimePeriod.AM) || (period === TimePeriod.PM); if (isPeriodValid) { this.periodSubject.next(period); } } get selectedPeriod() { return this.periodSubject.asObservable(); } setDefaultTimeIfAvailable(time, min, max, format, minutesGap) { /* Workaround to double error message*/ try { if (TimeAdapter.isTimeAvailable(time, min, max, 'minutes', minutesGap)) { this.setDefaultTime(time, format); } } catch (e) { console.error(e); } } getFullTime(format) { const selectedHour = this.hourSubject.getValue().time; const selectedMinute = this.minuteSubject.getValue().time; const hour = selectedHour != null ? selectedHour : DEFAULT_HOUR.time; const minute = selectedMinute != null ? selectedMinute : DEFAULT_MINUTE.time; const period = format === 12 ? this.periodSubject.getValue() : ''; const time = `${hour}:${minute} ${period}`.trim(); return TimeAdapter.formatTime(time, { format }); } setDefaultTime(time, format) { const defaultTime = TimeAdapter.parseTime(time, { format }).toJSDate(); if (DateTime.fromJSDate(defaultTime).isValid) { const period = time.substr(time.length - 2).toUpperCase(); const hour = defaultTime.getHours(); this.hour = Object.assign(Object.assign({}, DEFAULT_HOUR), { time: formatHourByPeriod(hour, period) }); this.minute = Object.assign(Object.assign({}, DEFAULT_MINUTE), { time: defaultTime.getMinutes() }); this.period = period; } else { this.resetTime(); } } resetTime() { this.hour = Object.assign({}, DEFAULT_HOUR); this.minute = Object.assign({}, DEFAULT_MINUTE); this.period = TimePeriod.AM; } } NgxMaterialTimepickerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); NgxMaterialTimepickerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /*** * Format hour in 24hours format to meridian (AM or PM) format */ function formatHourByPeriod(hour, period) { switch (period) { case TimePeriod.AM: return hour === 0 ? 12 : hour; case TimePeriod.PM: return hour === 12 ? 12 : hour - 12; default: return hour; } } const TIME_LOCALE = new InjectionToken('TimeLocale', { providedIn: 'root', factory: () => TimeAdapter.DEFAULT_LOCALE }); const NUMBERING_SYSTEM = new InjectionToken('NumberingSystem', { providedIn: 'root', factory: () => TimeAdapter.DEFAULT_NUMBERING_SYSTEM }); class NgxMaterialTimepickerEventService { constructor() { this.backdropClickSubject = new Subject(); this.keydownEventSubject = new Subject(); } get backdropClick() { return this.backdropClickSubject.asObservable().pipe(shareReplay({ bufferSize: 1, refCount: true })); } get keydownEvent() { return this.keydownEventSubject.asObservable().pipe(shareReplay({ bufferSize: 1, refCount: true })); } dispatchEvent(event) { switch (event.type) { case 'click': this.backdropClickSubject.next(event); break; case 'keydown': this.keydownEventSubject.next(event); break; default: throw new Error('no such event type'); } } } NgxMaterialTimepickerEventService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); NgxMaterialTimepickerEventService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerEventService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerEventService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); class AppendToInputDirective { constructor(elementRef, renderer) { this.renderer = renderer; this.element = elementRef.nativeElement; } get inputCords() { return this.inputElement.getBoundingClientRect(); } get direction() { const height = this.element.offsetHeight; const { bottom, top } = this._inputCords; const isElementFit = (window && window.innerHeight) - bottom < height; const isTop = isElementFit && top > height; const isCenter = isElementFit && top < height; if (isTop) { return 'top'; } else if (isCenter) { return 'center'; } return 'bottom'; } ngAfterViewInit() { this._inputCords = this.inputCords; this._direction = this.direction; this.append(); } changePosition() { const { bottom, top } = this.inputCords; const y = this.defineElementYByDirection(top, bottom); this.setStyle('top', `${y}px`); } append() { const { left, bottom, top } = this._inputCords; const y = this.defineElementYByDirection(top, bottom); this.setStyle('position', 'fixed'); this.setStyle('left', `${left}px`); this.setStyle('top', `${y}px`); } setStyle(style, value) { this.renderer.setStyle(this.element, style, value); } defineElementYByDirection(inputTop, inputBottom) { if (this._direction === 'top') { return inputTop - this.element.offsetHeight; } else if (this._direction === 'center') { return inputTop - (this.element.offsetHeight / 2); } return inputBottom; } } AppendToInputDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AppendToInputDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); AppendToInputDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.17", type: AppendToInputDirective, selector: "[ngxAppendToInput]", inputs: { inputElement: ["ngxAppendToInput", "inputElement"] }, host: { listeners: { "window:scroll": "changePosition()" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AppendToInputDirective, decorators: [{ type: Directive, args: [{ selector: '[ngxAppendToInput]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { inputElement: [{ type: Input, args: ['ngxAppendToInput'] }], changePosition: [{ type: HostListener, args: ['window:scroll'] }] } }); class NgxMaterialTimepickerContentComponent { } NgxMaterialTimepickerContentComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); NgxMaterialTimepickerContentComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.17", type: NgxMaterialTimepickerContentComponent, selector: "ngx-material-timepicker-content", inputs: { appendToInput: "appendToInput", inputElement: "inputElement" }, ngImport: i0, template: "<div [ngxAppendToInput]=\"inputElement\" *ngIf=\"appendToInput;else timepickerModal\">\n <!--suppress HtmlUnknownAttribute -->\n <ng-container *ngTemplateOutlet=\"timepickerOutlet\"></ng-container>\n</div>\n\n<ng-template #timepickerModal>\n <!--suppress HtmlUnknownAttribute -->\n <ng-container *ngTemplateOutlet=\"timepickerOutlet\"></ng-container>\n</ng-template>\n\n<ng-template #timepickerOutlet>\n <ng-content></ng-content>\n</ng-template>\n", directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: AppendToInputDirective, selector: "[ngxAppendToInput]", inputs: ["ngxAppendToInput"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerContentComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-material-timepicker-content', templateUrl: './ngx-material-timepicker-content.component.html', }] }], propDecorators: { appendToInput: [{ type: Input }], inputElement: [{ type: Input }] } }); // @dynamic class TimepickerTimeUtils { static getHours(format) { return Array(format).fill(1).map((v, i) => { const angleStep = 30; const time = v + i; const angle = angleStep * time; return { time: time === 24 ? 0 : time, angle }; }); } static disableHours(hours, config) { if (config.min || config.max) { return hours.map(value => { const hour = config.format === 24 ? value.time : TimeAdapter.formatHour(value.time, config.format, config.period); const currentTime = DateTime.fromObject({ hour }).toFormat(TimeFormat.TWELVE); return Object.assign(Object.assign({}, value), { disabled: !TimeAdapter.isTimeAvailable(currentTime, config.min, config.max, 'hours') }); }); } return hours; } static getMinutes(gap = 1) { const minutesCount = 60; const angleStep = 360 / minutesCount; const minutes = []; for (let i = 0; i < minutesCount; i++) { const angle = angleStep * i; if (i % gap === 0) { minutes.push({ time: i, angle: angle !== 0 ? angle : 360 }); } } return minutes; } static disableMinutes(minutes, selectedHour, config) { if (config.min || config.max) { const hour = TimeAdapter.formatHour(selectedHour, config.format, config.period); return minutes.map(value => { const currentTime = DateTime.fromObject({ hour, minute: value.time }).toFormat(TimeFormat.TWELVE); return Object.assign(Object.assign({}, value), { disabled: !TimeAdapter.isTimeAvailable(currentTime, config.min, config.max, 'minutes') }); }); } return minutes; } } class TimeLocalizerPipe { constructor(locale) { this.locale = locale; } transform(time, timeUnit, isKeyboardEnabled = false) { if (time == null || time === '') { return ''; } switch (timeUnit) { case TimeUnit.HOUR: { const format = (time === 0 || isKeyboardEnabled) ? 'HH' : 'H'; return this.formatTime('hour', time, format); } case TimeUnit.MINUTE: return this.formatTime('minute', time, 'mm'); default: throw new Error(`There is no Time Unit with type ${timeUnit}`); } } formatTime(timeMeasure, time, format) { try { return DateTime.fromObject({ [timeMeasure]: +time }).setLocale(this.locale).toFormat(format); } catch (_a) { throw new Error(`Cannot format provided time - ${time} to locale - ${this.locale}`); } } } TimeLocalizerPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: TimeLocalizerPipe, deps: [{ token: TIME_LOCALE }], target: i0.ɵɵFactoryTarget.Pipe }); TimeLocalizerPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: TimeLocalizerPipe, name: "timeLocalizer" }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: TimeLocalizerPipe, decorators: [{ type: Pipe, args: [{ name: 'timeLocalizer' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [TIME_LOCALE] }] }]; } }); class TimeParserPipe { constructor(locale, numberingSystem) { this.locale = locale; this.numberingSystem = numberingSystem; } transform(time, timeUnit = TimeUnit.HOUR) { if (time == null || time === '') { return ''; } if (!isNaN(+time)) { return time; } if (timeUnit === TimeUnit.MINUTE) { return this.parseTime(time, 'm', 'minute'); } return this.parseTime(time, 'H', 'hour'); } parseTime(time, format, timeMeasure) { const parsedTime = DateTime.fromFormat(String(time), format, { numberingSystem: this.numberingSystem, locale: this.locale })[timeMeasure]; if (!isNaN(parsedTime)) { return parsedTime; } throw new Error(`Cannot parse time - ${time}`); } } TimeParserPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: TimeParserPipe, deps: [{ token: TIME_LOCALE }, { token: NUMBERING_SYSTEM }], target: i0.ɵɵFactoryTarget.Pipe }); TimeParserPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: TimeParserPipe, name: "timeParser" }); TimeParserPipe.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: TimeParserPipe }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: TimeParserPipe, decorators: [{ type: Pipe, args: [{ name: 'timeParser' }] }, { type: Injectable }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [TIME_LOCALE] }] }, { type: undefined, decorators: [{ type: Inject, args: [NUMBERING_SYSTEM] }] }]; } }); class AutofocusDirective { constructor(element, document) { this.element = element; this.document = document; this.activeElement = this.document.activeElement; } ngOnChanges() { if (this.isFocusActive) { // To avoid ExpressionChangedAfterItHasBeenCheckedError; setTimeout(() => this.element.nativeElement.focus({ preventScroll: true })); } } ngOnDestroy() { // To avoid ExpressionChangedAfterItHasBeenCheckedError; setTimeout(() => this.activeElement.focus({ preventScroll: true })); } } AutofocusDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AutofocusDirective, deps: [{ token: i0.ElementRef }, { token: DOCUMENT, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); AutofocusDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.17", type: AutofocusDirective, selector: "[timepickerAutofocus]", inputs: { isFocusActive: ["timepickerAutofocus", "isFocusActive"] }, usesOnChanges: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AutofocusDirective, decorators: [{ type: Directive, args: [{ selector: '[timepickerAutofocus]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { isFocusActive: [{ type: Input, args: ['timepickerAutofocus'] }] } }); /* tslint:disable:triple-equals */ class NgxMaterialTimepickerDialControlComponent { constructor(timeParserPipe, timeLocalizerPipe) { this.timeParserPipe = timeParserPipe; this.timeLocalizerPipe = timeLocalizerPipe; this.timeUnitChanged = new EventEmitter(); this.timeChanged = new EventEmitter(); this.focused = new EventEmitter(); this.unfocused = new EventEmitter(); } get selectedTime() { if (!!this.time) { return this.timeList.find(t => t.time === +this.time); } } ngOnInit() { if (this.isEditable) { this.timeControl = new FormControl({ value: this.formatTimeForUI(this.time), disabled: this.disabled }); this.timeControl.valueChanges.pipe(tap((value) => { if (value.length > 2) { this.updateInputValue(value.slice(-1)); } }), debounceTime(500), distinctUntilChanged(), filter((value) => !isTimeDisabledToChange(this.time, value, this.timeList)), tap((value) => this.time = this.timeParserPipe.transform(value, this.timeUnit).toString())).subscribe(() => this.updateTime()); } } saveTimeAndChangeTimeUnit(event, unit) { event.preventDefault(); this.previousTime = this.time; this.timeUnitChanged.next(unit); this.focused.next(); } updateTime() { const time = this.selectedTime; if (time) { this.timeChanged.next(time); this.previousTime = time.time; if (this.isEditable) { this.updateInputValue(this.formatTimeForUI(time.time)); } } } onKeydown(e) { if (!isDigit(e)) { e.preventDefault(); } else { this.changeTimeByArrow(e.keyCode); } } changeTimeByArrow(keyCode) { const ARROW_UP = 38; const ARROW_DOWN = 40; let time; if (keyCode === ARROW_UP) { time = String(+this.time + (this.minutesGap || 1)); } else if (keyCode === ARROW_DOWN) { time = String(+this.time - (this.minutesGap || 1)); } if (!isTimeUnavailable(time, this.timeList)) { this.time = time; this.updateTime(); } } formatTimeForUI(value) { const parsedTime = this.timeParserPipe.transform(value, this.timeUnit).toString(); return this.timeLocalizerPipe.transform(parsedTime, this.timeUnit, true); } updateInputValue(value) { this.editableTimeTmpl.nativeElement.value = value; } } NgxMaterialTimepickerDialControlComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerDialControlComponent, deps: [{ token: TimeParserPipe }, { token: TimeLocalizerPipe }], target: i0.ɵɵFactoryTarget.Component }); NgxMaterialTimepickerDialControlComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.17", type: NgxMaterialTimepickerDialControlComponent, selector: "ngx-material-timepicker-dial-control", inputs: { timeList: "timeList", timeUnit: "timeUnit", time: "time", isActive: "isActive", isEditable: "isEditable", minutesGap: "minutesGap", disabled: "disabled" }, outputs: { timeUnitChanged: "timeUnitChanged", timeChanged: "timeChanged", focused: "focused", unfocused: "unfocused" }, providers: [TimeParserPipe, TimeLocalizerPipe], viewQueries: [{ propertyName: "editableTimeTmpl", first: true, predicate: ["editableTimeTmpl"], descendants: true }], ngImport: i0, template: "<!--suppress HtmlFormInputWithoutLabel, HtmlUnknownAttribute -->\n<input class=\"timepicker-dial__control timepicker-dial__item\"\n [ngClass]=\"{'timepicker-dial__item_active': isActive}\"\n [ngModel]=\"time | timeLocalizer: timeUnit\"\n (ngModelChange)=\"time = $event\"\n [disabled]=\"disabled\"\n (input)=\"updateTime()\" (focus)=\"saveTimeAndChangeTimeUnit($event, timeUnit)\"\n readonly [timepickerAutofocus]=\"isActive\"\n *ngIf=\"!isEditable;else editableTemplate\">\n\n<ng-template #editableTemplate>\n <!--suppress HtmlFormInputWithoutLabel, HtmlUnknownAttribute -->\n <input class=\"timepicker-dial__control timepicker-dial__item timepicker-dial__control_editable\"\n #editableTimeTmpl\n [formControl]=\"timeControl\"\n [ngClass]=\"{'timepicker-dial__item_active': isActive}\"\n [timepickerAutofocus]=\"isActive\"\n (focus)=\"saveTimeAndChangeTimeUnit($event, timeUnit)\"\n (keydown)=\"onKeydown($event)\">\n</ng-template>\n", styles: [".timepicker-dial__item{cursor:pointer;color:#ffffff80;font-family:\"Roboto\",sans-serif}@supports (font-family: var(--primary-font-family)){.timepicker-dial__item{font-family:var(--primary-font-family);color:var(--dial-inactive-color)}}.timepicker-dial__item_active{color:#fff}@supports (color: var(--dial-active-color)){.timepicker-dial__item_active{color:var(--dial-active-color)}}.timepicker-dial__control{border:none;background-color:transparent;font-size:50px;width:60px;padding:0;border-radius:3px;text-align:right}.timepicker-dial__control_editable:focus{color:#00bfff;background-color:#fff;outline:deepskyblue}@supports (color: var(--dial-editable-active-color)){.timepicker-dial__control_editable:focus{color:var(--dial-editable-active-color)}}@supports (background-color: var(--dial-editable-background-color)){.timepicker-dial__control_editable:focus{background-color:var(--dial-editable-background-color)}}@supports (outline: var(--dial-editable-active-color)){.timepicker-dial__control_editable:focus{outline:var(--dial-editable-active-color)}}.timepicker-dial__control:disabled{cursor:default}.timepicker-dial__control:focus-visible{outline:none}\n"], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: AutofocusDirective, selector: "[timepickerAutofocus]", inputs: ["timepickerAutofocus"] }, { type: i4.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }], pipes: { "timeLocalizer": TimeLocalizerPipe } }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerDialControlComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-material-timepicker-dial-control', templateUrl: 'ngx-material-timepicker-dial-control.component.html', styleUrls: ['ngx-material-timepicker-dial-control.component.scss'], providers: [TimeParserPipe, TimeLocalizerPipe], }] }], ctorParameters: function () { return [{ type: TimeParserPipe }, { type: TimeLocalizerPipe }]; }, propDecorators: { timeList: [{ type: Input }], timeUnit: [{ type: Input }], time: [{ type: Input }], isActive: [{ type: Input }], isEditable: [{ type: Input }], minutesGap: [{ type: Input }], disabled: [{ type: Input }], editableTimeTmpl: [{ type: ViewChild, args: ['editableTimeTmpl'] }], timeUnitChanged: [{ type: Output }], timeChanged: [{ type: Output }], focused: [{ type: Output }], unfocused: [{ type: Output }] } }); function isTimeDisabledToChange(currentTime, nextTime, timeList) { const isNumber = /\d/.test(nextTime); if (isNumber) { return isTimeUnavailable(nextTime, timeList); } } function isTimeUnavailable(time, timeList) { const selectedTime = timeList.find(value => value.time === +time); return !selectedTime || (selectedTime && selectedTime.disabled); } class NgxMaterialTimepickerPeriodComponent { constructor() { this.timePeriod = TimePeriod; this.isPeriodAvailable = true; this.periodChanged = new EventEmitter(); } changePeriod(period) { this.isPeriodAvailable = this.isSwitchPeriodAvailable(period); if (this.isPeriodAvailable) { this.periodChanged.next(period); } } animationDone() { this.isPeriodAvailable = true; } isSwitchPeriodAvailable(period) { const time = this.getDisabledTimeByPeriod(period); return !time.every(t => t.disabled); } getDisabledTimeByPeriod(period) { switch (this.activeTimeUnit) { case TimeUnit.HOUR: return TimepickerTimeUtils.disableHours(this.hours, { min: this.minTime, max: this.maxTime, format: this.format, period }); case TimeUnit.MINUTE: return TimepickerTimeUtils.disableMinutes(this.minutes, +this.selectedHour, { min: this.minTime, max: this.maxTime, format: this.format, period }); default: throw new Error('no such TimeUnit'); } } } NgxMaterialTimepickerPeriodComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerPeriodComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); NgxMaterialTimepickerPeriodComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.17", type: NgxMaterialTimepickerPeriodComponent, selector: "ngx-material-timepicker-period", inputs: { selectedPeriod: "selectedPeriod", format: "format", activeTimeUnit: "activeTimeUnit", hours: "hours", minutes: "minutes", minTime: "minTime", maxTime: "maxTime", selectedHour: "selectedHour", meridiems: "meridiems" }, outputs: { periodChanged: "periodChanged" }, ngImport: i0, template: "<div class=\"timepicker-period\">\n\t\t\t<button class=\"timepicker-dial__item timepicker-period__btn\"\n [ngClass]=\"{'timepicker-dial__item_active': selectedPeriod === timePeriod.AM}\"\n (click)=\"changePeriod(timePeriod.AM)\"\n type=\"button\">{{meridiems[0]}}</button>\n <button class=\"timepicker-dial__item timepicker-period__btn\"\n [ngClass]=\"{'timepicker-dial__item_active': selectedPeriod === timePeriod.PM}\"\n (click)=\"changePeriod(timePeriod.PM)\"\n type=\"button\">{{meridiems[1]}}</button>\n <div class=\"timepicker-period__warning\" [@scaleInOut] (@scaleInOut.done)=\"animationDone()\" *ngIf=\"!isPeriodAvailable\">\n <p>Current time would be invalid in this period.</p>\n </div>\n</div>\n", styles: [".timepicker-dial__item{cursor:pointer;color:#ffffff80;font-family:\"Roboto\",sans-serif}@supports (font-family: var(--primary-font-family)){.timepicker-dial__item{font-family:var(--primary-font-family);color:var(--dial-inactive-color)}}.timepicker-dial__item_active{color:#fff}@supports (color: var(--dial-active-color)){.timepicker-dial__item_active{color:var(--dial-active-color)}}.timepicker-period{display:flex;flex-direction:column;position:relative}.timepicker-period__btn{padding:1px 3px;border:0;background-color:transparent;font-size:18px;font-weight:500;-webkit-user-select:none;-moz-user-select:none;user-select:none;outline:none;border-radius:3px;transition:background-color .5s;font-family:\"Roboto\",sans-serif}@supports (font-family: var(--primary-font-family)){.timepicker-period__btn{font-family:var(--primary-font-family)}}.timepicker-period__btn:focus{background-color:#00000012}.timepicker-period__warning{padding:5px 10px;border-radius:3px;background-color:#0000008c;color:#fff;position:absolute;width:200px;left:-20px;top:40px}.timepicker-period__warning>p{margin:0;font-size:12px;font-family:\"Roboto\",sans-serif}@supports (font-family: var(--primary-font-family)){.timepicker-period__warning>p{font-family:var(--primary-font-family)}}\n"], directives: [{ type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [ trigger('scaleInOut', [ transition(':enter', [ style({ transform: 'scale(0)' }), animate('.2s', style({ transform: 'scale(1)' })), sequence([ animate('3s', style({ opacity: 1 })), animate('.3s', style({ opacity: 0 })) ]) ]) ]) ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerPeriodComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-material-timepicker-period', templateUrl: 'ngx-material-timepicker-period.component.html', styleUrls: ['ngx-material-timepicker-period.component.scss'], animations: [ trigger('scaleInOut', [ transition(':enter', [ style({ transform: 'scale(0)' }), animate('.2s', style({ transform: 'scale(1)' })), sequence([ animate('3s', style({ opacity: 1 })), animate('.3s', style({ opacity: 0 })) ]) ]) ]) ] }] }], propDecorators: { selectedPeriod: [{ type: Input }], format: [{ type: Input }], activeTimeUnit: [{ type: Input }], hours: [{ type: Input }], minutes: [{ type: Input }], minTime: [{ type: Input }], maxTime: [{ type: Input }], selectedHour: [{ type: Input }], meridiems: [{ type: Input }], periodChanged: [{ type: Output }] } }); class NgxMaterialTimepickerDialComponent { constructor(locale) { this.locale = locale; this.timeUnit = TimeUnit; this.meridiems = Info.meridiems({ locale: this.locale }); this.periodChanged = new EventEmitter(); this.timeUnitChanged = new EventEmitter(); this.hourChanged = new EventEmitter(); this.minuteChanged = new EventEmitter(); } ngOnChanges(changes) { if (changes['period'] && changes['period'].currentValue || changes['format'] && changes['format'].currentValue) { const hours = TimepickerTimeUtils.getHours(this.format); this.hours = TimepickerTimeUtils.disableHours(hours, { min: this.minTime, max: this.maxTime, format: this.format, period: this.period, }); } if (changes['period'] && changes['period'].currentValue || changes['hour'] && changes['hour'].currentValue) { const minutes = TimepickerTimeUtils.getMinutes(this.minutesGap); this.minutes = TimepickerTimeUtils.disableMinutes(minutes, +this.hour, { min: this.minTime, max: this.maxTime, format: this.format, period: this.period, }); } } changeTimeUnit(unit) { this.timeUnitChanged.next(unit); } changePeriod(period) { this.periodChanged.next(period); } changeHour(hour) { this.hourChanged.next(hour); if (this.isEditable) { this.changeTimeUnit(TimeUnit.MINUTE); } } changeMinute(minute) { this.minuteChanged.next(minute); } showHint() { this.isHintVisible = true; } hideHint() { this.isHintVisible = false; } } NgxMaterialTimepickerDialComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerDialComponent, deps: [{ token: TIME_LOCALE }], target: i0.ɵɵFactoryTarget.Component }); NgxMaterialTimepickerDialComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.17", type: NgxMaterialTimepickerDialComponent, selector: "ngx-material-timepicker-dial", inputs: { editableHintTmpl: "editableHintTmpl", hour: "hour", minute: "minute", format: "format", period: "period", activeTimeUnit: "activeTimeUnit", minTime: "minTime", maxTime: "maxTime", isEditable: "isEditable", minutesGap: "minutesGap", hoursOnly: "hoursOnly" }, outputs: { periodChanged: "periodChanged", timeUnitChanged: "timeUnitChanged", hourChanged: "hourChanged", minuteChanged: "minuteChanged" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"timepicker-dial\">\n <div class=\"timepicker-dial__container\">\n <div class=\"timepicker-dial__time\">\n <ngx-material-timepicker-dial-control [timeList]=\"hours\" [time]=\"hour\" [timeUnit]=\"timeUnit.HOUR\"\n [isActive]=\"activeTimeUnit === timeUnit.HOUR\"\n [isEditable]=\"isEditable\"\n (timeUnitChanged)=\"changeTimeUnit($event)\"\n (timeChanged)=\"changeHour($event)\"\n (focused)=\"showHint()\"\n (unfocused)=\"hideHint()\">\n\n </ngx-material-timepicker-dial-control>\n <span>:</span>\n <ngx-material-timepicker-dial-control [timeList]=\"minutes\" [time]=\"minute\" [timeUnit]=\"timeUnit.MINUTE\"\n [isActive]=\"activeTimeUnit === timeUnit.MINUTE\"\n [isEditable]=\"isEditable\"\n [minutesGap]=\"minutesGap\"\n [disabled]=\"hoursOnly\"\n (timeUnitChanged)=\"changeTimeUnit($event)\"\n (timeChanged)=\"changeMinute($event)\"\n (focused)=\"showHint()\"\n (unfocused)=\"hideHint()\">\n\n </ngx-material-timepicker-dial-control>\n </div>\n <ngx-material-timepicker-period class=\"timepicker-dial__period\"\n [ngClass]=\"{'timepicker-dial__period--hidden': format === 24}\"\n [selectedPeriod]=\"period\" [activeTimeUnit]=\"activeTimeUnit\"\n [maxTime]=\"maxTime\" [minTime]=\"minTime\" [format]=\"format\"\n [hours]=\"hours\" [minutes]=\"minutes\" [selectedHour]=\"hour\"\n [meridiems]=\"meridiems\"\n (periodChanged)=\"changePeriod($event)\"></ngx-material-timepicker-period>\n </div>\n <div *ngIf=\"isEditable || editableHintTmpl\" [ngClass]=\"{'timepicker-dial__hint-container--hidden': !isHintVisible}\">\n <!--suppress HtmlUnknownAttribute -->\n <ng-container *ngTemplateOutlet=\"editableHintTmpl ? editableHintTmpl : editableHintDefault\"></ng-container>\n <ng-template #editableHintDefault>\n <small class=\"timepicker-dial__hint\"> * use arrows (<span>&#8645;</span>) to change the time</small>\n </ng-template>\n </div>\n</div>\n", styles: [".timepicker-dial{text-align:right}.timepicker-dial__container{display:flex;align-items:center;justify-content:flex-end;-webkit-tap-highlight-color:rgba(0,0,0,0)}.timepicker-dial__time{display:flex;align-items:baseline;line-height:normal;font-size:50px;color:#ffffff80;font-family:\"Roboto\",sans-serif}@supports (font-family: var(--primary-font-family)){.timepicker-dial__time{font-family:var(--primary-font-family);color:var(--dial-inactive-color)}}.timepicker-dial__period{display:block;margin-left:10px}.timepicker-dial__period--hidden{visibility:hidden}.timepicker-dial__hint-container--hidden{visibility:hidden}.timepicker-dial__hint{display:inline-block;font-size:10px;color:#fff}@supports (color: var(--dial-active-color)){.timepicker-dial__hint{color:var(--dial-active-color)}}.timepicker-dial__hint span{font-size:14px}@media (max-device-width: 1023px) and (orientation: landscape){.timepicker-dial__container{flex-direction:column}.timepicker-dial__period{margin-left:0}}\n"], components: [{ type: NgxMaterialTimepickerDialControlComponent, selector: "ngx-material-timepicker-dial-control", inputs: ["timeList", "timeUnit", "time", "isActive", "isEditable", "minutesGap", "disabled"], outputs: ["timeUnitChanged", "timeChanged", "focused", "unfocused"] }, { type: NgxMaterialTimepickerPeriodComponent, selector: "ngx-material-timepicker-period", inputs: ["selectedPeriod", "format", "activeTimeUnit", "hours", "minutes", "minTime", "maxTime", "selectedHour", "meridiems"], outputs: ["periodChanged"] }], directives: [{ type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerDialComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-material-timepicker-dial', templateUrl: 'ngx-material-timepicker-dial.component.html', styleUrls: ['ngx-material-timepicker-dial.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [TIME_LOCALE] }] }]; }, propDecorators: { editableHintTmpl: [{ type: Input }], hour: [{ type: Input }], minute: [{ type: Input }], format: [{ type: Input }], period: [{ type: Input }], activeTimeUnit: [{ type: Input }], minTime: [{ type: Input }], maxTime: [{ type: Input }], isEditable: [{ type: Input }], minutesGap: [{ type: Input }], hoursOnly: [{ type: Input }], periodChanged: [{ type: Output }], timeUnitChanged: [{ type: Output }], hourChanged: [{ type: Output }], minuteChanged: [{ type: Output }] } }); class NgxMaterialTimepickerHoursFace { constructor(format) { this.hourChange = new EventEmitter(); this.hourSelected = new EventEmitter(); this.hoursList = []; this.hoursList = TimepickerTimeUtils.getHours(format); } onTimeSelected(time) { this.hourSelected.next(time); } } NgxMaterialTimepickerHoursFace.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerHoursFace, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); NgxMaterialTimepickerHoursFace.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.17", type: NgxMaterialTimepickerHoursFace, inputs: { selectedHour: "selectedHour", minTime: "minTime", maxTime: "maxTime", format: "format" }, outputs: { hourChange: "hourChange", hourSelected: "hourSelected" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: NgxMaterialTimepickerHoursFace, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: undefined }]; }, propDecorators: { selectedHour: [{ type: Input }], minTime: [{ type: Input }], maxTime: [{ type: Input }], format: [{ type: Input }], hourChange: [{ type: Output }], hourSelected: [{ type: Output }] } }); class ActiveHourPipe { transform(hour, currentHour, isClockFaceDisabled) { if (hour == null || isClockFaceDisabled) { return false; } return hour === currentHour; } } ActiveHourPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.1