UNPKG

igniteui-angular

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

1,554 lines • 185 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { CommonModule } from '@angular/common'; import { Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, NgModule, Output, TemplateRef, ViewChild, ContentChild, Injectable } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { HAMMER_GESTURE_CONFIG, HammerGestureConfig } from '@angular/platform-browser'; import { IgxIconModule } from '../icon/index'; import { IgxInputGroupModule, IgxInputGroupComponent } from '../input-group/input-group.component'; import { IgxInputDirective } from '../directives/input/input.directive'; import { IgxAmPmItemDirective, IgxHourItemDirective, IgxItemListDirective, IgxMinuteItemDirective, IgxTimePickerTemplateDirective } from './time-picker.directives'; import { Subject, fromEvent, interval, animationFrameScheduler } from 'rxjs'; import { IGX_TIME_PICKER_COMPONENT } from './time-picker.common'; import { AbsoluteScrollStrategy } from '../services/overlay/scroll'; import { AutoPositionStrategy } from '../services/overlay/position'; import { takeUntil, throttle } from 'rxjs/operators'; import { IgxButtonModule } from '../directives/button/button.directive'; import { IgxMaskModule } from '../directives/mask/mask.directive'; import { IgxToggleModule, IgxToggleDirective } from '../directives/toggle/toggle.directive'; import { TimeDisplayFormatPipe, TimeInputFormatPipe } from './time-picker.pipes'; import { CurrentResourceStrings } from '../core/i18n/resources'; import { InteractionMode } from '../core/enums'; /** @type {?} */ let NEXT_ID = 0; /** @type {?} */ const HOURS_POS = [0, 1, 2]; /** @type {?} */ const MINUTES_POS = [3, 4, 5]; /** @type {?} */ const AMPM_POS = [6, 7, 8]; /** @type {?} */ const ITEMS_COUNT = 7; export class TimePickerHammerConfig extends HammerGestureConfig { constructor() { super(...arguments); this.overrides = { pan: { direction: Hammer.DIRECTION_VERTICAL, threshold: 1 } }; } } TimePickerHammerConfig.decorators = [ { type: Injectable } ]; if (false) { /** @type {?} */ TimePickerHammerConfig.prototype.overrides; } /** * @record */ export function IgxTimePickerValueChangedEventArgs() { } if (false) { /** @type {?} */ IgxTimePickerValueChangedEventArgs.prototype.oldValue; /** @type {?} */ IgxTimePickerValueChangedEventArgs.prototype.newValue; } /** * @record */ export function IgxTimePickerValidationFailedEventArgs() { } if (false) { /** @type {?} */ IgxTimePickerValidationFailedEventArgs.prototype.timePicker; /** @type {?} */ IgxTimePickerValidationFailedEventArgs.prototype.currentValue; /** @type {?} */ IgxTimePickerValidationFailedEventArgs.prototype.setThroughUI; } export class IgxTimePickerComponent { constructor() { /** * An \@Input property that sets the value of the `id` attribute. * ```html * <igx-time-picker [id]="'igx-time-picker-5'" format="h:mm tt" ></igx-time-picker> * ``` */ this.id = `igx-time-picker-${NEXT_ID++}`; /** * An \@Input property that allows you to disable the `igx-time-picker` component. By default `disabled` is set to false. * ```html * <igx-time-picker [disabled]="'true'" [vertical]="true" format="h:mm tt" ></igx-time-picker> * ``` */ this.disabled = false; /** * An \@Input property that gets/sets the delta by which hour and minute items would be changed <br> * when the user presses the Up/Down keys. * By default `itemsDelta` is set to `{hours: 1, minutes:1}` * ```html * <igx-time-picker [itemsDelta]="{hours:3, minutes:5}" id="time-picker"></igx-time-picker> * ``` */ this.itemsDelta = { hours: 1, minutes: 1 }; /** * An \@Input property that determines the spin behavior. By default `isSpinLoop` is set to true. * The minutes and hour spinning will wrap around by default. * ```html * <igx-time-picker [isSpinLoop]="false" id="time-picker"></igx-time-picker> * ``` */ this.isSpinLoop = true; /** * An \@Input property that Gets/Sets the orientation of the `igxTimePicker`. By default `vertical` is set to false. * ```html * <igx-time-picker [vertical]="true" id="time-picker"></igx-time-picker> * ``` */ this.vertical = false; /** * Sets the character used to prompt the user for input. * Default value is "'-'". * ```html * <igx-time-picker [promptChar] = "'_'"> * ``` * \@memberof IgxTimePickerComponent */ this.promptChar = '-'; /** * An \@Input property that allows you to switch the interaction mode between * a dialog picker or dropdown with editable masked input. * Deafult is dialog picker. * ```html * public mode = InteractionMode.DROPDOWN; * //.. * <igx-time-picker [mode]="mode"></igx-time-picker> * ``` * \@memberof IgxTimePickerComponent */ this.mode = InteractionMode.Dialog; /** * Emitted when selection is made. The event contains the selected value. Returns {`oldValue`: `Date`, `newValue`: `Date`}. * ```typescript * \@ViewChild("toast") * private toast: IgxToastComponent; * public onValueChanged(timepicker){ * this.toast.show() * } * //... * ``` * ```html * <igx-time-picker (onValueChanged)="onValueChanged($event)"></igx-time-picker> * <igx-toast #toast message="The value has been changed!"></igx-toast> * ``` */ this.onValueChanged = new EventEmitter(); /** * Emitted when an invalid value is being set. Returns {`timePicker`: `any`, `currentValue`: `Date`, `setThroughUI`: `boolean`} * ```typescript * public min: string = "09:00"; * public max: string = "18:00"; * \@ViewChild("toast") * private toast: IgxToastComponent; * public onValidationFailed(timepicker){ * this.toast.show(); * } * //... * ``` * ```html * <igx-time-picker [minValue]="min" [maxValue]="max" (onValidationFailed)="onValidationFailed($event)"></igx-time-picker> * <igx-toast #toast message="Value must be between 09:00 and 18:00!"></igx-toast> * ``` */ this.onValidationFailed = new EventEmitter(); /** * Emitted when a timePicker is being opened. * ```html * \@ViewChild("toast") * private toast: IgxToastComponent; * public onOpen(timepicker){ * this.toast.show(); * } * //... * ``` * ```html * <igx-time-picker [minValue]="min" [maxValue]="max" (onOpen)="onOpen($event)"></igx-time-picker> * <igx-toast #toast message="The time picker has been opened!"></igx-toast> * ``` */ this.onOpen = new EventEmitter(); /** * Emitted when a timePicker is being closed. */ this.onClose = new EventEmitter(); /** * @hidden */ this._hourItems = []; /** * @hidden */ this._minuteItems = []; /** * @hidden */ this._ampmItems = []; /** * @hidden */ this.cleared = false; /** * @hidden */ this.isNotEmpty = false; /** * @hidden */ this.displayFormat = new TimeDisplayFormatPipe(this); /** * @hidden */ this.inputFormat = new TimeInputFormatPipe(this); this._resourceStrings = CurrentResourceStrings.TimePickerResStrings; this._okButtonLabel = null; this._cancelButtonLabel = null; this._isHourListLoop = this.isSpinLoop; this._isMinuteListLoop = this.isSpinLoop; this._hourView = []; this._minuteView = []; this._ampmView = []; this._destroy$ = new Subject(); this._onTouchedCallback = () => { }; this._onChangeCallback = () => { }; } /** * An accessor that allows you to set a time using the `value` input. * ```html * public date: Date = new Date(Date.now()); * //... * <igx-time-picker [value]="date" format="h:mm tt"></igx-time-picker> * ``` * @param {?} value * @return {?} */ set value(value) { if (this._isValueValid(value)) { /** @type {?} */ const oldVal = this._value; this._value = value; this._onChangeCallback(value); /** @type {?} */ const dispVal = this._formatTime(this.value, this.format); if (this.mode === InteractionMode.DropDown && this._displayValue !== dispVal) { this.displayValue = dispVal; } /** @type {?} */ const args = { oldValue: oldVal, newValue: value }; this.onValueChanged.emit(args); } else { /** @type {?} */ const args = { timePicker: this, currentValue: value, setThroughUI: false }; this.onValidationFailed.emit(args); } } /** * An accessor that returns the value of `igx-time-picker` component. * ```html * \@ViewChild("MyPick") * public pick: IgxTimePickerComponent; * ngAfterViewInit(){ * let pickSelect = this.pick.value; * } * ``` * @return {?} */ get value() { return this._value; } /** * An accessor that sets the resource strings. * By default it uses EN resources. * @param {?} value * @return {?} */ set resourceStrings(value) { this._resourceStrings = Object.assign({}, this._resourceStrings, value); } /** * An accessor that returns the resource strings. * @return {?} */ get resourceStrings() { return this._resourceStrings; } /** * An \@Input property that renders OK button with custom text. By default `okButtonLabel` is set to OK. * ```html * <igx-time-picker okButtonLabel='SET' [value]="date" format="h:mm tt"></igx-time-picker> * ``` * @param {?} value * @return {?} */ set okButtonLabel(value) { this._okButtonLabel = value; } /** * An accessor that returns the label of ok button. * @return {?} */ get okButtonLabel() { return this._okButtonLabel || this.resourceStrings.igx_time_picker_ok; } /** * An \@Input property that renders cancel button with custom text. * By default `cancelButtonLabel` is set to Cancel. * ```html * <igx-time-picker cancelButtonLabel='Exit' [value]="date" format="h:mm tt"></igx-time-picker> * ``` * @param {?} value * @return {?} */ set cancelButtonLabel(value) { this._cancelButtonLabel = value; } /** * An accessor that returns the label of cancel button. * @return {?} */ get cancelButtonLabel() { return this._cancelButtonLabel || this.resourceStrings.igx_time_picker_cancel; } /** * An \@Input property that Gets/Sets format of time while `igxTimePicker` does not have focus. <br> * By default `format` is set to hh:mm tt. <br> * List of time-flags: <br> * `h` : hours field in 12-hours format without leading zero <br> * `hh` : hours field in 12-hours format with leading zero <br> * `H` : hours field in 24-hours format without leading zero <br> * `HH` : hours field in 24-hours format with leading zero <br> * `m` : minutes field without leading zero <br> * `mm` : minutes field with leading zero <br> * `tt` : 2 character string which represents AM/PM field <br> * ```html * <igx-time-picker format="HH:m" id="time-picker"></igx-time-picker> * ``` * @return {?} */ get format() { return this._format || 'hh:mm tt'; } /** * @param {?} formatValue * @return {?} */ set format(formatValue) { this._format = formatValue; this.mask = this._format.indexOf('tt') !== -1 ? '00:00 LL' : '00:00'; if (this.displayValue) { this.displayValue = this._formatTime(this.value, this._format); } } /** * @hidden * @return {?} */ get displayValue() { if (this._displayValue === undefined) { return this._formatTime(this.value, this.format); } return this._displayValue; } /** * @param {?} value * @return {?} */ set displayValue(value) { this._displayValue = value; } /** * Returns the current time formatted as string using the `format` option. * If there is no set time the return is an empty string. * ```typescript * \@ViewChild("MyChild") * private picker: IgxTimePickerComponent; * ngAfterViewInit(){ * let time = this.picker.displayTime; * } * ``` * @return {?} */ get displayTime() { if (this.value) { return this._formatTime(this.value, this.format); } return ''; } /** * @hidden * @return {?} */ get hourView() { return this._hourView; } /** * @hidden * @return {?} */ get minuteView() { return this._minuteView; } /** * @hidden * @return {?} */ get ampmView() { return this._ampmView; } /** * @hidden * @return {?} */ get showClearButton() { return (this.displayValue && this.displayValue !== this.parseMask(false)) || this.isNotEmpty; } /** * @hidden * @return {?} */ get validMinuteEntries() { /** @type {?} */ const minuteEntries = []; for (let i = 0; i < 60; i++) { minuteEntries.push(i); } return minuteEntries; } /** * @hidden * @return {?} */ get validHourEntries() { /** @type {?} */ const hourEntries = []; /** @type {?} */ const index = this.format.indexOf('h') !== -1 ? 13 : 24; for (let i = 0; i < index; i++) { hourEntries.push(i); } return hourEntries; } /** * Gets the input group template. * ```typescript * let template = this.template(); * ``` * \@memberof IgxTimePickerComponent * @return {?} */ get template() { if (this.timePickerTemplateDirective) { return this.timePickerTemplateDirective.template; } return this.mode === InteractionMode.Dialog ? this.defaultTimePickerTemplate : this.dropdownInputTemplate; } /** * Gets the context passed to the input group template. * \@memberof IgxTimePickerComponent * @return {?} */ get context() { return { value: this.value, displayTime: this.displayTime, displayValue: this.displayValue, openDialog: () => { this.openDialog(); } }; } /** * @hidden * @return {?} */ ngOnInit() { this._generateHours(); this._generateMinutes(); if (this.format.indexOf('tt') !== -1) { this._generateAmPm(); } this._dropDownOverlaySettings = { modal: false, closeOnOutsideClick: true, scrollStrategy: new AbsoluteScrollStrategy(), positionStrategy: new AutoPositionStrategy() }; } /** * @hidden * @return {?} */ ngAfterViewInit() { if (this.mode === InteractionMode.DropDown && this.input) { fromEvent(this.input.nativeElement, 'keydown').pipe(throttle(() => interval(0, animationFrameScheduler)), takeUntil(this._destroy$)).subscribe((event) => { if (event.key === "ArrowUp" /* UP_ARROW */ || event.key === "Up" /* UP_ARROW_IE */ || event.key === "ArrowDown" /* DOWN_ARROW */ || event.key === "Down" /* DOWN_ARROW_IE */) { this.spinOnEdit(event); } }); } if (this.container && this.group) { this.container.nativeElement.style.width = this.group.element.nativeElement.getBoundingClientRect().width + 'px'; } if (this.toggleRef) { this.toggleRef.onClosed.pipe(takeUntil(this._destroy$)).subscribe(() => { if (this._input) { this._input.nativeElement.focus(); } if (this.mode === InteractionMode.DropDown) { this._onDropDownClosed(); } this.onClose.emit(this); }); this.toggleRef.onOpened.pipe(takeUntil(this._destroy$)).subscribe(() => { this.onOpen.emit(this); }); } } /** * @hidden * @return {?} */ ngOnDestroy() { this._destroy$.next(true); this._destroy$.complete(); } /** * @hidden * @param {?} event * @return {?} */ onKeydownSpace(event) { this.openDialog(); event.preventDefault(); } /** * @hidden * @return {?} */ onAltArrowDown() { this.openDialog(); } /** * @private * @param {?} item * @param {?} items * @param {?} selectedItem * @param {?} isListLoop * @param {?} viewType * @return {?} */ _scrollItemIntoView(item, items, selectedItem, isListLoop, viewType) { /** @type {?} */ let itemIntoView; if (items) { /** @type {?} */ const index = (item === 'AM' || item === 'PM') ? items.indexOf(item) : items.indexOf(parseInt(item, 10)); /** @type {?} */ let view; if (index !== -1) { if (isListLoop) { if (index > 0) { selectedItem = this._itemToString(items[index - 1], viewType); itemIntoView = this._nextItem(items, selectedItem, isListLoop, viewType); } else { selectedItem = this._itemToString(items[1], viewType); itemIntoView = this._prevItem(items, selectedItem, isListLoop, viewType); } } else { view = items.slice(index - 3, index + 4); selectedItem = this._itemToString(items[index], viewType); itemIntoView = { selectedItem, view }; } itemIntoView.view = this._viewToString(itemIntoView.view, viewType); } } return itemIntoView; } /** * @private * @param {?} view * @param {?} viewType * @return {?} */ _viewToString(view, viewType) { for (let i = 0; i < view.length; i++) { if (typeof (view[i]) !== 'string') { view[i] = this._itemToString(view[i], viewType); } } return view; } /** * @private * @param {?} item * @param {?} viewType * @return {?} */ _itemToString(item, viewType) { if (item === null) { item = ''; } else if (viewType && typeof (item) !== 'string') { /** @type {?} */ const leadZeroHour = (item < 10 && (this.format.indexOf('hh') !== -1 || this.format.indexOf('HH') !== -1)); /** @type {?} */ const leadZeroMinute = (item < 10 && this.format.indexOf('mm') !== -1); /** @type {?} */ const leadZero = (viewType === 'hour') ? leadZeroHour : leadZeroMinute; item = (leadZero) ? '0' + item : `${item}`; } return item; } /** * @private * @param {?} items * @param {?} selectedItem * @param {?} isListLoop * @param {?} viewType * @return {?} */ _prevItem(items, selectedItem, isListLoop, viewType) { /** @type {?} */ const selectedIndex = items.indexOf(parseInt(selectedItem, 10)); /** @type {?} */ const itemsCount = items.length; /** @type {?} */ let view; if (selectedIndex === -1) { view = items.slice(0, 7); selectedItem = items[3]; } else if (isListLoop) { if (selectedIndex - 4 < 0) { view = items.slice(itemsCount - (4 - selectedIndex), itemsCount); view = view.concat(items.slice(0, selectedIndex + 3)); } else if (selectedIndex + 4 > itemsCount) { view = items.slice(selectedIndex - 4, itemsCount); view = view.concat(items.slice(0, selectedIndex + 3 - itemsCount)); } else { view = items.slice(selectedIndex - 4, selectedIndex + 3); } selectedItem = (selectedIndex === 0) ? items[itemsCount - 1] : items[selectedIndex - 1]; } else if (selectedIndex > 3) { view = items.slice(selectedIndex - 4, selectedIndex + 3); selectedItem = items[selectedIndex - 1]; } else if (selectedIndex === 3) { view = items.slice(0, 7); } view = this._viewToString(view, viewType); selectedItem = this._itemToString(selectedItem, viewType); return { selectedItem, view }; } /** * @private * @param {?} items * @param {?} selectedItem * @param {?} isListLoop * @param {?} viewType * @return {?} */ _nextItem(items, selectedItem, isListLoop, viewType) { /** @type {?} */ const selectedIndex = items.indexOf(parseInt(selectedItem, 10)); /** @type {?} */ const itemsCount = items.length; /** @type {?} */ let view; if (selectedIndex === -1) { view = items.slice(0, 7); selectedItem = items[3]; } else if (isListLoop) { if (selectedIndex < 2) { view = items.slice(itemsCount - (2 - selectedIndex), itemsCount); view = view.concat(items.slice(0, selectedIndex + 5)); } else if (selectedIndex + 4 >= itemsCount) { view = items.slice(selectedIndex - 2, itemsCount); view = view.concat(items.slice(0, selectedIndex + 5 - itemsCount)); } else { view = items.slice(selectedIndex - 2, selectedIndex + 5); } selectedItem = (selectedIndex === itemsCount - 1) ? items[0] : items[selectedIndex + 1]; } else if (selectedIndex + 1 < itemsCount - 3) { view = items.slice(selectedIndex - 2, selectedIndex + 5); selectedItem = items[selectedIndex + 1]; } else if (selectedIndex === itemsCount - 4) { view = items.slice(selectedIndex - 3, itemsCount); } view = this._viewToString(view, viewType); selectedItem = this._itemToString(selectedItem, viewType); return { selectedItem, view }; } /** * @private * @param {?} value * @param {?} format * @return {?} */ _formatTime(value, format) { if (!value) { return ''; } else { /** @type {?} */ let hour = value.getHours(); /** @type {?} */ const minute = value.getMinutes(); /** @type {?} */ let formattedMinute; /** @type {?} */ let formattedHour; /** @type {?} */ let amPM; if (format.indexOf('h') !== -1) { amPM = (hour > 11) ? 'PM' : 'AM'; if (hour > 12) { hour -= 12; formattedHour = hour < 10 && format.indexOf('hh') !== -1 ? '0' + hour : `${hour}`; } else if (hour === 0) { formattedHour = '12'; } else if (hour < 10 && format.indexOf('hh') !== -1) { formattedHour = '0' + hour; } else { formattedHour = `${hour}`; } } else { if (hour < 10 && format.indexOf('HH') !== -1) { formattedHour = '0' + hour; } else { formattedHour = `${hour}`; } } formattedMinute = minute < 10 && format.indexOf('mm') !== -1 ? '0' + minute : `${minute}`; return format.replace('hh', formattedHour).replace('h', formattedHour) .replace('HH', formattedHour).replace('H', formattedHour) .replace('mm', formattedMinute).replace('m', formattedMinute) .replace('tt', amPM); } } /** * @private * @param {?} start * @param {?} end * @return {?} */ _updateHourView(start, end) { this._hourView = this._viewToString(this._hourItems.slice(start, end), 'hour'); } /** * @private * @param {?} start * @param {?} end * @return {?} */ _updateMinuteView(start, end) { this._minuteView = this._viewToString(this._minuteItems.slice(start, end), 'minute'); } /** * @private * @param {?} start * @param {?} end * @return {?} */ _updateAmPmView(start, end) { this._ampmView = this._ampmItems.slice(start, end); } /** * @private * @param {?} items * @return {?} */ _addEmptyItems(items) { for (let i = 0; i < 3; i++) { items.push(null); } } /** * @private * @return {?} */ _generateHours() { /** @type {?} */ let hourItemsCount = 24; if (this.format.indexOf('h') !== -1) { hourItemsCount = 13; } hourItemsCount /= this.itemsDelta.hours; /** @type {?} */ let i = this.format.indexOf('H') !== -1 ? 0 : 1; if (hourItemsCount < 7 || !this.isSpinLoop) { this._addEmptyItems(this._hourItems); this._isHourListLoop = false; } if (hourItemsCount > 1) { for (i; i < hourItemsCount; i++) { this._hourItems.push(i * this.itemsDelta.hours); } } else { this._hourItems.push(0); } if (hourItemsCount < 7 || !this.isSpinLoop) { this._addEmptyItems(this._hourItems); } } /** * @private * @return {?} */ _generateMinutes() { /** @type {?} */ const minuteItemsCount = 60 / this.itemsDelta.minutes; if (minuteItemsCount < 7 || !this.isSpinLoop) { this._addEmptyItems(this._minuteItems); this._isMinuteListLoop = false; } for (let i = 0; i < minuteItemsCount; i++) { this._minuteItems.push(i * this.itemsDelta.minutes); } if (minuteItemsCount < 7 || !this.isSpinLoop) { this._addEmptyItems(this._minuteItems); } } /** * @private * @return {?} */ _generateAmPm() { this._addEmptyItems(this._ampmItems); this._ampmItems.push('AM'); this._ampmItems.push('PM'); this._addEmptyItems(this._ampmItems); } /** * @private * @return {?} */ _getSelectedTime() { /** @type {?} */ const date = this.value ? new Date(this.value) : new Date(); date.setHours(parseInt(this.selectedHour, 10)); date.setMinutes(parseInt(this.selectedMinute, 10)); date.setSeconds(0); if (this.selectedAmPm === 'PM' && this.selectedHour !== '12') { date.setHours(date.getHours() + 12); } if (this.selectedAmPm === 'AM' && this.selectedHour === '12') { date.setHours(0); } return date; } /** * @private * @param {?} value * @return {?} */ _convertMinMaxValue(value) { /** @type {?} */ const date = this.value ? new Date(this.value) : this._dateFromModel ? new Date(this._dateFromModel) : new Date(); /** @type {?} */ const sections = value.split(/[\s:]+/); date.setHours(parseInt(sections[0], 10)); date.setMinutes(parseInt(sections[1], 10)); date.setSeconds(0); if (sections[2] && sections[2] === 'PM' && sections[0] !== '12') { date.setHours(date.getHours() + 12); } if (sections[0] === '12' && sections[2] && sections[2] === 'AM') { date.setHours(0); } return date; } /** * @private * @param {?} value * @return {?} */ _isValueValid(value) { if (this.maxValue && value > this._convertMinMaxValue(this.maxValue)) { return false; } else if (this.minValue && value < this._convertMinMaxValue(this.minValue)) { return false; } else { return true; } } /** * @private * @param {?} val * @return {?} */ _isEntryValid(val) { /** @type {?} */ const sections = val.split(/[\s:]+/); /** @type {?} */ const re = new RegExp(this.promptChar, 'g'); /** @type {?} */ const hour = parseInt(sections[0].replace(re, ''), 10); /** @type {?} */ const minutes = parseInt(sections[1].replace(re, ''), 10); return this.validHourEntries.indexOf(hour) !== -1 && this.validMinuteEntries.indexOf(minutes) !== -1; } /** * @private * @return {?} */ _getCursorPosition() { return this.input.nativeElement.selectionStart; } /** * @private * @param {?} start * @param {?=} end * @return {?} */ _setCursorPosition(start, end = start) { this.input.nativeElement.setSelectionRange(start, end); } /** * @private * @return {?} */ _updateEditableInput() { if (this.mode === InteractionMode.DropDown) { this.displayValue = this._formatTime(this._getSelectedTime(), this.format); } } /** * @private * @param {?} currentVal * @param {?} minVal * @param {?} maxVal * @param {?} hDelta * @param {?} sign * @return {?} */ _spinHours(currentVal, minVal, maxVal, hDelta, sign) { /** @type {?} */ const oldVal = new Date(currentVal); currentVal.setMinutes(sign * hDelta); if (currentVal.getDate() !== oldVal.getDate() && this.isSpinLoop) { currentVal.setDate(oldVal.getDate()); } /** @type {?} */ let minutes = currentVal.getMinutes(); if (currentVal.getTime() > maxVal.getTime()) { if (this.isSpinLoop) { minutes = minutes < minVal.getMinutes() ? 60 + minutes : minutes; minVal.setMinutes(sign * minutes); return minVal; } else { return oldVal; } } else if (currentVal.getTime() < minVal.getTime()) { if (this.isSpinLoop) { minutes = minutes <= maxVal.getMinutes() ? minutes : minutes - 60; maxVal.setMinutes(minutes); return maxVal; } else { return oldVal; } } else { return currentVal; } } /** * @private * @param {?} currentVal * @param {?} mDelta * @param {?} sign * @return {?} */ _spinMinutes(currentVal, mDelta, sign) { /** @type {?} */ let minutes = currentVal.getMinutes() + (sign * mDelta); if (minutes < 0 || minutes >= 60) { minutes = this.isSpinLoop ? minutes - (sign * 60) : currentVal.getMinutes(); } currentVal.setMinutes(minutes); return currentVal; } /** * @private * @return {?} */ _initializeContainer() { if (this.value) { /** @type {?} */ const formttedTime = this._formatTime(this.value, this.format); /** @type {?} */ const sections = formttedTime.split(/[\s:]+/); this.selectedHour = sections[0]; this.selectedMinute = sections[1]; if (this._ampmItems !== null) { this.selectedAmPm = sections[2]; } } if (this.selectedHour === undefined) { this.selectedHour = `${this._hourItems[3]}`; } if (this.selectedMinute === undefined) { this.selectedMinute = '0'; } if (this.selectedAmPm === undefined && this._ampmItems !== null) { this.selectedAmPm = this._ampmItems[3]; } this._prevSelectedHour = this.selectedHour; this._prevSelectedMinute = this.selectedMinute; this._prevSelectedAmPm = this.selectedAmPm; this._onTouchedCallback(); this._updateHourView(0, ITEMS_COUNT); this._updateMinuteView(0, ITEMS_COUNT); this._updateAmPmView(0, ITEMS_COUNT); if (this.selectedHour) { this.scrollHourIntoView(this.selectedHour); } if (this.selectedMinute) { this.scrollMinuteIntoView(this.selectedMinute); } if (this.selectedAmPm) { this.scrollAmPmIntoView(this.selectedAmPm); } requestAnimationFrame(() => { this.hourList.nativeElement.focus(); }); } /** * @private * @return {?} */ _closeDropDown() { this.toggleRef.close(); this._onDropDownClosed(); } /** * @private * @return {?} */ _onDropDownClosed() { /** @type {?} */ const oldValue = this.value; /** @type {?} */ const newVal = this._convertMinMaxValue(this.displayValue); if (this._isValueValid(newVal)) { if (!this.value || oldValue.getTime() !== newVal.getTime()) { this.value = newVal; } } else { this.displayValue = this.inputFormat.transform(this._formatTime(oldValue, this.format)); /** @type {?} */ const args = { timePicker: this, currentValue: newVal, setThroughUI: true }; this.onValidationFailed.emit(args); } } /** * @hidden * @return {?} */ getEditElement() { return this._input.nativeElement; } /** * @hidden * @param {?} value * @return {?} */ writeValue(value) { // use this flag to make sure that min/maxValue are checked (in _convertMinMaxValue() method) // against the real value when initializing the component and value is bound via ngModel this._dateFromModel = value; this.value = value; if (this.mode === InteractionMode.DropDown) { this.displayValue = this._formatTime(this.value, this.format); } } /** * @hidden * @param {?} fn * @return {?} */ registerOnChange(fn) { this._onChangeCallback = fn; } /** * @hidden * @param {?} fn * @return {?} */ registerOnTouched(fn) { this._onTouchedCallback = fn; } /** * opens the dialog. * ```html * <igx-time-picker #timePicker></igx-time-picker> * ``` * ```typescript * \@ViewChild('timePicker', { read: IgxTimePickerComponent }) picker: IgxTimePickerComponent; * picker.openDialog(); * ``` * @param {?=} timePicker * @return {?} */ openDialog(timePicker = this) { if (this.toggleRef.collapsed) { /** @type {?} */ let settings; if (this.mode === InteractionMode.Dialog && this.overlaySettings) { settings = this.overlaySettings; } if (this.mode === InteractionMode.DropDown) { settings = this.overlaySettings || this._dropDownOverlaySettings; /** @type {?} */ const posStrategy = settings.positionStrategy; if (this.group && posStrategy) { posStrategy.settings.target = this.group.element.nativeElement; } else if (this.templateDropDownTarget && posStrategy) { posStrategy.settings.target = this.templateDropDownTarget.nativeElement; } else if (!posStrategy || (posStrategy && !posStrategy.settings.target)) { throw new Error('There is no target element for the dropdown to attach.' + 'Mark a DOM element with #dropDownTarget ref variable or provide correct overlay positionStrategy.'); } } if (this.outlet) { settings.outlet = this.outlet; } this.toggleRef.open(settings); this._initializeContainer(); } else if (this.mode === InteractionMode.DropDown) { this._closeDropDown(); } } /** * Scrolls a hour item into view. * ```typescript * scrhintoView(picker) { * picker.scrollHourIntoView('2'); * } * ``` * ```html * <igx-time-picker #picker format="h:mm tt" (onOpen)="scrhintoView(picker)"></igx-time-picker> * ``` * @param {?} item to be scrolled in view. * @return {?} */ scrollHourIntoView(item) { /** @type {?} */ const hourIntoView = this._scrollItemIntoView(item, this._hourItems, this.selectedHour, this._isHourListLoop, 'hour'); if (hourIntoView) { this._hourView = hourIntoView.view; this.selectedHour = hourIntoView.selectedItem; this._updateEditableInput(); } } /** * Scrolls a minute item into view. * ```typescript * scrMintoView(picker) { * picker.scrollMinuteIntoView('3'); * } * ``` * ```html * <igx-time-picker #picker format="h:mm tt" (onOpen)="scrMintoView(picker)"></igx-time-picker> * ``` * @param {?} item to be scrolled in view. * @return {?} */ scrollMinuteIntoView(item) { /** @type {?} */ const minuteIntoView = this._scrollItemIntoView(item, this._minuteItems, this.selectedMinute, this._isMinuteListLoop, 'minute'); if (minuteIntoView) { this._minuteView = minuteIntoView.view; this.selectedMinute = minuteIntoView.selectedItem; this._updateEditableInput(); } } /** * Scrolls an ampm item into view. * ```typescript * scrAmPmIntoView(picker) { * picker.scrollAmPmIntoView('PM'); * } * ``` * ```html * <igx-time-picker #picker format="h:mm tt" (onOpen)="scrAmPmIntoView(picker)"></igx-time-picker> * ``` * @param {?} item to be scrolled in view. * @return {?} */ scrollAmPmIntoView(item) { /** @type {?} */ const ampmIntoView = this._scrollItemIntoView(item, this._ampmItems, this.selectedAmPm, false, null); if (ampmIntoView) { this._ampmView = ampmIntoView.view; this.selectedAmPm = ampmIntoView.selectedItem; this._updateEditableInput(); } } /** * @hidden * @return {?} */ nextHour() { /** @type {?} */ const nextHour = this._nextItem(this._hourItems, this.selectedHour, this._isHourListLoop, 'hour'); this._hourView = nextHour.view; this.selectedHour = nextHour.selectedItem; this._updateEditableInput(); } /** * @hidden * @return {?} */ prevHour() { /** @type {?} */ const prevHour = this._prevItem(this._hourItems, this.selectedHour, this._isHourListLoop, 'hour'); this._hourView = prevHour.view; this.selectedHour = prevHour.selectedItem; this._updateEditableInput(); } /** * @hidden * @return {?} */ nextMinute() { /** @type {?} */ const nextMinute = this._nextItem(this._minuteItems, this.selectedMinute, this._isMinuteListLoop, 'minute'); this._minuteView = nextMinute.view; this.selectedMinute = nextMinute.selectedItem; this._updateEditableInput(); } /** * @hidden * @return {?} */ prevMinute() { /** @type {?} */ const prevMinute = this._prevItem(this._minuteItems, this.selectedMinute, this._isMinuteListLoop, 'minute'); this._minuteView = prevMinute.view; this.selectedMinute = prevMinute.selectedItem; this._updateEditableInput(); } /** * @hidden * @return {?} */ nextAmPm() { /** @type {?} */ const selectedIndex = this._ampmItems.indexOf(this.selectedAmPm); if (selectedIndex + 1 < this._ampmItems.length - 3) { this._updateAmPmView(selectedIndex - 2, selectedIndex + 5); this.selectedAmPm = this._ampmItems[selectedIndex + 1]; this._updateEditableInput(); } } /** * @hidden * @return {?} */ prevAmPm() { /** @type {?} */ const selectedIndex = this._ampmItems.indexOf(this.selectedAmPm); if (selectedIndex > 3) { this._updateAmPmView(selectedIndex - 4, selectedIndex + 3); this.selectedAmPm = this._ampmItems[selectedIndex - 1]; this._updateEditableInput(); } } /** * If current value is valid selects it, closes the dialog and returns true, otherwise returns false. * ```html * <igx-dialog class="igx-time-picker__dialog-popup" [rightButtonLabel]="okButtonLabel" (onRightButtonSelect)="okButtonClick()"> * //.. * </igx-dialog> * ``` * @return {?} */ okButtonClick() { /** @type {?} */ const time = this._getSelectedTime(); if (this._isValueValid(time)) { this.hideOverlay(); this.value = time; return true; } else { /** @type {?} */ const args = { timePicker: this, currentValue: time, setThroughUI: true }; this.onValidationFailed.emit(args); return false; } } /** * Closes the dialog without selecting the current value. * ```html * <igx-dialog class="igx-time-picker__dialog-popup" [leftButtonLabel]="cancelButtonLabel" (onLeftButtonSelect)="cancelButtonClick()"> * //... * </igx-dialog> * ``` * @return {?} */ cancelButtonClick() { this.hideOverlay(); this.selectedHour = this._prevSelectedHour; this.selectedMinute = this._prevSelectedMinute; this.selectedAmPm = this._prevSelectedAmPm; } /** * Returns an array of the hours currently in view. * ```html * \@ViewChild("MyChild") * private picker: IgxTimePickerComponent; * ngAfterViewInit(){ * let hInView = this.picker.hoursInView; * } * ``` * @return {?} */ hoursInView() { return this._hourView.filter((hour) => hour !== ''); } /** * Returns an array of the minutes currently in view. * ```html * \@ViewChild("MyChild") * private picker: IgxTimePickerComponent; * ngAfterViewInit(){ * let minInView = this.picker.minutesInView; * } * ``` * @return {?} */ minutesInView() { return this._minuteView.filter((minute) => minute !== ''); } /** * Returns an array of the AM/PM currently in view. * ```html * \@ViewChild("MyChild") * private picker: IgxTimePickerComponent; * ngAfterViewInit(){ * let ApInView = this.picker.ampmInView; * } * ``` * @return {?} */ ampmInView() { return this._ampmView.filter((ampm) => ampm !== ''); } /** * @hidden * @return {?} */ hideOverlay() { this.toggleRef.close(); } /** * @hidden * @param {?=} preserveAmPm * @return {?} */ parseMask(preserveAmPm = true) { /** @type {?} */ const prompts = this.promptChar + this.promptChar; /** @type {?} */ const amPm = preserveAmPm ? 'AM' : prompts; return this.format.indexOf('tt') !== -1 ? `${prompts}:${prompts} ${amPm}` : `${prompts}:${prompts}`; } /** * @hidden * @return {?} */ clear() { if (this.toggleRef.collapsed) { this.cleared = true; this.isNotEmpty = false; /** @type {?} */ const oldVal = new Date(this.value); this.displayValue = ''; this.value.setHours(0, 0); if (oldVal.getTime() !== this.value.getTime()) { /** @type {?} */ const args = { oldValue: oldVal, newValue: this.value }; this.onValueChanged.emit(args); } } else { this.hideOverlay(); } } /** * @hidden * @param {?} event * @return {?} */ onInput(event) { /** @type {?} */ const val = event.target.value; /** @type {?} */ const oldVal = new Date(this.value); this.isNotEmpty = val !== this.parseMask(false); // handle cases where all empty positions (promts) are filled and we want to update // timepicker own value property if it is a valid Date if (val.indexOf(this.promptChar) === -1) { if (this._isEntryValid(val)) { /** @type {?} */ const newVal = this._convertMinMaxValue(val); if (oldVal.getTime() !== newVal.getTime()) { this.value = newVal; } } else { /** @type {?} */ const args = { timePicker: this, currentValue: val, setThroughUI: false }; this.onValidationFailed.emit(args); } // handle cases where the user deletes the display value (when pressing backspace or delete) } else if (!this.value || !val || val === this.parseMask(false)) { this.isNotEmpty = false; this.value.setHours(0, 0); this.displayValue = val; if (oldVal.getTime() !== this.value.getTime()) { /** @type {?} */ const args = { oldValue: oldVal, newValue: this.value }; this.onValueChanged.emit(args); } } } /** * @hidden * @param {?} event * @return {?} */ onFocus(event) { this.isNotEmpty = event.target.value !== this.parseMask(false); } /** * @hidden * @param {?} event * @return {?} */ onBlur(event) { /** @type {?} */ const value = event.target.value; this.isNotEmpty = value !== ''; this.displayValue = value; if (value && value !== this.parseMask()) { if (this._isEntryValid(value)) { /** @type {?} */ const newVal = this._convertMinMaxValue(value); if (!this.value || this.value.getTime() !== newVal.getTime()) { this.value = newVal; } } else { /** @type {?} */ const args = { timePicker: this, currentValue: value, setThroughUI: false }; this.onValidationFailed.emit(args); } } } /** * @hidden * @param {?} event * @return {?} */ spinOnEdit(event) { event.preventDefault(); /** @type {?} */ let sign; /** @type {?} */ let displayVal; /** @type {?} */ const currentVal = new Date(this.value); /** @type {?} */ const min = this.minValue ? this._convertMinMaxValue(this.minValue) : this._convertMinMaxValue('00:00'); /** @type {?} */ const max = this.maxValue ? this._convertMinMaxValue(this.maxValue) : this._convertMinMaxValue('24:00'); /** @type {?} */ const cursor = this._getCursorPosition(); if (event.key) { /** @type {?} */ const key = event.key; sign = key === "ArrowDown" /* DOWN_ARROW */ || key === "Down" /* DOWN_ARROW_IE */ ? -1 : 1; } if (event.deltaY) { sign = event.deltaY < 0 ? 1 : -1; } if (!this.displayValue) { this.value = min; displayVal = this._formatTime(this.value, this.format); } else { /** @type {?} */ const hDelta = this.itemsDelta.hours * 60 + (sign * this.value.getMinutes()); /** @type {?} */ const