@danielmoncada/angular-datetime-picker
Version:
Angular Date Time Picker
1,229 lines (1,221 loc) • 231 kB
JavaScript
import { ɵɵdefineInjectable, Injectable, InjectionToken, inject, LOCALE_ID, Directive, Optional, Inject, Input, EventEmitter, Component, ChangeDetectionStrategy, ElementRef, NgZone, ChangeDetectorRef, Output, ViewChild, TemplateRef, Injector, SkipSelf, ViewContainerRef, forwardRef, Renderer2, Pipe, NgModule } from '@angular/core';
import { DOCUMENT, Location, getLocaleFirstDayOfWeek, CommonModule } from '@angular/common';
import { FocusTrapFactory, A11yModule } from '@angular/cdk/a11y';
import { NoopScrollStrategy, Overlay, OverlayConfig, OverlayContainer, OverlayModule } from '@angular/cdk/overlay';
import { BasePortalOutlet, CdkPortalOutlet, ComponentPortal, PortalInjector, PortalModule } from '@angular/cdk/portal';
import { SPACE, LEFT_ARROW, UP_ARROW, RIGHT_ARROW, DOWN_ARROW, ESCAPE, ENTER, PAGE_DOWN, PAGE_UP, END, HOME } from '@angular/cdk/keycodes';
import { coerceBooleanProperty, coerceNumberProperty, coerceArray } from '@angular/cdk/coercion';
import { Subject, Subscription, defer, merge, of } from 'rxjs';
import { take, filter, startWith, debounceTime } from 'rxjs/operators';
import { trigger, state, style, transition, group, query, animateChild, animate, keyframes } from '@angular/animations';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, Validators } from '@angular/forms';
import { Platform, PlatformModule } from '@angular/cdk/platform';
import * as _moment from 'moment';
import _moment__default from 'moment';
/**
* date-time-picker-intl.service
*/
class OwlDateTimeIntl {
constructor() {
/**
* Stream that emits whenever the labels here are changed. Use this to notify
* components if the labels have changed after initialization.
*/
this.changes = new Subject();
/** A label for the up second button (used by screen readers). */
this.upSecondLabel = 'Add a second';
/** A label for the down second button (used by screen readers). */
this.downSecondLabel = 'Minus a second';
/** A label for the up minute button (used by screen readers). */
this.upMinuteLabel = 'Add a minute';
/** A label for the down minute button (used by screen readers). */
this.downMinuteLabel = 'Minus a minute';
/** A label for the up hour button (used by screen readers). */
this.upHourLabel = 'Add a hour';
/** A label for the down hour button (used by screen readers). */
this.downHourLabel = 'Minus a hour';
/** A label for the previous month button (used by screen readers). */
this.prevMonthLabel = 'Previous month';
/** A label for the next month button (used by screen readers). */
this.nextMonthLabel = 'Next month';
/** A label for the previous year button (used by screen readers). */
this.prevYearLabel = 'Previous year';
/** A label for the next year button (used by screen readers). */
this.nextYearLabel = 'Next year';
/** A label for the previous multi-year button (used by screen readers). */
this.prevMultiYearLabel = 'Previous 21 years';
/** A label for the next multi-year button (used by screen readers). */
this.nextMultiYearLabel = 'Next 21 years';
/** A label for the 'switch to month view' button (used by screen readers). */
this.switchToMonthViewLabel = 'Change to month view';
/** A label for the 'switch to year view' button (used by screen readers). */
this.switchToMultiYearViewLabel = 'Choose month and year';
/** A label for the cancel button */
this.cancelBtnLabel = 'Cancel';
/** A label for the set button */
this.setBtnLabel = 'Set';
/** A label for the range 'from' in picker info */
this.rangeFromLabel = 'From';
/** A label for the range 'to' in picker info */
this.rangeToLabel = 'To';
/** A label for the hour12 button (AM) */
this.hour12AMLabel = 'AM';
/** A label for the hour12 button (PM) */
this.hour12PMLabel = 'PM';
}
}
OwlDateTimeIntl.ɵprov = ɵɵdefineInjectable({ factory: function OwlDateTimeIntl_Factory() { return new OwlDateTimeIntl(); }, token: OwlDateTimeIntl, providedIn: "root" });
OwlDateTimeIntl.decorators = [
{ type: Injectable, args: [{ providedIn: 'root' },] }
];
/**
* date-time-adapter.class
*/
/** InjectionToken for date time picker that can be used to override default locale code. */
const OWL_DATE_TIME_LOCALE = new InjectionToken('OWL_DATE_TIME_LOCALE', {
providedIn: 'root',
factory: OWL_DATE_TIME_LOCALE_FACTORY
});
/** @docs-private */
function OWL_DATE_TIME_LOCALE_FACTORY() {
return inject(LOCALE_ID);
}
/** Provider for OWL_DATE_TIME_LOCALE injection token. */
const OWL_DATE_TIME_LOCALE_PROVIDER = {
provide: OWL_DATE_TIME_LOCALE,
useExisting: LOCALE_ID
};
class DateTimeAdapter {
constructor() {
/** A stream that emits when the locale changes. */
this._localeChanges = new Subject();
/** total milliseconds in a day. */
this.millisecondsInDay = 86400000;
/** total milliseconds in a minute. */
this.milliseondsInMinute = 60000;
}
get localeChanges() {
return this._localeChanges;
}
/**
* Compare two given dates
* 1 if the first date is after the second,
* -1 if the first date is before the second
* 0 if dates are equal.
* */
compare(first, second) {
if (!this.isValid(first) || !this.isValid(second)) {
throw Error('JSNativeDate: Cannot compare invalid dates.');
}
const dateFirst = this.clone(first);
const dateSecond = this.clone(second);
const diff = this.getTime(dateFirst) - this.getTime(dateSecond);
if (diff < 0) {
return -1;
}
else if (diff > 0) {
return 1;
}
else {
// Return 0 if diff is 0; return NaN if diff is NaN
return diff;
}
}
/**
* Check if two given dates are in the same year
* 1 if the first date's year is after the second,
* -1 if the first date's year is before the second
* 0 if two given dates are in the same year
* */
compareYear(first, second) {
if (!this.isValid(first) || !this.isValid(second)) {
throw Error('JSNativeDate: Cannot compare invalid dates.');
}
const yearLeft = this.getYear(first);
const yearRight = this.getYear(second);
const diff = yearLeft - yearRight;
if (diff < 0) {
return -1;
}
else if (diff > 0) {
return 1;
}
else {
return 0;
}
}
/**
* Attempts to deserialize a value to a valid date object. This is different from parsing in that
* deserialize should only accept non-ambiguous, locale-independent formats (e.g. a ISO 8601
* string). The default implementation does not allow any deserialization, it simply checks that
* the given value is already a valid date object or null. The `<mat-datepicker>` will call this
* method on all of it's `@Input()` properties that accept dates. It is therefore possible to
* support passing values from your backend directly to these properties by overriding this method
* to also deserialize the format used by your backend.
*/
deserialize(value) {
if (value == null ||
(this.isDateInstance(value) && this.isValid(value))) {
return value;
}
return this.invalid();
}
/**
* Sets the locale used for all dates.
*/
setLocale(locale) {
this.locale = locale;
this._localeChanges.next(locale);
}
/**
* Get the locale used for all dates.
* */
getLocale() {
return this.locale;
}
/**
* Clamp the given date between min and max dates.
*/
clampDate(date, min, max) {
if (min && this.compare(date, min) < 0) {
return min;
}
if (max && this.compare(date, max) > 0) {
return max;
}
return date;
}
}
/**
* date-time-format.class
*/
/** InjectionToken for date time picker that can be used to override default format. */
const OWL_DATE_TIME_FORMATS = new InjectionToken('OWL_DATE_TIME_FORMATS');
/**
* date-time.class
*/
let nextUniqueId = 0;
var DateView;
(function (DateView) {
DateView["MONTH"] = "month";
DateView["YEAR"] = "year";
DateView["MULTI_YEARS"] = "multi-years";
})(DateView || (DateView = {}));
class OwlDateTime {
constructor(dateTimeAdapter, dateTimeFormats) {
this.dateTimeAdapter = dateTimeAdapter;
this.dateTimeFormats = dateTimeFormats;
/**
* Whether to show the second's timer
*/
this._showSecondsTimer = false;
/**
* Whether the timer is in hour12 format
*/
this._hour12Timer = false;
/**
* The view that the calendar should start in.
*/
this.startView = DateView.MONTH;
/**
* Whether to should only the year and multi-year views.
*/
this.yearOnly = false;
/**
* Whether to should only the multi-year view.
*/
this.multiyearOnly = false;
/**
* Hours to change per step
*/
this._stepHour = 1;
/**
* Minutes to change per step
*/
this._stepMinute = 1;
/**
* Seconds to change per step
*/
this._stepSecond = 1;
/**
* Whether to hide dates in other months at the start or end of the current month.
*/
this._hideOtherMonths = false;
/**
* Date Time Checker to check if the give dateTime is selectable
*/
this.dateTimeChecker = (dateTime) => {
return (!!dateTime &&
(!this.dateTimeFilter || this.dateTimeFilter(dateTime)) &&
(!this.minDateTime ||
this.dateTimeAdapter.compare(dateTime, this.minDateTime) >=
0) &&
(!this.maxDateTime ||
this.dateTimeAdapter.compare(dateTime, this.maxDateTime) <= 0));
};
if (!this.dateTimeAdapter) {
throw Error(`OwlDateTimePicker: No provider found for DateTimeAdapter. You must import one of the following ` +
`modules at your application root: OwlNativeDateTimeModule, OwlMomentDateTimeModule, or provide a ` +
`custom implementation.`);
}
if (!this.dateTimeFormats) {
throw Error(`OwlDateTimePicker: No provider found for OWL_DATE_TIME_FORMATS. You must import one of the following ` +
`modules at your application root: OwlNativeDateTimeModule, OwlMomentDateTimeModule, or provide a ` +
`custom implementation.`);
}
this._id = `owl-dt-picker-${nextUniqueId++}`;
}
get showSecondsTimer() {
return this._showSecondsTimer;
}
set showSecondsTimer(val) {
this._showSecondsTimer = coerceBooleanProperty(val);
}
get hour12Timer() {
return this._hour12Timer;
}
set hour12Timer(val) {
this._hour12Timer = coerceBooleanProperty(val);
}
get stepHour() {
return this._stepHour;
}
set stepHour(val) {
this._stepHour = coerceNumberProperty(val, 1);
}
get stepMinute() {
return this._stepMinute;
}
set stepMinute(val) {
this._stepMinute = coerceNumberProperty(val, 1);
}
get stepSecond() {
return this._stepSecond;
}
set stepSecond(val) {
this._stepSecond = coerceNumberProperty(val, 1);
}
get firstDayOfWeek() {
return this._firstDayOfWeek;
}
set firstDayOfWeek(value) {
value = coerceNumberProperty(value);
if (value > 6 || value < 0) {
this._firstDayOfWeek = undefined;
}
else {
this._firstDayOfWeek = value;
}
}
get hideOtherMonths() {
return this._hideOtherMonths;
}
set hideOtherMonths(val) {
this._hideOtherMonths = coerceBooleanProperty(val);
}
get id() {
return this._id;
}
get formatString() {
return this.pickerType === 'both'
? this.dateTimeFormats.fullPickerInput
: this.pickerType === 'calendar'
? this.dateTimeFormats.datePickerInput
: this.dateTimeFormats.timePickerInput;
}
get disabled() {
return false;
}
getValidDate(obj) {
return this.dateTimeAdapter.isDateInstance(obj) &&
this.dateTimeAdapter.isValid(obj)
? obj
: null;
}
}
OwlDateTime.decorators = [
{ type: Directive }
];
OwlDateTime.ctorParameters = () => [
{ type: DateTimeAdapter, decorators: [{ type: Optional }] },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [OWL_DATE_TIME_FORMATS,] }] }
];
OwlDateTime.propDecorators = {
showSecondsTimer: [{ type: Input }],
hour12Timer: [{ type: Input }],
startView: [{ type: Input }],
yearOnly: [{ type: Input }],
multiyearOnly: [{ type: Input }],
stepHour: [{ type: Input }],
stepMinute: [{ type: Input }],
stepSecond: [{ type: Input }],
firstDayOfWeek: [{ type: Input }],
hideOtherMonths: [{ type: Input }]
};
/**
* calendar.component
*/
class OwlCalendarComponent {
constructor(elmRef, pickerIntl, ngZone, cdRef, dateTimeAdapter, dateTimeFormats) {
this.elmRef = elmRef;
this.pickerIntl = pickerIntl;
this.ngZone = ngZone;
this.cdRef = cdRef;
this.dateTimeAdapter = dateTimeAdapter;
this.dateTimeFormats = dateTimeFormats;
this.DateView = DateView;
this._selecteds = [];
/**
* The view that the calendar should start in.
*/
this.startView = DateView.MONTH;
/**
* Whether to should only the year and multi-year views.
*/
this.yearOnly = false;
/**
* Whether to should only the multi-year view.
*/
this.multiyearOnly = false;
/** Emits when the currently picker moment changes. */
this.pickerMomentChange = new EventEmitter();
/** Emits when the currently selected date changes. */
this.selectedChange = new EventEmitter();
/** Emits when any date is selected. */
this.userSelection = new EventEmitter();
/**
* Emits the selected year. This doesn't imply a change on the selected date
* */
this.yearSelected = new EventEmitter();
/**
* Emits the selected month. This doesn't imply a change on the selected date
* */
this.monthSelected = new EventEmitter();
this.intlChangesSub = Subscription.EMPTY;
/**
* Used for scheduling that focus should be moved to the active cell on the next tick.
* We need to schedule it, rather than do it immediately, because we have to wait
* for Angular to re-evaluate the view children.
*/
this.moveFocusOnNextTick = false;
/**
* Date filter for the month and year view
*/
this.dateFilterForViews = (date) => {
return (!!date &&
(!this.dateFilter || this.dateFilter(date)) &&
(!this.minDate ||
this.dateTimeAdapter.compare(date, this.minDate) >= 0) &&
(!this.maxDate ||
this.dateTimeAdapter.compare(date, this.maxDate) <= 0));
};
this.intlChangesSub = this.pickerIntl.changes.subscribe(() => {
this.cdRef.markForCheck();
});
}
get minDate() {
return this._minDate;
}
set minDate(value) {
value = this.dateTimeAdapter.deserialize(value);
value = this.getValidDate(value);
this._minDate = value
? this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(value), this.dateTimeAdapter.getMonth(value), this.dateTimeAdapter.getDate(value))
: null;
}
get maxDate() {
return this._maxDate;
}
set maxDate(value) {
value = this.dateTimeAdapter.deserialize(value);
value = this.getValidDate(value);
this._maxDate = value
? this.dateTimeAdapter.createDate(this.dateTimeAdapter.getYear(value), this.dateTimeAdapter.getMonth(value), this.dateTimeAdapter.getDate(value))
: null;
}
get pickerMoment() {
return this._pickerMoment;
}
set pickerMoment(value) {
value = this.dateTimeAdapter.deserialize(value);
this._pickerMoment =
this.getValidDate(value) || this.dateTimeAdapter.now();
}
get selected() {
return this._selected;
}
set selected(value) {
value = this.dateTimeAdapter.deserialize(value);
this._selected = this.getValidDate(value);
}
get selecteds() {
return this._selecteds;
}
set selecteds(values) {
this._selecteds = values.map(v => {
v = this.dateTimeAdapter.deserialize(v);
return this.getValidDate(v);
});
}
get periodButtonText() {
return this.isMonthView
? this.dateTimeAdapter.format(this.pickerMoment, this.dateTimeFormats.monthYearLabel)
: this.dateTimeAdapter.getYearName(this.pickerMoment);
}
get periodButtonLabel() {
return this.isMonthView
? this.pickerIntl.switchToMultiYearViewLabel
: this.pickerIntl.switchToMonthViewLabel;
}
get prevButtonLabel() {
if (this._currentView === DateView.MONTH) {
return this.pickerIntl.prevMonthLabel;
}
else if (this._currentView === DateView.YEAR) {
return this.pickerIntl.prevYearLabel;
}
else {
return null;
}
}
get nextButtonLabel() {
if (this._currentView === DateView.MONTH) {
return this.pickerIntl.nextMonthLabel;
}
else if (this._currentView === DateView.YEAR) {
return this.pickerIntl.nextYearLabel;
}
else {
return null;
}
}
get currentView() {
return this._currentView;
}
set currentView(view) {
this._currentView = view;
this.moveFocusOnNextTick = true;
}
get isInSingleMode() {
return this.selectMode === 'single';
}
get isInRangeMode() {
return (this.selectMode === 'range' ||
this.selectMode === 'rangeFrom' ||
this.selectMode === 'rangeTo');
}
get showControlArrows() {
return this._currentView !== DateView.MULTI_YEARS;
}
get isMonthView() {
return this._currentView === DateView.MONTH;
}
/**
* Bind class 'owl-dt-calendar' to host
* */
get owlDTCalendarClass() {
return true;
}
ngOnInit() {
}
ngAfterContentInit() {
this._currentView = this.startView;
}
ngAfterViewChecked() {
if (this.moveFocusOnNextTick) {
this.moveFocusOnNextTick = false;
this.focusActiveCell();
}
}
ngOnDestroy() {
this.intlChangesSub.unsubscribe();
}
/**
* Toggle between month view and year view
*/
toggleViews() {
let nextView = null;
if (this._currentView === DateView.MONTH) {
nextView = DateView.MULTI_YEARS;
}
else {
if (this.multiyearOnly) {
nextView = DateView.MULTI_YEARS;
}
else if (this.yearOnly) {
nextView = this._currentView === DateView.YEAR ? DateView.MULTI_YEARS : DateView.YEAR;
}
else {
nextView = DateView.MONTH;
}
}
this.currentView = nextView;
}
/**
* Handles user clicks on the previous button.
* */
previousClicked() {
this.pickerMoment = this.isMonthView
? this.dateTimeAdapter.addCalendarMonths(this.pickerMoment, -1)
: this.dateTimeAdapter.addCalendarYears(this.pickerMoment, -1);
this.pickerMomentChange.emit(this.pickerMoment);
}
/**
* Handles user clicks on the next button.
* */
nextClicked() {
this.pickerMoment = this.isMonthView
? this.dateTimeAdapter.addCalendarMonths(this.pickerMoment, 1)
: this.dateTimeAdapter.addCalendarYears(this.pickerMoment, 1);
this.pickerMomentChange.emit(this.pickerMoment);
}
dateSelected(date) {
if (!this.dateFilterForViews(date)) {
return;
}
this.selectedChange.emit(date);
/*if ((this.isInSingleMode && !this.dateTimeAdapter.isSameDay(date, this.selected)) ||
this.isInRangeMode) {
this.selectedChange.emit(date);
}*/
}
/**
* Change the pickerMoment value and switch to a specific view
*/
goToDateInView(date, view) {
this.handlePickerMomentChange(date);
if ((!this.yearOnly && !this.multiyearOnly) ||
(this.multiyearOnly && (view !== DateView.MONTH && view !== DateView.YEAR)) ||
(this.yearOnly && view !== DateView.MONTH)) {
this.currentView = view;
}
return;
}
/**
* Change the pickerMoment value
*/
handlePickerMomentChange(date) {
this.pickerMoment = this.dateTimeAdapter.clampDate(date, this.minDate, this.maxDate);
this.pickerMomentChange.emit(this.pickerMoment);
return;
}
userSelected() {
this.userSelection.emit();
}
/**
* Whether the previous period button is enabled.
*/
prevButtonEnabled() {
return (!this.minDate || !this.isSameView(this.pickerMoment, this.minDate));
}
/**
* Whether the next period button is enabled.
*/
nextButtonEnabled() {
return (!this.maxDate || !this.isSameView(this.pickerMoment, this.maxDate));
}
/**
* Focus to the host element
* */
focusActiveCell() {
this.ngZone.runOutsideAngular(() => {
this.ngZone.onStable
.asObservable()
.pipe(take(1))
.subscribe(() => {
this.elmRef.nativeElement
.querySelector('.owl-dt-calendar-cell-active')
.focus();
});
});
}
selectYearInMultiYearView(normalizedYear) {
this.yearSelected.emit(normalizedYear);
}
selectMonthInYearView(normalizedMonth) {
this.monthSelected.emit(normalizedMonth);
}
/**
* Whether the two dates represent the same view in the current view mode (month or year).
*/
isSameView(date1, date2) {
if (this._currentView === DateView.MONTH) {
return !!(date1 &&
date2 &&
this.dateTimeAdapter.getYear(date1) ===
this.dateTimeAdapter.getYear(date2) &&
this.dateTimeAdapter.getMonth(date1) ===
this.dateTimeAdapter.getMonth(date2));
}
else if (this._currentView === DateView.YEAR) {
return !!(date1 &&
date2 &&
this.dateTimeAdapter.getYear(date1) ===
this.dateTimeAdapter.getYear(date2));
}
else {
return false;
}
}
/**
* Get a valid date object
*/
getValidDate(obj) {
return this.dateTimeAdapter.isDateInstance(obj) &&
this.dateTimeAdapter.isValid(obj)
? obj
: null;
}
}
OwlCalendarComponent.decorators = [
{ type: Component, args: [{
selector: 'owl-date-time-calendar',
exportAs: 'owlDateTimeCalendar',
template: "<div class=\"owl-dt-calendar-control\">\n <!-- focus when keyboard tab (http://kizu.ru/en/blog/keyboard-only-focus/#x) -->\n <button class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\n type=\"button\" tabindex=\"0\"\n [style.visibility]=\"showControlArrows? 'visible': 'hidden'\"\n [disabled]=\"!prevButtonEnabled()\"\n [attr.aria-label]=\"prevButtonLabel\"\n (click)=\"previousClicked()\">\n <span class=\"owl-dt-control-content 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 <div class=\"owl-dt-calendar-control-content\">\n <button class=\"owl-dt-control owl-dt-control-button owl-dt-control-period-button\"\n type=\"button\" tabindex=\"0\"\n [attr.aria-label]=\"periodButtonLabel\"\n (click)=\"toggleViews()\">\n <span class=\"owl-dt-control-content owl-dt-control-button-content\" tabindex=\"-1\">\n {{periodButtonText}}\n\n <span class=\"owl-dt-control-button-arrow\"\n [style.transform]=\"'rotate(' + (isMonthView? 0 : 180) +'deg)'\">\n <!-- <editor-fold desc=\"SVG Arrow\"> -->\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 width=\"50%\" height=\"50%\" viewBox=\"0 0 292.362 292.362\" style=\"enable-background:new 0 0 292.362 292.362;\"\n xml:space=\"preserve\">\n <g>\n <path d=\"M286.935,69.377c-3.614-3.617-7.898-5.424-12.848-5.424H18.274c-4.952,0-9.233,1.807-12.85,5.424\n C1.807,72.998,0,77.279,0,82.228c0,4.948,1.807,9.229,5.424,12.847l127.907,127.907c3.621,3.617,7.902,5.428,12.85,5.428\n s9.233-1.811,12.847-5.428L286.935,95.074c3.613-3.617,5.427-7.898,5.427-12.847C292.362,77.279,290.548,72.998,286.935,69.377z\"/>\n </g>\n </svg>\n <!-- </editor-fold> -->\n </span>\n </span>\n </button>\n </div>\n <button class=\"owl-dt-control owl-dt-control-button owl-dt-control-arrow-button\"\n type=\"button\" tabindex=\"0\"\n [style.visibility]=\"showControlArrows? 'visible': 'hidden'\"\n [disabled]=\"!nextButtonEnabled()\"\n [attr.aria-label]=\"nextButtonLabel\"\n (click)=\"nextClicked()\">\n <span class=\"owl-dt-control-content owl-dt-control-button-content\" tabindex=\"-1\">\n <!-- <editor-fold desc=\"SVG Arrow Right\"> -->\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n viewBox=\"0 0 250.738 250.738\" style=\"enable-background:new 0 0 250.738 250.738;\" xml:space=\"preserve\">\n <path style=\"fill-rule:evenodd;clip-rule:evenodd;\" d=\"M191.75,111.689L84.766,5.291c-7.1-7.055-18.613-7.055-25.713,0\n c-7.101,7.054-7.101,18.49,0,25.544l95.053,94.534l-95.053,94.533c-7.101,7.054-7.101,18.491,0,25.545\n c7.1,7.054,18.613,7.054,25.713,0L191.75,139.05c3.784-3.759,5.487-8.759,5.238-13.681\n C197.237,120.447,195.534,115.448,191.75,111.689z\"/>\n </svg>\n <!-- </editor-fold> -->\n </span>\n </button>\n</div>\n<div class=\"owl-dt-calendar-main\" cdkMonitorSubtreeFocus [ngSwitch]=\"currentView\" tabindex=\"-1\">\n <owl-date-time-month-view\n *ngSwitchCase=\"DateView.MONTH\"\n [pickerMoment]=\"pickerMoment\"\n [firstDayOfWeek]=\"firstDayOfWeek\"\n [selected]=\"selected\"\n [selecteds]=\"selecteds\"\n [selectMode]=\"selectMode\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n [dateFilter]=\"dateFilter\"\n [hideOtherMonths]=\"hideOtherMonths\"\n (pickerMomentChange)=\"handlePickerMomentChange($event)\"\n (selectedChange)=\"dateSelected($event)\"\n (userSelection)=\"userSelected()\"></owl-date-time-month-view>\n\n <owl-date-time-year-view\n *ngSwitchCase=\"DateView.YEAR\"\n [pickerMoment]=\"pickerMoment\"\n [selected]=\"selected\"\n [selecteds]=\"selecteds\"\n [selectMode]=\"selectMode\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n [dateFilter]=\"dateFilter\"\n (keyboardEnter)=\"focusActiveCell()\"\n (pickerMomentChange)=\"handlePickerMomentChange($event)\"\n (monthSelected)=\"selectMonthInYearView($event)\"\n (change)=\"goToDateInView($event, DateView.MONTH)\"></owl-date-time-year-view>\n\n <owl-date-time-multi-year-view\n *ngSwitchCase=\"DateView.MULTI_YEARS\"\n [pickerMoment]=\"pickerMoment\"\n [selected]=\"selected\"\n [selecteds]=\"selecteds\"\n [selectMode]=\"selectMode\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n [dateFilter]=\"dateFilter\"\n (keyboardEnter)=\"focusActiveCell()\"\n (pickerMomentChange)=\"handlePickerMomentChange($event)\"\n (yearSelected)=\"selectYearInMultiYearView($event)\"\n (change)=\"goToDateInView($event, DateView.YEAR)\"></owl-date-time-multi-year-view>\n</div>\n",
host: {
'[class.owl-dt-calendar]': 'owlDTCalendarClass'
},
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
styles: [""]
},] }
];
OwlCalendarComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: OwlDateTimeIntl },
{ type: NgZone },
{ type: ChangeDetectorRef },
{ type: DateTimeAdapter, decorators: [{ type: Optional }] },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [OWL_DATE_TIME_FORMATS,] }] }
];
OwlCalendarComponent.propDecorators = {
minDate: [{ type: Input }],
maxDate: [{ type: Input }],
pickerMoment: [{ type: Input }],
selected: [{ type: Input }],
selecteds: [{ type: Input }],
dateFilter: [{ type: Input }],
firstDayOfWeek: [{ type: Input }],
selectMode: [{ type: Input }],
startView: [{ type: Input }],
yearOnly: [{ type: Input }],
multiyearOnly: [{ type: Input }],
hideOtherMonths: [{ type: Input }],
pickerMomentChange: [{ type: Output }],
selectedChange: [{ type: Output }],
userSelection: [{ type: Output }],
yearSelected: [{ type: Output }],
monthSelected: [{ type: Output }]
};
/**
* timer.component
*/
class OwlTimerComponent {
constructor(ngZone, elmRef, pickerIntl, cdRef, dateTimeAdapter) {
this.ngZone = ngZone;
this.elmRef = elmRef;
this.pickerIntl = pickerIntl;
this.cdRef = cdRef;
this.dateTimeAdapter = dateTimeAdapter;
this.isPM = false; // a flag indicates the current timer moment is in PM or AM
/**
* Hours to change per step
*/
this.stepHour = 1;
/**
* Minutes to change per step
*/
this.stepMinute = 1;
/**
* Seconds to change per step
*/
this.stepSecond = 1;
this.selectedChange = new EventEmitter();
}
get pickerMoment() {
return this._pickerMoment;
}
set pickerMoment(value) {
value = this.dateTimeAdapter.deserialize(value);
this._pickerMoment =
this.getValidDate(value) || this.dateTimeAdapter.now();
}
get minDateTime() {
return this._minDateTime;
}
set minDateTime(value) {
value = this.dateTimeAdapter.deserialize(value);
this._minDateTime = this.getValidDate(value);
}
get maxDateTime() {
return this._maxDateTime;
}
set maxDateTime(value) {
value = this.dateTimeAdapter.deserialize(value);
this._maxDateTime = this.getValidDate(value);
}
get hourValue() {
return this.dateTimeAdapter.getHours(this.pickerMoment);
}
/**
* The value would be displayed in hourBox.
* We need this because the value displayed in hourBox it not
* the same as the hourValue when the timer is in hour12Timer mode.
* */
get hourBoxValue() {
let hours = this.hourValue;
if (!this.hour12Timer) {
return hours;
}
else {
if (hours === 0) {
hours = 12;
this.isPM = false;
}
else if (hours > 0 && hours < 12) {
this.isPM = false;
}
else if (hours === 12) {
this.isPM = true;
}
else if (hours > 12 && hours < 24) {
hours = hours - 12;
this.isPM = true;
}
return hours;
}
}
get minuteValue() {
return this.dateTimeAdapter.getMinutes(this.pickerMoment);
}
get secondValue() {
return this.dateTimeAdapter.getSeconds(this.pickerMoment);
}
get upHourButtonLabel() {
return this.pickerIntl.upHourLabel;
}
get downHourButtonLabel() {
return this.pickerIntl.downHourLabel;
}
get upMinuteButtonLabel() {
return this.pickerIntl.upMinuteLabel;
}
get downMinuteButtonLabel() {
return this.pickerIntl.downMinuteLabel;
}
get upSecondButtonLabel() {
return this.pickerIntl.upSecondLabel;
}
get downSecondButtonLabel() {
return this.pickerIntl.downSecondLabel;
}
get hour12ButtonLabel() {
return this.isPM
? this.pickerIntl.hour12PMLabel
: this.pickerIntl.hour12AMLabel;
}
get owlDTTimerClass() {
return true;
}
get owlDTTimeTabIndex() {
return -1;
}
ngOnInit() { }
/**
* Focus to the host element
* */
focus() {
this.ngZone.runOutsideAngular(() => {
this.ngZone.onStable
.asObservable()
.pipe(take(1))
.subscribe(() => {
this.elmRef.nativeElement.focus();
});
});
}
/**
* Set the hour value via typing into timer box input
* We need this to handle the hour value when the timer is in hour12 mode
* */
setHourValueViaInput(hours) {
if (this.hour12Timer && this.isPM && hours >= 1 && hours <= 11) {
hours = hours + 12;
}
else if (this.hour12Timer && !this.isPM && hours === 12) {
hours = 0;
}
this.setHourValue(hours);
}
setHourValue(hours) {
const m = this.dateTimeAdapter.setHours(this.pickerMoment, hours);
this.selectedChange.emit(m);
this.cdRef.markForCheck();
}
setMinuteValue(minutes) {
const m = this.dateTimeAdapter.setMinutes(this.pickerMoment, minutes);
this.selectedChange.emit(m);
this.cdRef.markForCheck();
}
setSecondValue(seconds) {
const m = this.dateTimeAdapter.setSeconds(this.pickerMoment, seconds);
this.selectedChange.emit(m);
this.cdRef.markForCheck();
}
setMeridiem(event) {
this.isPM = !this.isPM;
let hours = this.hourValue;
if (this.isPM) {
hours = hours + 12;
}
else {
hours = hours - 12;
}
if (hours >= 0 && hours <= 23) {
this.setHourValue(hours);
}
this.cdRef.markForCheck();
event.preventDefault();
}
/**
* Check if the up hour button is enabled
*/
upHourEnabled() {
return (!this.maxDateTime ||
this.compareHours(this.stepHour, this.maxDateTime) < 1);
}
/**
* Check if the down hour button is enabled
*/
downHourEnabled() {
return (!this.minDateTime ||
this.compareHours(-this.stepHour, this.minDateTime) > -1);
}
/**
* Check if the up minute button is enabled
*/
upMinuteEnabled() {
return (!this.maxDateTime ||
this.compareMinutes(this.stepMinute, this.maxDateTime) < 1);
}
/**
* Check if the down minute button is enabled
*/
downMinuteEnabled() {
return (!this.minDateTime ||
this.compareMinutes(-this.stepMinute, this.minDateTime) > -1);
}
/**
* Check if the up second button is enabled
*/
upSecondEnabled() {
return (!this.maxDateTime ||
this.compareSeconds(this.stepSecond, this.maxDateTime) < 1);
}
/**
* Check if the down second button is enabled
*/
downSecondEnabled() {
return (!this.minDateTime ||
this.compareSeconds(-this.stepSecond, this.minDateTime) > -1);
}
/**
* PickerMoment's hour value +/- certain amount and compare it to the give date
* 1 is after the comparedDate
* -1 is before the comparedDate
* 0 is equal the comparedDate
* */
compareHours(amount, comparedDate) {
const hours = this.dateTimeAdapter.getHours(this.pickerMoment) + amount;
const result = this.dateTimeAdapter.setHours(this.pickerMoment, hours);
return this.dateTimeAdapter.compare(result, comparedDate);
}
/**
* PickerMoment's minute value +/- certain amount and compare it to the give date
* 1 is after the comparedDate
* -1 is before the comparedDate
* 0 is equal the comparedDate
* */
compareMinutes(amount, comparedDate) {
const minutes = this.dateTimeAdapter.getMinutes(this.pickerMoment) + amount;
const result = this.dateTimeAdapter.setMinutes(this.pickerMoment, minutes);
return this.dateTimeAdapter.compare(result, comparedDate);
}
/**
* PickerMoment's second value +/- certain amount and compare it to the give date
* 1 is after the comparedDate
* -1 is before the comparedDate
* 0 is equal the comparedDate
* */
compareSeconds(amount, comparedDate) {
const seconds = this.dateTimeAdapter.getSeconds(this.pickerMoment) + amount;
const result = this.dateTimeAdapter.setSeconds(this.pickerMoment, seconds);
return this.dateTimeAdapter.compare(result, comparedDate);
}
/**
* Get a valid date object
*/
getValidDate(obj) {
return this.dateTimeAdapter.isDateInstance(obj) &&
this.dateTimeAdapter.isValid(obj)
? obj
: null;
}
}
OwlTimerComponent.decorators = [
{ type: Component, args: [{
exportAs: 'owlDateTimeTimer',
selector: 'owl-date-time-timer',
template: "<owl-date-time-timer-box\n [upBtnAriaLabel]=\"upHourButtonLabel\"\n [downBtnAriaLabel]=\"downHourButtonLabel\"\n [upBtnDisabled]=\"!upHourEnabled()\"\n [downBtnDisabled]=\"!downHourEnabled()\"\n [boxValue]=\"hourBoxValue\"\n [value]=\"hourValue\" [min]=\"0\" [max]=\"23\"\n [step]=\"stepHour\" [inputLabel]=\"'Hour'\"\n (inputChange)=\"setHourValueViaInput($event)\"\n (valueChange)=\"setHourValue($event)\"></owl-date-time-timer-box>\n<owl-date-time-timer-box\n [showDivider]=\"true\"\n [upBtnAriaLabel]=\"upMinuteButtonLabel\"\n [downBtnAriaLabel]=\"downMinuteButtonLabel\"\n [upBtnDisabled]=\"!upMinuteEnabled()\"\n [downBtnDisabled]=\"!downMinuteEnabled()\"\n [value]=\"minuteValue\" [min]=\"0\" [max]=\"59\"\n [step]=\"stepMinute\" [inputLabel]=\"'Minute'\"\n (inputChange)=\"setMinuteValue($event)\"\n (valueChange)=\"setMinuteValue($event)\"></owl-date-time-timer-box>\n<owl-date-time-timer-box\n *ngIf=\"showSecondsTimer\"\n [showDivider]=\"true\"\n [upBtnAriaLabel]=\"upSecondButtonLabel\"\n [downBtnAriaLabel]=\"downSecondButtonLabel\"\n [upBtnDisabled]=\"!upSecondEnabled()\"\n [downBtnDisabled]=\"!downSecondEnabled()\"\n [value]=\"secondValue\" [min]=\"0\" [max]=\"59\"\n [step]=\"stepSecond\" [inputLabel]=\"'Second'\"\n (inputChange)=\"setSecondValue($event)\"\n (valueChange)=\"setSecondValue($event)\"></owl-date-time-timer-box>\n\n<div *ngIf=\"hour12Timer\" class=\"owl-dt-timer-hour12\">\n <button class=\"owl-dt-control-button owl-dt-timer-hour12-box\"\n type=\"button\" tabindex=\"0\"\n (click)=\"setMeridiem($event)\">\n <span class=\"owl-dt-control-button-content\" tabindex=\"-1\">\n {{hour12ButtonLabel}}\n </span>\n </button>\n</div>\n",
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
'[class.owl-dt-timer]': 'owlDTTimerClass',
'[attr.tabindex]': 'owlDTTimeTabIndex'
},
styles: [""]
},] }
];
OwlTimerComponent.ctorParameters = () => [
{ type: NgZone },
{ type: ElementRef },
{ type: OwlDateTimeIntl },
{ type: ChangeDetectorRef },
{ type: DateTimeAdapter, decorators: [{ type: Optional }] }
];
OwlTimerComponent.propDecorators = {
pickerMoment: [{ type: Input }],
minDateTime: [{ type: Input }],
maxDateTime: [{ type: Input }],
showSecondsTimer: [{ type: Input }],
hour12Timer: [{ type: Input }],
stepHour: [{ type: Input }],
stepMinute: [{ type: Input }],
stepSecond: [{ type: Input }],
selectedChange: [{ type: Output }]
};
/**
* date-time-picker.animations
*/
const owlDateTimePickerAnimations = {
transformPicker: trigger('transformPicker', [
state('void', style({ opacity: 0, transform: 'scale(1, 0)' })),
state('enter', style({ opacity: 1, transform: 'scale(1, 1)' })),
transition('void => enter', group([
query('@fadeInPicker', animateChild(), { optional: true }),
animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')
])),
transition('enter => void', animate('100ms linear', style({ opacity: 0 })))
]),
fadeInPicker: trigger('fadeInPicker', [
state('enter', style({ opacity: 1 })),
state('void', style({ opacity: 0 })),
transition('void => enter', animate('400ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)')),
])
};
/**
* date-time-picker-container.component
*/
class OwlDateTimeContainerComponent {
constructor(cdRef, elmRef, pickerIntl, dateTimeAdapter) {
this.cdRef = cdRef;
this.elmRef = elmRef;
this.pickerIntl = pickerIntl;
this.dateTimeAdapter = dateTimeAdapter;
this.activeSelectedIndex = 0; // The current active SelectedIndex in range select mode (0: 'from', 1: 'to')
/**
* Stream emits when try to hide picker
* */
this.hidePicker$ = new Subject();
/**
* Stream emits when try to confirm the selected value
* */
this.confirmSelected$ = new Subject();
this.pickerOpened$ = new Subject();
}
get hidePickerStream() {
return this.hidePicker$.asObservable();
}
get confirmSelectedStream() {
return this.confirmSelected$.asObservable();
}
get pickerOpenedStream() {
return this.pickerOpened$.asObservable();
}
get pickerMoment() {
return this._clamPickerMoment;
}
set pickerMoment(value) {
if (value) {
this._clamPickerMoment = this.dateTimeAdapter.clampDate(value, this.picker.minDateTime, this.picker.maxDateTime);
}
this.cdRef.markForCheck();
}
get pickerType() {
return this.picker.pickerType;
}
get cancelLabel() {
return this.pickerIntl.cancelBtnLabel;
}
get setLabel() {
return this.pickerIntl.setBtnLabel;
}
/**
* The range 'from' label
* */
get fromLabel() {
return this.pickerIntl.rangeFromLabel;
}
/**
* The range 'to' label
* */
get toLabel() {
return this.pickerIntl.rangeToLabel;
}
/**
* The range 'from' formatted value
* */
get fromFormattedValue() {
const value = this.picker.selecteds[0];
return value
? this.dateTimeAdapter.format(value, this.picker.formatString)
: '';
}
/**
* The range 'to' formatted value
* */
get toFormattedValue() {
const value = this.picker.selecteds[1];
return value
? this.dateTimeAdapter.format(value, this.picker.formatString)
: '';
}
/**
* Cases in which the control buttons show in the picker
* 1) picker mode is 'dialog'
* 2) picker type is NOT 'calendar' and the picker mode is NOT 'inline'
* */
get showControlButtons() {
return (this.picker.pickerMode === 'dialog' ||
(this.picker.pickerType !== 'calendar' &&
this.picker.pickerMode !== 'inline'));
}
get containerElm() {
return this.elmRef.nativeElement;
}
get owlDTContainerClass() {
return true;
}
get owlDTPopupContainerClass() {
return this.picker.pickerMode === 'popup';
}
get owlDTDialogContainerClass() {
return this.picker.pickerMode === 'dialog';
}
get owlDTInlineContainerClass() {
return this.picker.pickerMode === 'inline';
}
get owlDTContainerDisabledClass() {
return this.picker.disabled;
}
get owlDTContainerId() {
return this.picker.id;
}
get owlDTContainerAnimation() {
return this.picker.pickerMode === 'inline' ? '' : 'enter';
}
ngOnInit() {
if (this.picker.selectMode === 'range') {
if (this.picker.selecteds[0]) {
this.retainStartTime = this.dateTimeAdapter.clone(this.picker.selecteds[0]);
}
if (this.picker.selecteds[1]) {
this.retainEndTime = this.dateTimeAdapter.clone(this.picker.selecteds[1]);
}
}
}
ngAfterContentInit() {
this.initPicker();
}
ngAfterViewInit() {
this.focusPicker();
}
handleContainerAnimationDone(event) {
const toState = event.toState;
if (toState === 'enter') {
this.pickerOpened$.next();
}
}
dateSelected(date) {
let result;
if (this.picker.isInSingleMode) {
result = this.dateSelectedInSingleMode(date);
if (result) {
this.pickerMoment = result;
this.picker.select(result);
}
else {
// we close the picker when result is null and pickerType is calendar.
if (this.pickerType === 'calendar') {
this.hidePicker$.next(null);
}
}
return;
}
if (this.picker.isInRangeMode) {
result = this.dateSelectedInRangeMode(date);
if (result) {
this.pickerMoment = result[this.activeSelectedIndex];
this.picker.select(result);
}
}
}
timeSelected(time) {
this.pickerMoment = this.dateTimeAdapter.clone(time);
if (!this.picker.dateTimeChecker(this.pickerMoment)) {
return;
}
if (this.picker.isInSingleMode) {
this.picker.select(this.pickerMoment);
return;
}
if (this.picker.isInRangeMode) {
const selecteds = [...this.picker.selecteds];
// check if the 'from' is after 'to' or 'to'is before 'from'
// In this case, we set both the 'from' and 'to' the same value
if ((this.activeSelectedIndex === 0 &&
selecteds[1] &&
this.dateTimeAdapter.compare(this.pickerMoment, selecteds[1]) === 1) ||
(this.activeSelectedIndex === 1 &&
selecteds[0] &&
this.dateTimeAdapter.compare(this.pickerMoment, selecteds[0]) === -1)) {
selecteds[0] = this.pickerMoment;
selecteds[1] = this.pickerMoment;
}
else {
selecteds[this.activeSelectedIndex] = this.pickerMoment;
}
if (selecteds[0]) {
this.retainStartTime = this.dateTimeAdapter.clone(selecteds[0]);
}
if (selecteds[1]) {
this.retainEndTime = this.dateTimeAdapter.clone(selecteds[1]);
}
this.picker.select(selecteds);
}
}
/**
* Handle click on cancel button
*/
onCancelClicked(event) {
this.hidePicker$.next(null);
event.preventDefault();
return;
}
/**
* Handle click on set button
*/
onSetClicked(event) {
if (!this.picker.dateTimeChecker(this.pickerMoment)) {
this.hidePicker$.next(null);
even