From 589273e550220e8118465384686d0440653e6d63 Mon Sep 17 00:00:00 2001 From: TianHun Date: Fri, 30 Aug 2019 12:03:55 +0800 Subject: [PATCH 1/9] feat(time-picker): add support second --- .../time-picker/_time-picker-component.scss | 5 + .../time-picker/_time-picker-theme.scss | 4 + .../src/lib/time-picker/time-picker.common.ts | 5 + .../time-picker/time-picker.component.html | 5 +- .../lib/time-picker/time-picker.component.ts | 156 +++++++++++++++++- .../lib/time-picker/time-picker.directives.ts | 72 +++++++- .../hierarchical-grid.sample.ts | 2 +- src/app/time-picker/time-picker.sample.html | 6 +- src/app/time-picker/time-picker.sample.ts | 2 +- 9 files changed, 238 insertions(+), 19 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-component.scss index c36ed9f41d8..9026201b156 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-component.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-component.scss @@ -47,6 +47,11 @@ @extend %time-picker__minuteList !optional; } + // SECOND + @include e(secondList) { + @extend %time-picker__secondList !optional; + } + // AM PM @include e(ampmList) { @extend %time-picker__ampmList !optional; diff --git a/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-theme.scss index 685649fd772..486154759d7 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-theme.scss @@ -187,6 +187,10 @@ text-align: center; } + %time-picker__secondList { + text-align: center; + } + %time-picker__ampmList { display: flex; flex-direction: column; diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts index 69aceb1b50c..025c63f29fe 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts @@ -8,9 +8,11 @@ export const IGX_TIME_PICKER_COMPONENT = 'IgxTimePickerComponentToken'; export interface IgxTimePickerBase { hourList: ElementRef; minuteList: ElementRef; + secondList: ElementRef; ampmList: ElementRef; selectedHour: string; selectedMinute: string; + selectedSecond: string; selectedAmPm: string; format: string; promptChar: string; @@ -18,11 +20,14 @@ export interface IgxTimePickerBase { mode: InteractionMode; showHoursList: boolean; showMinutesList: boolean; + showSecondsList: boolean; showAmPmList: boolean; nextHour(); prevHour(); nextMinute(); prevMinute(); + nextSecond(); + prevSecond(); nextAmPm(); prevAmPm(); okButtonClick(): boolean; diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html index d050257e794..2f983cb73e4 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html @@ -50,10 +50,13 @@

{{ minute }}
+
+ {{ second }} +
{{ ampm }}
- \ No newline at end of file + diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts index 06d1b2c301e..bf861458cbf 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts @@ -26,8 +26,9 @@ import { IgxInputDirective } from '../directives/input/input.directive'; import { IgxAmPmItemDirective, IgxHourItemDirective, - IgxItemListDirective, IgxMinuteItemDirective, + IgxSecondItemDirective, + IgxItemListDirective, IgxTimePickerTemplateDirective, IgxTimePickerActionsDirective } from './time-picker.directives'; @@ -243,7 +244,7 @@ export class IgxTimePickerComponent implements *``` */ @Input() - public itemsDelta = { hours: 1, minutes: 1 }; + public itemsDelta = { hours: 1, minutes: 1, seconds: 1 }; /** * An @Input property that allows you to set the `minValue` to limit the user input. @@ -308,9 +309,9 @@ export class IgxTimePickerComponent implements set format(formatValue: string) { this._format = formatValue; - this.mask = this._format.indexOf('tt') !== -1 ? '00:00 LL' : '00:00'; + this.mask = this._format.indexOf('tt') !== -1 ? '00:00:00 LL' : '00:00:00'; - if (!this.showHoursList || !this.showMinutesList) { + if (!this.showHoursList || !this.showMinutesList || !this.showSecondsList) { this.mask = this.mask.slice(this.mask.indexOf(':') + 1, this.mask.length); } @@ -490,6 +491,12 @@ export class IgxTimePickerComponent implements @ViewChild('minuteList', { static: false }) public minuteList: ElementRef; + /** + * @hidden + */ + @ViewChild('secondList', { static: false }) + public secondList: ElementRef; + /** * @hidden */ @@ -550,10 +557,17 @@ export class IgxTimePickerComponent implements * @hidden */ public _hourItems = []; + /** * @hidden */ public _minuteItems = []; + + /** + * @hidden + */ + public _secondItems = []; + /** * @hidden */ @@ -563,14 +577,17 @@ export class IgxTimePickerComponent implements * @hidden */ public cleared = false; + /** * @hidden */ public isNotEmpty = false; + /** * @hidden */ public displayFormat = new TimeDisplayFormatPipe(this); + /** * @hidden */ @@ -580,10 +597,17 @@ export class IgxTimePickerComponent implements * @hidden */ public selectedHour: string; + /** * @hidden */ public selectedMinute: string; + + /** + * @hidden + */ + public selectedSecond: string; + /** * @hidden */ @@ -599,9 +623,11 @@ export class IgxTimePickerComponent implements private _isHourListLoop = this.isSpinLoop; private _isMinuteListLoop = this.isSpinLoop; + private _isSecondListLoop = this.isSpinLoop; private _hourView = []; private _minuteView = []; + private _secondView = []; private _ampmView = []; private _dateFromModel: Date; @@ -611,6 +637,7 @@ export class IgxTimePickerComponent implements private _prevSelectedHour: string; private _prevSelectedMinute: string; + private _prevSelectedSecond: string; private _prevSelectedAmPm: string; private _onOpen = new EventEmitter(); @@ -676,6 +703,13 @@ export class IgxTimePickerComponent implements return this._minuteView; } + /** + * @hidden + */ + get secondView(): string[] { + return this._secondView; + } + /** * @hidden */ @@ -704,6 +738,13 @@ export class IgxTimePickerComponent implements return this.format.indexOf('m') !== - 1; } + /** + * @hidden + */ + get showSecondsList(): boolean { + return this.format.indexOf('s') !== - 1; + } + /** * @hidden */ @@ -767,6 +808,7 @@ export class IgxTimePickerComponent implements public ngOnInit(): void { this._generateHours(); this._generateMinutes(); + this._generateSeconds(); if (this.format.indexOf('tt') !== -1) { this._generateAmPm(); } @@ -977,9 +1019,10 @@ export class IgxTimePickerComponent implements return ''; } else { let hour = value.getHours(); - let formattedMinute, formattedHour; + let formattedSecond, formattedMinute, formattedHour; const minute = value.getMinutes(); + const second = value.getSeconds(); const amPM = (hour > 11) ? 'PM' : 'AM'; if (format.indexOf('h') !== -1) { @@ -1003,9 +1046,12 @@ export class IgxTimePickerComponent implements formattedMinute = minute < 10 && format.indexOf('mm') !== -1 ? '0' + minute : `${minute}`; + formattedSecond = second < 10 && format.indexOf('ss') !== -1 ? '0' + second : `${second}`; + return format.replace('hh', formattedHour).replace('h', formattedHour) .replace('HH', formattedHour).replace('H', formattedHour) .replace('mm', formattedMinute).replace('m', formattedMinute) + .replace('ss', formattedSecond).replace('m', formattedSecond) .replace('tt', amPM); } } @@ -1018,6 +1064,10 @@ export class IgxTimePickerComponent implements this._minuteView = this._viewToString(this._minuteItems.slice(start, end), 'minute'); } + private _updateSecondView(start: any, end: any): void { + this._secondView = this._viewToString(this._secondItems.slice(start, end), 'second'); + } + private _updateAmPmView(start: any, end: any): void { this._ampmView = this._ampmItems.slice(start, end); } @@ -1073,6 +1123,23 @@ export class IgxTimePickerComponent implements } } + private _generateSeconds(): void { + const secondItemsCount = 60 / this.itemsDelta.seconds; + + if (secondItemsCount < 7 || !this.isSpinLoop) { + this._addEmptyItems(this._secondItems); + this._isSecondListLoop = false; + } + + for (let i = 0; i < secondItemsCount; i++) { + this._secondItems.push(i * this.itemsDelta.seconds); + } + + if (secondItemsCount < 7 || !this.isSpinLoop) { + this._addEmptyItems(this._secondItems); + } + } + private _generateAmPm(): void { this._addEmptyItems(this._ampmItems); @@ -1091,7 +1158,9 @@ export class IgxTimePickerComponent implements if (this.selectedMinute) { date.setMinutes(parseInt(this.selectedMinute, 10)); } - date.setSeconds(0); + if (this.selectedSecond) { + date.setSeconds(parseInt(this.selectedSecond, 10)); + } if (((this.showHoursList && this.selectedHour !== '12') || (!this.showHoursList && this.selectedHour <= '11')) && this.selectedAmPm === 'PM') { date.setHours(date.getHours() + 12); @@ -1239,6 +1308,10 @@ export class IgxTimePickerComponent implements this.selectedMinute = this.showHoursList ? sections[1] : sections[0]; } + if (this.showSecondsList) { + this.selectedSecond = this.showMinutesList ? sections[2] : sections[1]; + } + if (this.showAmPmList && this._ampmItems !== null) { this.selectedAmPm = sections[sections.length - 1]; } @@ -1251,18 +1324,23 @@ export class IgxTimePickerComponent implements if (this.selectedMinute === undefined) { this.selectedMinute = !this.showMinutesList && this.value ? this.value.getMinutes().toString() : '0'; } + if (this.selectedSecond === undefined) { + this.selectedSecond = !this.showSecondsList && this.value ? this.value.getSeconds().toString() : '0'; + } if (this.selectedAmPm === undefined && this._ampmItems !== null) { this.selectedAmPm = this._ampmItems[3]; } this._prevSelectedHour = this.selectedHour; this._prevSelectedMinute = this.selectedMinute; + this._prevSelectedSecond = this.selectedSecond; this._prevSelectedAmPm = this.selectedAmPm; this._onTouchedCallback(); this._updateHourView(0, ITEMS_COUNT); this._updateMinuteView(0, ITEMS_COUNT); + this._updateSecondView(0, ITEMS_COUNT); this._updateAmPmView(0, ITEMS_COUNT); if (this.selectedHour) { @@ -1271,6 +1349,9 @@ export class IgxTimePickerComponent implements if (this.selectedMinute) { this.scrollMinuteIntoView(this.selectedMinute); } + if (this.selectedSecond) { + this.scrollSecondIntoView(this.selectedSecond); + } if (this.selectedAmPm) { this.scrollAmPmIntoView(this.selectedAmPm); } @@ -1423,6 +1504,29 @@ export class IgxTimePickerComponent implements } } + /** + * Scrolls a second item into view. + * ```typescript + *scrMintoView(picker) { + *picker.scrollSecondIntoView('4'); + *} + * ``` + *```html + * + *``` + * @param item to be scrolled in view. + */ + public scrollSecondIntoView(item: string): void { + if (this.showSecondsList) { + const secondIntoView = this._scrollItemIntoView(item, this._minuteItems, this.selectedSecond, this._isSecondListLoop, 'second'); + if (secondIntoView) { + this._secondView = secondIntoView.view; + this.selectedSecond = secondIntoView.selectedItem; + this._updateEditableInput(); + } + } + } + /** * Scrolls an ampm item into view. * ```typescript @@ -1490,6 +1594,28 @@ export class IgxTimePickerComponent implements this._updateEditableInput(); } + /** + * @hidden + */ + public nextSecond() { + const nextSecond = this._nextItem(this._secondItems, this.selectedSecond, this._isSecondListLoop, 'second'); + this._secondView = nextSecond.view; + this.selectedSecond = nextSecond.selectedItem; + + this._updateEditableInput(); + } + + /** + * @hidden + */ + public prevSecond() { + const prevSecond = this._prevItem(this._secondItems, this.selectedSecond, this._isSecondListLoop, 'second'); + this._secondView = prevSecond.view; + this.selectedSecond = prevSecond.selectedItem; + + this._updateEditableInput(); + } + /** * @hidden */ @@ -1560,6 +1686,7 @@ export class IgxTimePickerComponent implements this.selectedHour = this._prevSelectedHour; this.selectedMinute = this._prevSelectedMinute; + this.selectedSecond = this._prevSelectedSecond; this.selectedAmPm = this._prevSelectedAmPm; } @@ -1591,6 +1718,20 @@ export class IgxTimePickerComponent implements return this._minuteView.filter((minute) => minute !== ''); } + /** + * Returns an array of the seconds currently in view. + *```html + *@ViewChild("MyChild") + *private picker: IgxTimePickerComponent; + *ngAfterViewInit(){ + * let minInView = this.picker.secondsInView; + *} + *``` + */ + public secondsInView(): string[] { + return this._secondView.filter((second) => second !== ''); + } + /** * Returns an array of the AM/PM currently in view. *```html @@ -1801,8 +1942,9 @@ export class IgxTimePickerComponent implements declarations: [ IgxTimePickerComponent, IgxHourItemDirective, - IgxItemListDirective, IgxMinuteItemDirective, + IgxSecondItemDirective, + IgxItemListDirective, IgxAmPmItemDirective, IgxTimePickerTemplateDirective, IgxTimePickerActionsDirective, diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts index b3e92aa9bf2..8ba48d844dc 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts @@ -26,9 +26,10 @@ export class IgxItemListDirective { public isActive: boolean; - constructor(@Inject(IGX_TIME_PICKER_COMPONENT) - public timePicker: IgxTimePickerBase, - private elementRef: ElementRef) { } + constructor( + @Inject(IGX_TIME_PICKER_COMPONENT) public timePicker: IgxTimePickerBase, + private elementRef: ElementRef + ) { } @HostBinding('attr.tabindex') public tabindex = 0; @@ -48,6 +49,11 @@ export class IgxItemListDirective { return this.type === 'minuteList'; } + @HostBinding('class.igx-time-picker__secondList') + get secondCSS(): boolean { + return this.type === 'secondList'; + } + @HostBinding('class.igx-time-picker__ampmList') get ampmCSS(): boolean { return this.type === 'ampmList'; @@ -73,6 +79,10 @@ export class IgxItemListDirective { this.timePicker.nextMinute(); break; } + case 'secondList': { + this.timePicker.nextSecond(); + break; + } case 'ampmList': { this.timePicker.nextAmPm(); break; @@ -90,6 +100,10 @@ export class IgxItemListDirective { this.timePicker.prevMinute(); break; } + case 'secondList': { + this.timePicker.prevSecond(); + break; + } case 'ampmList': { this.timePicker.prevAmPm(); break; @@ -128,7 +142,9 @@ export class IgxItemListDirective { if (listName.indexOf('hourList') !== -1 && this.timePicker.minuteList) { this.timePicker.minuteList.nativeElement.focus(); - } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.ampmList) { + } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.secondList) { + this.timePicker.secondList.nativeElement.focus(); + } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1 || listName.indexOf('secondList') !== -1) && this.timePicker.ampmList) { this.timePicker.ampmList.nativeElement.focus(); } } @@ -142,9 +158,11 @@ export class IgxItemListDirective { const listName = (event.target as HTMLElement).className; - if (listName.indexOf('ampmList') !== -1 && this.timePicker.minuteList) { + if (listName.indexOf('ampmList') !== -1 && this.timePicker.secondList) { + this.timePicker.secondList.nativeElement.focus(); + } else if (listName.indexOf('ampmList') !== -1 || listName.indexOf('secondList') !== -1 && this.timePicker.minuteList) { this.timePicker.minuteList.nativeElement.focus(); - } else if ((listName.indexOf('ampmList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.hourList) { + } else if ((listName.indexOf('ampmList') !== -1 || listName.indexOf('secondList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.hourList) { this.timePicker.hourList.nativeElement.focus(); } } @@ -293,6 +311,48 @@ export class IgxMinuteItemDirective { } } +/** + * @hidden + */ +@Directive({ + selector: '[igxSecondItem]' +}) +export class IgxSecondItemDirective { + + @Input('igxSecondItem') + public value: string; + + @HostBinding('class.igx-time-picker__item') + get defaultCSS(): boolean { + return true; + } + + @HostBinding('class.igx-time-picker__item--selected') + get selectedCSS(): boolean { + return this.isSelectedSecond; + } + + @HostBinding('class.igx-time-picker__item--active') + get activeCSS(): boolean { + return this.isSelectedSecond && this.itemList.isActive; + } + + get isSelectedSecond(): boolean { + return this.timePicker.selectedSecond === this.value; + } + + constructor(@Inject(IGX_TIME_PICKER_COMPONENT) + public timePicker: IgxTimePickerBase, + private itemList: IgxItemListDirective) { } + + @HostListener('click', ['value']) + public onClick(item) { + if (item !== '') { + this.timePicker.scrollMinuteIntoView(item); + } + } +} + /** * @hidden */ diff --git a/src/app/hierarchical-grid/hierarchical-grid.sample.ts b/src/app/hierarchical-grid/hierarchical-grid.sample.ts index 76c79ab8fdf..6825d6fcdf7 100644 --- a/src/app/hierarchical-grid/hierarchical-grid.sample.ts +++ b/src/app/hierarchical-grid/hierarchical-grid.sample.ts @@ -103,7 +103,7 @@ export class HierarchicalGridSampleComponent { cellClick($evt: IGridCellEventArgs) { console.log('Cell Click', $evt); - console.log($evt.context); + console.log($evt); } public LoadMoreColumns() { diff --git a/src/app/time-picker/time-picker.sample.html b/src/app/time-picker/time-picker.sample.html index 8860be078f4..01cafbbcc87 100644 --- a/src/app/time-picker/time-picker.sample.html +++ b/src/app/time-picker/time-picker.sample.html @@ -64,7 +64,7 @@

Templated Time Picker

Time picker with required input group

- @@ -101,7 +101,7 @@

Templated Time Picker

Templated Time Picker

Time picker with dropdown mode + overlay settings + custom buttons

- + @@ -119,4 +119,4 @@

Templated Time Picker

-
\ No newline at end of file + diff --git a/src/app/time-picker/time-picker.sample.ts b/src/app/time-picker/time-picker.sample.ts index fe8359c9d17..85076677a85 100644 --- a/src/app/time-picker/time-picker.sample.ts +++ b/src/app/time-picker/time-picker.sample.ts @@ -18,7 +18,7 @@ export class TimePickerSampleComponent implements AfterViewInit { date1 = new Date(2018, 10, 27, 17, 45, 0, 0); date = new Date(2018, 10, 27, 17, 45, 0, 0); - val = new Date(0, 0, 0, 19, 35, 0, 0); + val = new Date(0, 0, 0, 19, 35, 30, 0); today = new Date(Date.now()); isRequired = true; From f9334d8922ee7a89790e7d6fb7d222225cbfc238 Mon Sep 17 00:00:00 2001 From: TianHun Date: Fri, 30 Aug 2019 15:14:00 +0800 Subject: [PATCH 2/9] feat(time-picker): amend README.md and spect.ts --- .../src/lib/time-picker/README.md | 2 + .../time-picker/time-picker.component.spec.ts | 99 ++++++++++++++++++- .../lib/time-picker/time-picker.component.ts | 2 +- 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/time-picker/README.md b/projects/igniteui-angular/src/lib/time-picker/README.md index eb44e615285..3c0478b83c9 100644 --- a/projects/igniteui-angular/src/lib/time-picker/README.md +++ b/projects/igniteui-angular/src/lib/time-picker/README.md @@ -120,6 +120,8 @@ List of time-flags: "HH": hours field in 24-hours format with leading zero "m": minutes field without leading zero "mm": minutes field with leading zero +"s": seconds field without leading zero +"ss": seconds field with leading zero "tt": 2 characters of string which represents AM/PM field | | `isSpinLoop` | boolean | Determines the spin behavior. By default `isSpinLoop` is set to true. | | `mode` | InteractionMode | Determines the interaction mode - a dialog picker or a dropdown with editable masked input. Default is dialog picker.| diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts index a28e81c6bc8..6efeecdc308 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts @@ -124,16 +124,19 @@ describe('IgxTimePicker', () => { const expectedColumnElements = 7; const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')).nativeElement.children; const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')).nativeElement.children; + const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')).nativeElement.children; const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')).nativeElement.children; // check element count expect(hourColumn.length).toBe(expectedColumnElements); expect(minuteColumn.length).toBe(expectedColumnElements); + expect(secondColumn.length).toBe(expectedColumnElements); expect(AMPMColumn.length).toBe(expectedColumnElements); // verify selected's position to be in the middle expect(hourColumn[3].classList).toContain('igx-time-picker__item--selected'); expect(minuteColumn[3].classList).toContain('igx-time-picker__item--selected'); + expect(secondColumn[3].classList).toContain('igx-time-picker__item--selected'); expect(AMPMColumn[3].classList).toContain('igx-time-picker__item--selected'); })); @@ -173,6 +176,8 @@ describe('IgxTimePicker', () => { const selectHour = hourColumn.children[middlePos - 3]; const minutesColumn = dom.query(By.css('.igx-time-picker__minuteList')); const selectMinutes = minutesColumn.children[middlePos - 3]; + const secondsColumn = dom.query(By.css('.igx-time-picker__secondList')); + const selectSeconds = secondsColumn.children[middlePos - 3]; UIInteractions.clickElement(selectHour); fixture.detectChanges(); @@ -180,6 +185,9 @@ describe('IgxTimePicker', () => { UIInteractions.clickElement(selectMinutes); fixture.detectChanges(); + UIInteractions.clickElement(selectSeconds); + fixture.detectChanges(); + const AMPMColumn = dom.query(By.css('.igx-time-picker__ampmList')); const selectAMPM = findByInnerText(AMPMColumn.children, 'AM'); @@ -215,6 +223,8 @@ describe('IgxTimePicker', () => { const selectHour = hourColumn.children[middlePos + 2]; const minutesColumn = dom.query(By.css('.igx-time-picker__minuteList')); const selectMinutes = minutesColumn.children[middlePos - 3]; + const secondsColumn = dom.query(By.css('.igx-time-picker__secondList')); + const selectSeconds = secondsColumn.children[middlePos - 3]; UIInteractions.clickElement(selectHour); fixture.detectChanges(); @@ -222,6 +232,9 @@ describe('IgxTimePicker', () => { UIInteractions.clickElement(selectMinutes); fixture.detectChanges(); + UIInteractions.clickElement(selectSeconds); + fixture.detectChanges(); + const AMPMColumn = dom.query(By.css('.igx-time-picker__ampmList')); const selectAMPM = findByInnerText(AMPMColumn.children, 'AM'); @@ -262,6 +275,10 @@ describe('IgxTimePicker', () => { const selectMinutes = minutesColumn.children[2]; const minuteValue = selectMinutes.nativeElement.innerText; + const secondsColumn = dom.query(By.css('.igx-time-picker__secondList')); + const selectSeconds = secondsColumn.children[2]; + const secondValue = selectSeconds.nativeElement.innerText; + const AMPMColumn = dom.query(By.css('.igx-time-picker__ampmList')); const selectAMPM = AMPMColumn.children[4]; const aMPMValue = selectAMPM.nativeElement.innerText; @@ -272,6 +289,9 @@ describe('IgxTimePicker', () => { UIInteractions.clickElement(selectMinutes); fixture.detectChanges(); + UIInteractions.clickElement(selectSeconds); + fixture.detectChanges(); + UIInteractions.clickElement(selectAMPM); fixture.detectChanges(); @@ -286,7 +306,7 @@ describe('IgxTimePicker', () => { expect(timePicker.onValueChanged.emit).toHaveBeenCalled(); const valueFromInput = dom.query(By.directive(IgxInputDirective)).nativeElement.value; - const selectedTime = `${hourValue}:${minuteValue} ${aMPMValue}`; + const selectedTime = `${hourValue}:${minuteValue}:${secondValue} ${aMPMValue}`; expect(valueFromInput).toEqual(selectedTime); })); @@ -304,6 +324,7 @@ describe('IgxTimePicker', () => { const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); + const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); hourColumn.nativeElement.focus(); @@ -336,6 +357,22 @@ describe('IgxTimePicker', () => { minuteColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); fixture.detectChanges(); + secondColumn.nativeElement.focus(); + fixture.detectChanges(); + + // move arrows several times with minute column + args = { key: 'ArrowDown', bubbles: true }; + secondColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + fixture.detectChanges(); + + args = { key: 'ArrowUp', bubbles: true }; + secondColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + fixture.detectChanges(); + + args = { key: 'ArrowDown', bubbles: true }; + secondColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + fixture.detectChanges(); + AMPMColumn.nativeElement.focus(); // move arrows several times with ampm column @@ -437,6 +474,7 @@ describe('IgxTimePicker', () => { // const timePicker = fixture.componentInstance.timePicker; const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); + const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); hourColumn.triggerEventHandler('focus', {}); @@ -450,6 +488,10 @@ describe('IgxTimePicker', () => { fixture.detectChanges(); expect(document.activeElement.classList).toContain('igx-time-picker__minuteList'); + secondColumn.triggerEventHandler('mouseover', {}); + fixture.detectChanges(); + expect(document.activeElement.classList).toContain('igx-time-picker__secondList'); + AMPMColumn.triggerEventHandler('mouseover', {}); fixture.detectChanges(); expect(document.activeElement.classList).toContain('igx-time-picker__ampmList'); @@ -469,6 +511,7 @@ describe('IgxTimePicker', () => { // const timePicker = fixture.componentInstance.timePicker; const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); + const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); let event = new WheelEvent('wheel', { deltaX: 0, deltaY: 0 }); @@ -512,6 +555,24 @@ describe('IgxTimePicker', () => { // move the mouse wheel down and expect the selected element to be 24 again expect(minuteColumn.nativeElement.children[3].innerText).toBe('24'); + // focus seconds + secondColumn.nativeElement.focus(); + fixture.detectChanges(); + + event = new WheelEvent('wheel', { deltaX: 0, deltaY: -100 }); + secondColumn.triggerEventHandler('wheel', event); + fixture.detectChanges(); + + // move the mouse wheel up and expect the selected element to be 23 + expect(secondColumn.nativeElement.children[3].innerText).toBe('25'); + + event = new WheelEvent('wheel', { deltaX: 0, deltaY: 100 }); + secondColumn.triggerEventHandler('wheel', event); + fixture.detectChanges(); + + // move the mouse wheel down and expect the selected element to be 24 again + expect(secondColumn.nativeElement.children[3].innerText).toBe('26'); + // focus ampm AMPMColumn.nativeElement.focus(); fixture.detectChanges(); @@ -545,6 +606,7 @@ describe('IgxTimePicker', () => { // const timePicker = fixture.componentInstance.timePicker; const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); + const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); // panmove is in reverse direction of mouse wheel @@ -587,6 +649,22 @@ describe('IgxTimePicker', () => { // swipe down and expect the selected element to be 24 again expect(minuteColumn.nativeElement.children[3].innerText).toBe('24'); + // focus minutes + secondColumn.nativeElement.focus(); + fixture.detectChanges(); + + secondColumn.triggerEventHandler('panmove', eventDown); + fixture.detectChanges(); + + // swipe up and expect the selected element to be 25 + expect(secondColumn.nativeElement.children[3].innerText).toBe('26'); + + secondColumn.triggerEventHandler('panmove', eventUp); + fixture.detectChanges(); + + // swipe down and expect the selected element to be 24 again + expect(secondColumn.nativeElement.children[3].innerText).toBe('27'); + // focus ampm AMPMColumn.nativeElement.focus(); fixture.detectChanges(); @@ -637,10 +715,12 @@ describe('IgxTimePicker', () => { const hoursInview = timePicker.hoursInView(); const minutesInview = timePicker.minutesInView(); + const secondsInview = timePicker.minutesInView(); const AMPMInview = timePicker.ampmInView(); expect(hoursInview).toEqual(['08', '09', '10', '11', '12', '01', '02']); expect(minutesInview).toEqual(['24', '25', '26', '27', '28', '29', '30']); + expect(secondsInview).toEqual(['24', '25', '26', '27', '28', '29', '30']); expect(AMPMInview).toEqual(['AM', 'PM']); })); @@ -658,6 +738,7 @@ describe('IgxTimePicker', () => { const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); + const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); hourColumn.nativeElement.focus(); @@ -676,6 +757,12 @@ describe('IgxTimePicker', () => { minuteColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); + secondColumn.nativeElement.focus(); + fixture.detectChanges(); + + secondColumn.triggerEventHandler('wheel', event); + fixture.detectChanges(); + AMPMColumn.nativeElement.focus(); fixture.detectChanges(); @@ -687,9 +774,10 @@ describe('IgxTimePicker', () => { const formatedHours = initialTime.getHours() < 10 ? '0' + initialTime.getHours() : initialTime.getHours(); const formatedMinutes = initialTime.getMinutes() < 10 ? '0' + initialTime.getMinutes() : initialTime.getMinutes(); + const formatedSeconds = initialTime.getSeconds() < 10 ? '0' + initialTime.getSeconds() : initialTime.getSeconds(); const formatedTestElementTime = - `${formatedHours}:${formatedMinutes} ${initialTime.getHours() >= 12 ? 'PM' : 'AM'}`; + `${formatedHours}:${formatedMinutes}:${formatedSeconds} ${initialTime.getHours() >= 12 ? 'PM' : 'AM'}`; // get time from dialog header const timeFromPopupHeader: any = fixture.debugElement.query(By.css('.igx-time-picker__header')).nativeElement.children; @@ -712,6 +800,7 @@ describe('IgxTimePicker', () => { const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); + const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); const event = new WheelEvent('wheel', { deltaX: 0, deltaY: 100 }); @@ -730,6 +819,12 @@ describe('IgxTimePicker', () => { minuteColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); + secondColumn.nativeElement.focus(); + fixture.detectChanges(); + + secondColumn.triggerEventHandler('wheel', event); + fixture.detectChanges(); + AMPMColumn.nativeElement.focus(); fixture.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts index bf861458cbf..04a8a8ddbfe 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts @@ -1051,7 +1051,7 @@ export class IgxTimePickerComponent implements return format.replace('hh', formattedHour).replace('h', formattedHour) .replace('HH', formattedHour).replace('H', formattedHour) .replace('mm', formattedMinute).replace('m', formattedMinute) - .replace('ss', formattedSecond).replace('m', formattedSecond) + .replace('ss', formattedSecond).replace('s', formattedSecond) .replace('tt', amPM); } } From 32c2f1db46cf712bcc458fa5e5baf6090a6c8cc2 Mon Sep 17 00:00:00 2001 From: TianHun Date: Thu, 26 Sep 2019 16:48:40 +0800 Subject: [PATCH 3/9] fix(time-picker): fix select seconds bugs --- .../time-picker/_time-picker-component.scss | 6 +- .../time-picker/_time-picker-theme.scss | 2 +- .../src/lib/time-picker/time-picker.common.ts | 9 +- .../time-picker/time-picker.component.html | 4 +- .../time-picker/time-picker.component.spec.ts | 68 +++---- .../lib/time-picker/time-picker.component.ts | 181 ++++++++++++------ .../lib/time-picker/time-picker.directives.ts | 44 ++--- .../src/lib/time-picker/time-picker.pipes.ts | 48 ++++- src/app/time-picker/time-picker.sample.html | 18 +- 9 files changed, 240 insertions(+), 140 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-component.scss index 9026201b156..207d663261c 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-component.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-component.scss @@ -47,9 +47,9 @@ @extend %time-picker__minuteList !optional; } - // SECOND - @include e(secondList) { - @extend %time-picker__secondList !optional; + // SECONDS + @include e(secondsList) { + @extend %time-picker__secondsList !optional; } // AM PM diff --git a/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-theme.scss index 486154759d7..74cf18782fb 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/time-picker/_time-picker-theme.scss @@ -187,7 +187,7 @@ text-align: center; } - %time-picker__secondList { + %time-picker__secondsList { text-align: center; } diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts index 025c63f29fe..d92f5da0596 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts @@ -8,11 +8,11 @@ export const IGX_TIME_PICKER_COMPONENT = 'IgxTimePickerComponentToken'; export interface IgxTimePickerBase { hourList: ElementRef; minuteList: ElementRef; - secondList: ElementRef; + secondsList: ElementRef; ampmList: ElementRef; selectedHour: string; selectedMinute: string; - selectedSecond: string; + selectedSeconds: string; selectedAmPm: string; format: string; promptChar: string; @@ -26,14 +26,15 @@ export interface IgxTimePickerBase { prevHour(); nextMinute(); prevMinute(); - nextSecond(); - prevSecond(); + nextSeconds(); + prevSeconds(); nextAmPm(); prevAmPm(); okButtonClick(): boolean; cancelButtonClick(): void; scrollHourIntoView(item: string): void; scrollMinuteIntoView(item: string): void; + scrollSecondsIntoView(item: string): void; scrollAmPmIntoView(item: string): void; close(): void; parseMask(preserveAmPm?: boolean): string; diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html index 2f983cb73e4..21d84957822 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html @@ -50,8 +50,8 @@

{{ minute }}
-
- {{ second }} +
+ {{ seconds }}
{{ ampm }} diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts index 6efeecdc308..cff4422515d 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts @@ -124,19 +124,19 @@ describe('IgxTimePicker', () => { const expectedColumnElements = 7; const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')).nativeElement.children; const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')).nativeElement.children; - const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')).nativeElement.children; + const secondsColumn: any = dom.query(By.css('.igx-time-picker__secondsList')).nativeElement.children; const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')).nativeElement.children; // check element count expect(hourColumn.length).toBe(expectedColumnElements); expect(minuteColumn.length).toBe(expectedColumnElements); - expect(secondColumn.length).toBe(expectedColumnElements); + expect(secondsColumn.length).toBe(expectedColumnElements); expect(AMPMColumn.length).toBe(expectedColumnElements); // verify selected's position to be in the middle expect(hourColumn[3].classList).toContain('igx-time-picker__item--selected'); expect(minuteColumn[3].classList).toContain('igx-time-picker__item--selected'); - expect(secondColumn[3].classList).toContain('igx-time-picker__item--selected'); + expect(secondsColumn[3].classList).toContain('igx-time-picker__item--selected'); expect(AMPMColumn[3].classList).toContain('igx-time-picker__item--selected'); })); @@ -176,7 +176,7 @@ describe('IgxTimePicker', () => { const selectHour = hourColumn.children[middlePos - 3]; const minutesColumn = dom.query(By.css('.igx-time-picker__minuteList')); const selectMinutes = minutesColumn.children[middlePos - 3]; - const secondsColumn = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn = dom.query(By.css('.igx-time-picker__secondsList')); const selectSeconds = secondsColumn.children[middlePos - 3]; UIInteractions.clickElement(selectHour); @@ -223,7 +223,7 @@ describe('IgxTimePicker', () => { const selectHour = hourColumn.children[middlePos + 2]; const minutesColumn = dom.query(By.css('.igx-time-picker__minuteList')); const selectMinutes = minutesColumn.children[middlePos - 3]; - const secondsColumn = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn = dom.query(By.css('.igx-time-picker__secondsList')); const selectSeconds = secondsColumn.children[middlePos - 3]; UIInteractions.clickElement(selectHour); @@ -275,9 +275,9 @@ describe('IgxTimePicker', () => { const selectMinutes = minutesColumn.children[2]; const minuteValue = selectMinutes.nativeElement.innerText; - const secondsColumn = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn = dom.query(By.css('.igx-time-picker__secondsList')); const selectSeconds = secondsColumn.children[2]; - const secondValue = selectSeconds.nativeElement.innerText; + const secondsValue = selectSeconds.nativeElement.innerText; const AMPMColumn = dom.query(By.css('.igx-time-picker__ampmList')); const selectAMPM = AMPMColumn.children[4]; @@ -306,7 +306,7 @@ describe('IgxTimePicker', () => { expect(timePicker.onValueChanged.emit).toHaveBeenCalled(); const valueFromInput = dom.query(By.directive(IgxInputDirective)).nativeElement.value; - const selectedTime = `${hourValue}:${minuteValue}:${secondValue} ${aMPMValue}`; + const selectedTime = `${hourValue}:${minuteValue}:${secondsValue} ${aMPMValue}`; expect(valueFromInput).toEqual(selectedTime); })); @@ -324,7 +324,7 @@ describe('IgxTimePicker', () => { const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); - const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn: any = dom.query(By.css('.igx-time-picker__secondsList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); hourColumn.nativeElement.focus(); @@ -357,20 +357,20 @@ describe('IgxTimePicker', () => { minuteColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); fixture.detectChanges(); - secondColumn.nativeElement.focus(); + secondsColumn.nativeElement.focus(); fixture.detectChanges(); // move arrows several times with minute column args = { key: 'ArrowDown', bubbles: true }; - secondColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + secondsColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); fixture.detectChanges(); args = { key: 'ArrowUp', bubbles: true }; - secondColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + secondsColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); fixture.detectChanges(); args = { key: 'ArrowDown', bubbles: true }; - secondColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + secondsColumn.nativeElement.dispatchEvent(new KeyboardEvent('keydown', args)); fixture.detectChanges(); AMPMColumn.nativeElement.focus(); @@ -474,7 +474,7 @@ describe('IgxTimePicker', () => { // const timePicker = fixture.componentInstance.timePicker; const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); - const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn: any = dom.query(By.css('.igx-time-picker__secondsList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); hourColumn.triggerEventHandler('focus', {}); @@ -488,9 +488,9 @@ describe('IgxTimePicker', () => { fixture.detectChanges(); expect(document.activeElement.classList).toContain('igx-time-picker__minuteList'); - secondColumn.triggerEventHandler('mouseover', {}); + secondsColumn.triggerEventHandler('mouseover', {}); fixture.detectChanges(); - expect(document.activeElement.classList).toContain('igx-time-picker__secondList'); + expect(document.activeElement.classList).toContain('igx-time-picker__secondsList'); AMPMColumn.triggerEventHandler('mouseover', {}); fixture.detectChanges(); @@ -511,7 +511,7 @@ describe('IgxTimePicker', () => { // const timePicker = fixture.componentInstance.timePicker; const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); - const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn: any = dom.query(By.css('.igx-time-picker__secondsList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); let event = new WheelEvent('wheel', { deltaX: 0, deltaY: 0 }); @@ -556,22 +556,22 @@ describe('IgxTimePicker', () => { expect(minuteColumn.nativeElement.children[3].innerText).toBe('24'); // focus seconds - secondColumn.nativeElement.focus(); + secondsColumn.nativeElement.focus(); fixture.detectChanges(); event = new WheelEvent('wheel', { deltaX: 0, deltaY: -100 }); - secondColumn.triggerEventHandler('wheel', event); + secondsColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); // move the mouse wheel up and expect the selected element to be 23 - expect(secondColumn.nativeElement.children[3].innerText).toBe('25'); + expect(secondsColumn.nativeElement.children[3].innerText).toBe('25'); event = new WheelEvent('wheel', { deltaX: 0, deltaY: 100 }); - secondColumn.triggerEventHandler('wheel', event); + secondsColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); // move the mouse wheel down and expect the selected element to be 24 again - expect(secondColumn.nativeElement.children[3].innerText).toBe('26'); + expect(secondsColumn.nativeElement.children[3].innerText).toBe('26'); // focus ampm AMPMColumn.nativeElement.focus(); @@ -606,7 +606,7 @@ describe('IgxTimePicker', () => { // const timePicker = fixture.componentInstance.timePicker; const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); - const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn: any = dom.query(By.css('.igx-time-picker__secondsList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); // panmove is in reverse direction of mouse wheel @@ -650,20 +650,20 @@ describe('IgxTimePicker', () => { expect(minuteColumn.nativeElement.children[3].innerText).toBe('24'); // focus minutes - secondColumn.nativeElement.focus(); + secondsColumn.nativeElement.focus(); fixture.detectChanges(); - secondColumn.triggerEventHandler('panmove', eventDown); + secondsColumn.triggerEventHandler('panmove', eventDown); fixture.detectChanges(); // swipe up and expect the selected element to be 25 - expect(secondColumn.nativeElement.children[3].innerText).toBe('26'); + expect(secondsColumn.nativeElement.children[3].innerText).toBe('26'); - secondColumn.triggerEventHandler('panmove', eventUp); + secondsColumn.triggerEventHandler('panmove', eventUp); fixture.detectChanges(); // swipe down and expect the selected element to be 24 again - expect(secondColumn.nativeElement.children[3].innerText).toBe('27'); + expect(secondsColumn.nativeElement.children[3].innerText).toBe('27'); // focus ampm AMPMColumn.nativeElement.focus(); @@ -738,7 +738,7 @@ describe('IgxTimePicker', () => { const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); - const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn: any = dom.query(By.css('.igx-time-picker__secondsList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); hourColumn.nativeElement.focus(); @@ -757,10 +757,10 @@ describe('IgxTimePicker', () => { minuteColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); - secondColumn.nativeElement.focus(); + secondsColumn.nativeElement.focus(); fixture.detectChanges(); - secondColumn.triggerEventHandler('wheel', event); + secondsColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); AMPMColumn.nativeElement.focus(); @@ -800,7 +800,7 @@ describe('IgxTimePicker', () => { const hourColumn: any = dom.query(By.css('.igx-time-picker__hourList')); const minuteColumn: any = dom.query(By.css('.igx-time-picker__minuteList')); - const secondColumn: any = dom.query(By.css('.igx-time-picker__secondList')); + const secondsColumn: any = dom.query(By.css('.igx-time-picker__secondsList')); const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList')); const event = new WheelEvent('wheel', { deltaX: 0, deltaY: 100 }); @@ -819,10 +819,10 @@ describe('IgxTimePicker', () => { minuteColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); - secondColumn.nativeElement.focus(); + secondsColumn.nativeElement.focus(); fixture.detectChanges(); - secondColumn.triggerEventHandler('wheel', event); + secondsColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); AMPMColumn.nativeElement.focus(); diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts index 04a8a8ddbfe..d60f3ad7531 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts @@ -27,7 +27,7 @@ import { IgxAmPmItemDirective, IgxHourItemDirective, IgxMinuteItemDirective, - IgxSecondItemDirective, + IgxSecondsItemDirective, IgxItemListDirective, IgxTimePickerTemplateDirective, IgxTimePickerActionsDirective @@ -53,7 +53,8 @@ let NEXT_ID = 0; const HOURS_POS = [0, 1, 2]; const MINUTES_POS = [3, 4, 5]; -const AMPM_POS = [6, 7, 8]; +const SECONDS_POS = [6, 7, 8]; +const AMPM_POS = [9, 10, 11]; const ITEMS_COUNT = 7; @@ -238,13 +239,19 @@ export class IgxTimePickerComponent implements /** * An @Input property that gets/sets the delta by which hour and minute items would be changed
* when the user presses the Up/Down keys. - * By default `itemsDelta` is set to `{hours: 1, minutes:1}` + * By default `itemsDelta` is set to `{hours: 1, minutes: 1, seconds: 1}` * ```html - * + * *``` */ @Input() - public itemsDelta = { hours: 1, minutes: 1, seconds: 1 }; + set itemsDelta(value) { + this._itemsDelta = { hours: 1, minutes: 1, seconds: 1, ...value }; + } + + get itemsDelta(): { hours: number, minutes: number, seconds: number } { + return this._itemsDelta; + } /** * An @Input property that allows you to set the `minValue` to limit the user input. @@ -270,7 +277,7 @@ export class IgxTimePickerComponent implements /** * 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. + *The seconds and minutes and hour spinning will wrap around by default. *```html * *``` @@ -297,6 +304,8 @@ export class IgxTimePickerComponent implements * `HH` : hours field in 24-hours format with leading zero
* `m` : minutes field without leading zero
* `mm` : minutes field with leading zero
+ * `s` : seconds field without leading zero
+ * `ss` : seconds field with leading zero
* `tt` : 2 character string which represents AM/PM field
* ```html * @@ -494,8 +503,8 @@ export class IgxTimePickerComponent implements /** * @hidden */ - @ViewChild('secondList', { static: false }) - public secondList: ElementRef; + @ViewChild('secondsList', { static: false }) + public secondsList: ElementRef; /** * @hidden @@ -566,7 +575,7 @@ export class IgxTimePickerComponent implements /** * @hidden */ - public _secondItems = []; + public _secondsItems = []; /** * @hidden @@ -606,7 +615,7 @@ export class IgxTimePickerComponent implements /** * @hidden */ - public selectedSecond: string; + public selectedSeconds: string; /** * @hidden @@ -620,14 +629,15 @@ export class IgxTimePickerComponent implements private _format: string; private _mask: string; private _displayValue: string; + private _itemsDelta: { hours: number, minutes: number, seconds: number } = { hours: 1, minutes: 1, seconds: 1 }; private _isHourListLoop = this.isSpinLoop; private _isMinuteListLoop = this.isSpinLoop; - private _isSecondListLoop = this.isSpinLoop; + private _isSecondsListLoop = this.isSpinLoop; private _hourView = []; private _minuteView = []; - private _secondView = []; + private _secondsView = []; private _ampmView = []; private _dateFromModel: Date; @@ -637,7 +647,7 @@ export class IgxTimePickerComponent implements private _prevSelectedHour: string; private _prevSelectedMinute: string; - private _prevSelectedSecond: string; + private _prevSelectedSeconds: string; private _prevSelectedAmPm: string; private _onOpen = new EventEmitter(); @@ -706,8 +716,8 @@ export class IgxTimePickerComponent implements /** * @hidden */ - get secondView(): string[] { - return this._secondView; + get secondsView(): string[] { + return this._secondsView; } /** @@ -752,6 +762,17 @@ export class IgxTimePickerComponent implements return this.format.indexOf('t') !== - 1; } + /** + * @hidden + */ + get validSecondsEntries(): any[] { + const secondsEntries = []; + for (let i = 0; i < 60; i++) { + secondsEntries.push(i); + } + return secondsEntries; + } + /** * @hidden */ @@ -939,8 +960,14 @@ export class IgxTimePickerComponent implements } else if (viewType && typeof (item) !== 'string') { const leadZeroHour = (item < 10 && (this.format.indexOf('hh') !== -1 || this.format.indexOf('HH') !== -1)); const leadZeroMinute = (item < 10 && this.format.indexOf('mm') !== -1); + const leadZeroSeconds = (item < 10 && this.format.indexOf('ss') !== -1); + + const leadZero = { + hour: leadZeroHour, + minute: leadZeroMinute, + seconds: leadZeroSeconds + }[viewType]; - const leadZero = (viewType === 'hour') ? leadZeroHour : leadZeroMinute; item = (leadZero) ? '0' + item : `${item}`; } return item; @@ -1019,10 +1046,10 @@ export class IgxTimePickerComponent implements return ''; } else { let hour = value.getHours(); - let formattedSecond, formattedMinute, formattedHour; + let formattedSeconds, formattedMinute, formattedHour; const minute = value.getMinutes(); - const second = value.getSeconds(); + const seconds = value.getSeconds(); const amPM = (hour > 11) ? 'PM' : 'AM'; if (format.indexOf('h') !== -1) { @@ -1046,12 +1073,12 @@ export class IgxTimePickerComponent implements formattedMinute = minute < 10 && format.indexOf('mm') !== -1 ? '0' + minute : `${minute}`; - formattedSecond = second < 10 && format.indexOf('ss') !== -1 ? '0' + second : `${second}`; + formattedSeconds = seconds < 10 && format.indexOf('ss') !== -1 ? '0' + seconds : `${seconds}`; return format.replace('hh', formattedHour).replace('h', formattedHour) .replace('HH', formattedHour).replace('H', formattedHour) .replace('mm', formattedMinute).replace('m', formattedMinute) - .replace('ss', formattedSecond).replace('s', formattedSecond) + .replace('ss', formattedSeconds).replace('s', formattedSeconds) .replace('tt', amPM); } } @@ -1064,8 +1091,8 @@ export class IgxTimePickerComponent implements this._minuteView = this._viewToString(this._minuteItems.slice(start, end), 'minute'); } - private _updateSecondView(start: any, end: any): void { - this._secondView = this._viewToString(this._secondItems.slice(start, end), 'second'); + private _updateSecondsView(start: any, end: any): void { + this._secondsView = this._viewToString(this._secondsItems.slice(start, end), 'seconds'); } private _updateAmPmView(start: any, end: any): void { @@ -1124,19 +1151,19 @@ export class IgxTimePickerComponent implements } private _generateSeconds(): void { - const secondItemsCount = 60 / this.itemsDelta.seconds; + const secondsItemsCount = 60 / this.itemsDelta.seconds; - if (secondItemsCount < 7 || !this.isSpinLoop) { - this._addEmptyItems(this._secondItems); - this._isSecondListLoop = false; + if (secondsItemsCount < 7 || !this.isSpinLoop) { + this._addEmptyItems(this._secondsItems); + this._isSecondsListLoop = false; } - for (let i = 0; i < secondItemsCount; i++) { - this._secondItems.push(i * this.itemsDelta.seconds); + for (let i = 0; i < secondsItemsCount; i++) { + this._secondsItems.push(i * this.itemsDelta.seconds); } - if (secondItemsCount < 7 || !this.isSpinLoop) { - this._addEmptyItems(this._secondItems); + if (secondsItemsCount < 7 || !this.isSpinLoop) { + this._addEmptyItems(this._secondsItems); } } @@ -1158,8 +1185,8 @@ export class IgxTimePickerComponent implements if (this.selectedMinute) { date.setMinutes(parseInt(this.selectedMinute, 10)); } - if (this.selectedSecond) { - date.setSeconds(parseInt(this.selectedSecond, 10)); + if (this.selectedSeconds) { + date.setSeconds(parseInt(this.selectedSeconds, 10)); } if (((this.showHoursList && this.selectedHour !== '12') || (!this.showHoursList && this.selectedHour <= '11')) && this.selectedAmPm === 'PM') { @@ -1177,7 +1204,7 @@ export class IgxTimePickerComponent implements private _convertMinMaxValue(value: string): Date { const date = this.value ? new Date(this.value) : this._dateFromModel ? new Date(this._dateFromModel) : new Date(); const sections = value.split(/[\s:]+/); - let hour, minutes, amPM; + let hour, minutes, seconds, amPM; date.setSeconds(0); @@ -1191,6 +1218,11 @@ export class IgxTimePickerComponent implements date.setMinutes(parseInt(minutes, 10)); } + if (this.showSecondsList) { + seconds = sections[sections.length - (this.showAmPmList ? 2 : 1)]; + date.setSeconds(parseInt(seconds, 10)); + } + if (this.showAmPmList) { amPM = sections[sections.length - 1]; @@ -1224,6 +1256,7 @@ export class IgxTimePickerComponent implements private _isEntryValid(val: string): boolean { let validH = true; let validM = true; + let validS = true; const sections = val.split(/[\s:]+/); const re = new RegExp(this.promptChar, 'g'); @@ -1237,7 +1270,12 @@ export class IgxTimePickerComponent implements validM = this.validMinuteEntries.indexOf(parseInt(minutes.replace(re, ''), 10)) !== -1; } - return validH && validM; + if (this.showSecondsList) { + const seconds = sections[sections.length - (this.showAmPmList ? 2 : 1)]; + validS = this.validSecondsEntries.indexOf(parseInt(seconds.replace(re, ''), 10)) !== -1; + } + + return validH && validM && validS; } private _getCursorPosition(): number { @@ -1295,6 +1333,17 @@ export class IgxTimePickerComponent implements return currentVal; } + private _spinSeconds(currentVal: Date, sDelta: number, sign: number) { + let seconds = currentVal.getSeconds() + (sign * sDelta); + + if (seconds < 0 || seconds >= 60) { + seconds = this.isSpinLoop ? seconds - (sign * 60) : currentVal.getSeconds(); + } + + currentVal.setSeconds(seconds); + return currentVal; + } + private _initializeContainer() { if (this.value) { const formttedTime = this._formatTime(this.value, this.format); @@ -1309,7 +1358,7 @@ export class IgxTimePickerComponent implements } if (this.showSecondsList) { - this.selectedSecond = this.showMinutesList ? sections[2] : sections[1]; + this.selectedSeconds = sections[sections.length - (this.showAmPmList ? 2 : 1)]; } if (this.showAmPmList && this._ampmItems !== null) { @@ -1324,8 +1373,8 @@ export class IgxTimePickerComponent implements if (this.selectedMinute === undefined) { this.selectedMinute = !this.showMinutesList && this.value ? this.value.getMinutes().toString() : '0'; } - if (this.selectedSecond === undefined) { - this.selectedSecond = !this.showSecondsList && this.value ? this.value.getSeconds().toString() : '0'; + if (this.selectedSeconds === undefined) { + this.selectedSeconds = !this.showSecondsList && this.value ? this.value.getSeconds().toString() : '0'; } if (this.selectedAmPm === undefined && this._ampmItems !== null) { this.selectedAmPm = this._ampmItems[3]; @@ -1333,14 +1382,14 @@ export class IgxTimePickerComponent implements this._prevSelectedHour = this.selectedHour; this._prevSelectedMinute = this.selectedMinute; - this._prevSelectedSecond = this.selectedSecond; + this._prevSelectedSeconds = this.selectedSeconds; this._prevSelectedAmPm = this.selectedAmPm; this._onTouchedCallback(); this._updateHourView(0, ITEMS_COUNT); this._updateMinuteView(0, ITEMS_COUNT); - this._updateSecondView(0, ITEMS_COUNT); + this._updateSecondsView(0, ITEMS_COUNT); this._updateAmPmView(0, ITEMS_COUNT); if (this.selectedHour) { @@ -1349,8 +1398,8 @@ export class IgxTimePickerComponent implements if (this.selectedMinute) { this.scrollMinuteIntoView(this.selectedMinute); } - if (this.selectedSecond) { - this.scrollSecondIntoView(this.selectedSecond); + if (this.selectedSeconds) { + this.scrollSecondsIntoView(this.selectedSeconds); } if (this.selectedAmPm) { this.scrollAmPmIntoView(this.selectedAmPm); @@ -1361,6 +1410,8 @@ export class IgxTimePickerComponent implements this.hourList.nativeElement.focus(); } else if (this.minuteList) { this.minuteList.nativeElement.focus(); + } else if (this.secondsList) { + this.secondsList.nativeElement.focus(); } }); } @@ -1505,10 +1556,10 @@ export class IgxTimePickerComponent implements } /** - * Scrolls a second item into view. + * Scrolls a seconds item into view. * ```typescript *scrMintoView(picker) { - *picker.scrollSecondIntoView('4'); + *picker.scrollSecondsIntoView('4'); *} * ``` *```html @@ -1516,12 +1567,12 @@ export class IgxTimePickerComponent implements *``` * @param item to be scrolled in view. */ - public scrollSecondIntoView(item: string): void { + public scrollSecondsIntoView(item: string): void { if (this.showSecondsList) { - const secondIntoView = this._scrollItemIntoView(item, this._minuteItems, this.selectedSecond, this._isSecondListLoop, 'second'); - if (secondIntoView) { - this._secondView = secondIntoView.view; - this.selectedSecond = secondIntoView.selectedItem; + const secondsIntoView = this._scrollItemIntoView(item, this._secondsItems, this.selectedSeconds, this._isSecondsListLoop, 'seconds'); + if (secondsIntoView) { + this._secondsView = secondsIntoView.view; + this.selectedSeconds = secondsIntoView.selectedItem; this._updateEditableInput(); } } @@ -1597,10 +1648,10 @@ export class IgxTimePickerComponent implements /** * @hidden */ - public nextSecond() { - const nextSecond = this._nextItem(this._secondItems, this.selectedSecond, this._isSecondListLoop, 'second'); - this._secondView = nextSecond.view; - this.selectedSecond = nextSecond.selectedItem; + public nextSeconds() { + const nextSeconds = this._nextItem(this._secondsItems, this.selectedSeconds, this._isSecondsListLoop, 'seconds'); + this._secondsView = nextSeconds.view; + this.selectedSeconds = nextSeconds.selectedItem; this._updateEditableInput(); } @@ -1608,10 +1659,10 @@ export class IgxTimePickerComponent implements /** * @hidden */ - public prevSecond() { - const prevSecond = this._prevItem(this._secondItems, this.selectedSecond, this._isSecondListLoop, 'second'); - this._secondView = prevSecond.view; - this.selectedSecond = prevSecond.selectedItem; + public prevSeconds() { + const prevSeconds = this._prevItem(this._secondsItems, this.selectedSeconds, this._isSecondsListLoop, 'seconds'); + this._secondsView = prevSeconds.view; + this.selectedSeconds = prevSeconds.selectedItem; this._updateEditableInput(); } @@ -1686,7 +1737,7 @@ export class IgxTimePickerComponent implements this.selectedHour = this._prevSelectedHour; this.selectedMinute = this._prevSelectedMinute; - this.selectedSecond = this._prevSelectedSecond; + this.selectedSeconds = this._prevSelectedSeconds; this.selectedAmPm = this._prevSelectedAmPm; } @@ -1729,7 +1780,7 @@ export class IgxTimePickerComponent implements *``` */ public secondsInView(): string[] { - return this._secondView.filter((second) => second !== ''); + return this._secondsView.filter((seconds) => seconds !== ''); } /** @@ -1899,6 +1950,7 @@ export class IgxTimePickerComponent implements } else { const hDelta = this.itemsDelta.hours * 60 + (sign * this.value.getMinutes()); const mDelta = this.itemsDelta.minutes; + const sDelta = this.itemsDelta.seconds; if (this.showHoursList && HOURS_POS.indexOf(cursor) !== -1) { this.value = this._spinHours(currentVal, min, max, hDelta, sign); @@ -1909,9 +1961,16 @@ export class IgxTimePickerComponent implements this.value = this._spinMinutes(currentVal, mDelta, sign); } - if (this.showAmPmList) { + if (this.showSecondsList) { if (((!this.showHoursList || !this.showMinutesList) && MINUTES_POS.indexOf(cursor) !== -1) || - (this.showHoursList && this.showMinutesList && AMPM_POS.indexOf(cursor) !== -1)) { + (this.showHoursList && this.showMinutesList && SECONDS_POS.indexOf(cursor) !== -1)) { + this.value = this._spinSeconds(currentVal, sDelta, sign); + } + } + + if (this.showAmPmList) { + if (((!this.showHoursList || !this.showMinutesList || !this.showSecondsList) && SECONDS_POS.indexOf(cursor) !== -1) || + (this.showHoursList && this.showMinutesList && this.showSecondsList && AMPM_POS.indexOf(cursor) !== -1)) { const sections = this.displayValue.split(/[\s:]+/); sign = sections[sections.length - 1] === 'AM' ? 1 : -1; @@ -1943,7 +2002,7 @@ export class IgxTimePickerComponent implements IgxTimePickerComponent, IgxHourItemDirective, IgxMinuteItemDirective, - IgxSecondItemDirective, + IgxSecondsItemDirective, IgxItemListDirective, IgxAmPmItemDirective, IgxTimePickerTemplateDirective, diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts index 8ba48d844dc..a5a8bc63530 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts @@ -49,9 +49,9 @@ export class IgxItemListDirective { return this.type === 'minuteList'; } - @HostBinding('class.igx-time-picker__secondList') - get secondCSS(): boolean { - return this.type === 'secondList'; + @HostBinding('class.igx-time-picker__secondsList') + get secondsCSS(): boolean { + return this.type === 'secondsList'; } @HostBinding('class.igx-time-picker__ampmList') @@ -79,8 +79,8 @@ export class IgxItemListDirective { this.timePicker.nextMinute(); break; } - case 'secondList': { - this.timePicker.nextSecond(); + case 'secondsList': { + this.timePicker.nextSeconds(); break; } case 'ampmList': { @@ -100,8 +100,8 @@ export class IgxItemListDirective { this.timePicker.prevMinute(); break; } - case 'secondList': { - this.timePicker.prevSecond(); + case 'secondsList': { + this.timePicker.prevSeconds(); break; } case 'ampmList': { @@ -142,9 +142,9 @@ export class IgxItemListDirective { if (listName.indexOf('hourList') !== -1 && this.timePicker.minuteList) { this.timePicker.minuteList.nativeElement.focus(); - } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.secondList) { - this.timePicker.secondList.nativeElement.focus(); - } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1 || listName.indexOf('secondList') !== -1) && this.timePicker.ampmList) { + } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.secondsList) { + this.timePicker.secondsList.nativeElement.focus(); + } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1 || listName.indexOf('secondsList') !== -1) && this.timePicker.ampmList) { this.timePicker.ampmList.nativeElement.focus(); } } @@ -158,11 +158,11 @@ export class IgxItemListDirective { const listName = (event.target as HTMLElement).className; - if (listName.indexOf('ampmList') !== -1 && this.timePicker.secondList) { - this.timePicker.secondList.nativeElement.focus(); - } else if (listName.indexOf('ampmList') !== -1 || listName.indexOf('secondList') !== -1 && this.timePicker.minuteList) { + if (listName.indexOf('ampmList') !== -1 && this.timePicker.secondsList) { + this.timePicker.secondsList.nativeElement.focus(); + } else if (listName.indexOf('ampmList') !== -1 || listName.indexOf('secondsList') !== -1 && this.timePicker.minuteList) { this.timePicker.minuteList.nativeElement.focus(); - } else if ((listName.indexOf('ampmList') !== -1 || listName.indexOf('secondList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.hourList) { + } else if ((listName.indexOf('ampmList') !== -1 || listName.indexOf('secondsList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.hourList) { this.timePicker.hourList.nativeElement.focus(); } } @@ -315,11 +315,11 @@ export class IgxMinuteItemDirective { * @hidden */ @Directive({ - selector: '[igxSecondItem]' + selector: '[igxSecondsItem]' }) -export class IgxSecondItemDirective { +export class IgxSecondsItemDirective { - @Input('igxSecondItem') + @Input('igxSecondsItem') public value: string; @HostBinding('class.igx-time-picker__item') @@ -329,16 +329,16 @@ export class IgxSecondItemDirective { @HostBinding('class.igx-time-picker__item--selected') get selectedCSS(): boolean { - return this.isSelectedSecond; + return this.isSelectedSeconds; } @HostBinding('class.igx-time-picker__item--active') get activeCSS(): boolean { - return this.isSelectedSecond && this.itemList.isActive; + return this.isSelectedSeconds && this.itemList.isActive; } - get isSelectedSecond(): boolean { - return this.timePicker.selectedSecond === this.value; + get isSelectedSeconds(): boolean { + return this.timePicker.selectedSeconds === this.value; } constructor(@Inject(IGX_TIME_PICKER_COMPONENT) @@ -348,7 +348,7 @@ export class IgxSecondItemDirective { @HostListener('click', ['value']) public onClick(item) { if (item !== '') { - this.timePicker.scrollMinuteIntoView(item); + this.timePicker.scrollSecondsIntoView(item); } } } diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.pipes.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.pipes.ts index b53bf7df655..f7da023140a 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.pipes.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.pipes.ts @@ -12,7 +12,7 @@ export class TimeDisplayFormatPipe implements PipeTransform { constructor(@Inject(IGX_TIME_PICKER_COMPONENT) private timePicker: IgxTimePickerBase) { } transform(value: any): string { - let hour, minutes, amPM; + let hour, minutes, seconds, amPM; const maskAmPM = this.timePicker.parseMask(); const mask = this.timePicker.parseMask(false); @@ -30,6 +30,10 @@ export class TimeDisplayFormatPipe implements PipeTransform { minutes = this.timePicker.showHoursList ? sections[1] : sections[0]; } + if (this.timePicker.showSecondsList) { + seconds = sections[sections.length - (this.timePicker.showAmPmList ? 2 : 1)]; + } + if (this.timePicker.showAmPmList) { amPM = sections[sections.length - 1]; } @@ -46,6 +50,10 @@ export class TimeDisplayFormatPipe implements PipeTransform { minutes = minutes === prompt + prompt ? '00' : minutes.replace(regExp, '0'); } + if (format.indexOf('ss') !== -1 && seconds.indexOf(prompt) !== -1) { + seconds = seconds === prompt + prompt ? '00' : seconds.replace(regExp, '0'); + } + if (format.indexOf('hh') === -1 && format.indexOf('HH') === -1 && hour !== undefined) { hour = hour.indexOf(prompt) !== -1 ? hour.replace(regExp, '') : hour; const hourVal = parseInt(hour, 10); @@ -58,11 +66,17 @@ export class TimeDisplayFormatPipe implements PipeTransform { minutes = !minutesVal ? '0' : minutesVal < 10 && minutesVal !== 0 ? minutes.replace('0', '') : minutes; } + if (format.indexOf('ss') === -1 && seconds !== undefined) { + seconds = seconds.indexOf(prompt) !== -1 ? seconds.replace(regExp, '') : seconds; + const secondsVal = parseInt(seconds, 10); + seconds = !secondsVal ? '0' : secondsVal < 10 && secondsVal !== 0 ? seconds.replace('0', '') : seconds; + } + if (format.indexOf('tt') !== -1 && (amPM !== 'AM' || amPM !== 'PM')) { amPM = amPM.indexOf('p') !== -1 || amPM.indexOf('P') !== -1 ? 'PM' : 'AM'; } - let result = amPM ? `${hour}:${minutes} ${amPM}` : `${hour}:${minutes}`; + let result = amPM ? `${hour}:${minutes}:${seconds} ${amPM}` : `${hour}:${minutes}:${seconds}`; if (!hour) { result = result.slice(result.indexOf(':') + 1, result.length); @@ -70,6 +84,15 @@ export class TimeDisplayFormatPipe implements PipeTransform { if (!minutes) { result = result.slice(0, result.indexOf(':')); + + if (seconds) { + result = result + ':' + seconds; + } + } + + if (!seconds) { + result = result.slice(0, result.lastIndexOf(':')); + if (amPM) { result = result + ' ' + amPM; } } @@ -90,7 +113,7 @@ export class TimeInputFormatPipe implements PipeTransform { const prompt = this.timePicker.promptChar; const regExp = new RegExp(prompt, 'g'); - let mask, hour, minutes, amPM; + let mask, hour, minutes, seconds, amPM; if (this.timePicker.cleared) { this.timePicker.cleared = false; @@ -121,11 +144,19 @@ export class TimeInputFormatPipe implements PipeTransform { minutes = leadZeroMinutes ? '0' + minutes : minutes; } + if (this.timePicker.showSecondsList) { + seconds = sections[sections.length - (this.timePicker.showAmPmList ? 2 : 1)]; + seconds = seconds.replace(regExp, ''); + + const leadZeroSeconds = (parseInt(seconds, 10) < 10 && !seconds.startsWith('0')) || seconds === '0'; + seconds = leadZeroSeconds ? '0' + seconds : seconds; + } + if (this.timePicker.showAmPmList) { amPM = sections[sections.length - 1]; } - let result = amPM ? `${hour}:${minutes} ${amPM}` : `${hour}:${minutes}`; + let result = amPM ? `${hour}:${minutes}:${seconds} ${amPM}` : `${hour}:${minutes}:${seconds}`; if (!hour) { result = result.slice(result.indexOf(':') + 1, result.length); @@ -133,6 +164,15 @@ export class TimeInputFormatPipe implements PipeTransform { if (!minutes) { result = result.slice(0, result.indexOf(':')); + + if (seconds) { + result = result + ':' + seconds; + } + } + + if (!seconds) { + result = result.slice(0, result.lastIndexOf(':')); + if (amPM) { result = result + ' ' + amPM; } } diff --git a/src/app/time-picker/time-picker.sample.html b/src/app/time-picker/time-picker.sample.html index 01cafbbcc87..8113843a4dd 100644 --- a/src/app/time-picker/time-picker.sample.html +++ b/src/app/time-picker/time-picker.sample.html @@ -13,15 +13,15 @@

Time Picker with Dropdown

-
-

Time Picker with Dropdown Hour Mode

-
{{showDate(date1)}}
-
Mask: {{hourModeTimePicker.mask}}, Format: {{hourModeTimePicker.format}}
-
- - -
-
+
+

Time Picker with Dropdown Hour Mode

+
{{showDate(date1)}}
+
Mask: {{hourModeTimePicker.mask}}, Format: {{hourModeTimePicker.format}}
+
+ + +
+

Horizontal Time Picker

AM/PM Time format

From 9f4b39a43a1eb374289a28bef2c3516c1e6632ba Mon Sep 17 00:00:00 2001 From: Boris Date: Fri, 6 Dec 2019 10:18:32 +0200 Subject: [PATCH 4/9] refactor(time-picker): dynamically generate possible cursor positions - trim mask with included seconds - add seconds to header --- .../time-picker/time-picker.component.html | 6 +- .../lib/time-picker/time-picker.component.ts | 109 +++++++++++++----- .../lib/time-picker/time-picker.directives.ts | 12 +- .../src/lib/time-picker/time-picker.pipes.ts | 64 +++++----- 4 files changed, 123 insertions(+), 68 deletions(-) diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html index 21d84957822..d5cf9dbfa07 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.html @@ -39,7 +39,7 @@
{{ selectedAmPm }}

- {{ selectedHour }}:{{ selectedMinute }} + {{ selectedHour }}:{{ selectedMinute }}:{{ selectedSeconds }}

@@ -57,6 +57,8 @@

{{ ampm }}

- + + diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts index 06b9e6576fd..4792c8f85db 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts @@ -50,12 +50,6 @@ import { InteractionMode } from '../core/enums'; import { DeprecateProperty } from '../core/deprecateDecorators'; let NEXT_ID = 0; - -const HOURS_POS = [0, 1, 2]; -const MINUTES_POS = [3, 4, 5]; -const SECONDS_POS = [6, 7, 8]; -const AMPM_POS = [9, 10, 11]; - const ITEMS_COUNT = 7; @Injectable() @@ -320,13 +314,19 @@ export class IgxTimePickerComponent implements this._format = formatValue; this.mask = this._format.indexOf('tt') !== -1 ? '00:00:00 LL' : '00:00:00'; - if (!this.showHoursList || !this.showMinutesList || !this.showSecondsList) { - this.mask = this.mask.slice(this.mask.indexOf(':') + 1, this.mask.length); + if (!this.showHoursList || !this.showMinutesList) { + this.trimMask(); + } + + if (!this.showSecondsList) { + this.trimMask(); } if (this.displayValue) { this.displayValue = this._formatTime(this.value, this._format); } + + this.determineCursorPos(); } /** @@ -653,9 +653,18 @@ export class IgxTimePickerComponent implements private _onOpen = new EventEmitter(); private _onClose = new EventEmitter(); + private hours_pos = new Set(); + private minutes_pos = new Set(); + private seconds_pos = new Set(); + private ampm_pos = new Set(); + private _onTouchedCallback: () => void = () => { }; private _onChangeCallback: (_: Date) => void = () => { }; + private trimMask(): void { + this.mask = this.mask.slice(this.mask.indexOf(':') + 1, this.mask.length); + } + /** * @hidden */ @@ -890,6 +899,8 @@ export class IgxTimePickerComponent implements this.toggleRef.onClosing.pipe(takeUntil(this._destroy$)).subscribe((event) => { this.onClosing.emit(event); }); + + this.determineCursorPos(); } } @@ -919,6 +930,39 @@ export class IgxTimePickerComponent implements this.openDialog(this.getInputGroupElement()); } + private determineCursorPos(): void { + this.clearCursorPos(); + for (const char of this.format) { + if (char === 'H' || char === 'h') { + this.hours_pos.size === 0 ? this.hours_pos.add(this.format.indexOf(char)) : + this.hours_pos.add(this.format.lastIndexOf(char)); + this.hours_pos.add(this.format.lastIndexOf(char) + 1); + } + if (char === 'M' || char === 'm') { + this.minutes_pos.size === 0 ? this.minutes_pos.add(this.format.indexOf(char)) : + this.minutes_pos.add(this.format.lastIndexOf(char)); + this.minutes_pos.add(this.format.lastIndexOf(char) + 1); + } + if (char === 'S' || char === 's') { + this.seconds_pos.size === 0 ? this.seconds_pos.add(this.format.indexOf(char)) : + this.seconds_pos.add(this.format.lastIndexOf(char)); + this.seconds_pos.add(this.format.lastIndexOf(char) + 1); + } + if (char === 'T' || char === 't') { + this.ampm_pos.size === 0 ? this.ampm_pos.add(this.format.indexOf(char)) : + this.ampm_pos.add(this.format.lastIndexOf(char)); + this.ampm_pos.add(this.format.lastIndexOf(char) + 1); + } + } + } + + private clearCursorPos() { + this.hours_pos.forEach(v => this.hours_pos.delete(v)); + this.minutes_pos.forEach(v => this.minutes_pos.delete(v)); + this.seconds_pos.forEach(v => this.seconds_pos.delete(v)); + this.ampm_pos.forEach(v => this.ampm_pos.delete(v)); + } + private _scrollItemIntoView(item: string, items: any[], selectedItem: string, isListLoop: boolean, viewType: string): any { let itemIntoView; if (items) { @@ -1189,7 +1233,7 @@ export class IgxTimePickerComponent implements date.setSeconds(parseInt(this.selectedSeconds, 10)); } if (((this.showHoursList && this.selectedHour !== '12') || (!this.showHoursList && this.selectedHour <= '11')) && - this.selectedAmPm === 'PM') { + this.selectedAmPm === 'PM') { date.setHours(date.getHours() + 12); } if (!this.showHoursList && this.selectedAmPm === 'AM' && this.selectedHour > '11') { @@ -1227,8 +1271,8 @@ export class IgxTimePickerComponent implements amPM = sections[sections.length - 1]; if (((this.showHoursList && date.getHours().toString() !== '12') || - (!this.showHoursList && date.getHours().toString() <= '11')) && amPM === 'PM') { - date.setHours(date.getHours() + 12); + (!this.showHoursList && date.getHours().toString() <= '11')) && amPM === 'PM') { + date.setHours(date.getHours() + 12); } if (!this.showHoursList && amPM === 'AM' && date.getHours().toString() > '11') { @@ -1569,7 +1613,8 @@ export class IgxTimePickerComponent implements */ public scrollSecondsIntoView(item: string): void { if (this.showSecondsList) { - const secondsIntoView = this._scrollItemIntoView(item, this._secondsItems, this.selectedSeconds, this._isSecondsListLoop, 'seconds'); + const secondsIntoView = this._scrollItemIntoView(item, + this._secondsItems, this.selectedSeconds, this._isSecondsListLoop, 'seconds'); if (secondsIntoView) { this._secondsView = secondsIntoView.view; this.selectedSeconds = secondsIntoView.selectedItem; @@ -1952,32 +1997,32 @@ export class IgxTimePickerComponent implements const mDelta = this.itemsDelta.minutes; const sDelta = this.itemsDelta.seconds; - if (this.showHoursList && HOURS_POS.indexOf(cursor) !== -1) { + if (this.showHoursList && this.hours_pos.has(cursor)) { this.value = this._spinHours(currentVal, min, max, hDelta, sign); } if (this.showMinutesList && - ((this.showHoursList && MINUTES_POS.indexOf(cursor) !== -1) || (!this.showHoursList && HOURS_POS.indexOf(cursor) !== -1))) { - this.value = this._spinMinutes(currentVal, mDelta, sign); + ((this.showHoursList && this.minutes_pos.has(cursor)) || + (!this.showHoursList && this.minutes_pos.has(cursor)))) { + this.value = this._spinMinutes(currentVal, mDelta, sign); } - if (this.showSecondsList) { - if (((!this.showHoursList || !this.showMinutesList) && MINUTES_POS.indexOf(cursor) !== -1) || - (this.showHoursList && this.showMinutesList && SECONDS_POS.indexOf(cursor) !== -1)) { - this.value = this._spinSeconds(currentVal, sDelta, sign); - } + if (this.showSecondsList && + (this.showHoursList && this.showMinutesList && this.seconds_pos.has(cursor)) || + ((!this.showHoursList || !this.showMinutesList) && this.seconds_pos.has(cursor)) || + (!this.showHoursList && !this.showMinutesList && this.seconds_pos.has(cursor))) { + this.value = this._spinSeconds(currentVal, sDelta, sign); } - if (this.showAmPmList) { - if (((!this.showHoursList || !this.showMinutesList || !this.showSecondsList) && SECONDS_POS.indexOf(cursor) !== -1) || - (this.showHoursList && this.showMinutesList && this.showSecondsList && AMPM_POS.indexOf(cursor) !== -1)) { - - const sections = this.displayValue.split(/[\s:]+/); - sign = sections[sections.length - 1] === 'AM' ? 1 : -1; - currentVal.setHours(currentVal.getHours() + (sign * 12)); + if (this.showAmPmList && + (this.showHoursList && this.showMinutesList && this.showSecondsList && this.ampm_pos.has(cursor)) || + ((!this.showHoursList || !this.showMinutesList || !this.showSecondsList) && this.ampm_pos.has(cursor)) || + (this.determineFormatParts() && this.ampm_pos.has(cursor))) { + const sections = this.displayValue.split(/[\s:]+/); + sign = sections[sections.length - 1] === 'AM' ? 1 : -1; + currentVal.setHours(currentVal.getHours() + (sign * 12)); - this.value = currentVal; - } + this.value = currentVal; } displayVal = this._formatTime(this.value, this.format); @@ -1992,6 +2037,12 @@ export class IgxTimePickerComponent implements this._setCursorPosition(cursor); }); } + + private determineFormatParts(): boolean { + return (this.showHoursList && (!this.showMinutesList || !this.showSecondsList)) || + (this.showMinutesList && (!this.showHoursList || !this.showSecondsList)) || + (this.showSecondsList && (!this.showHoursList || !this.showMinutesList)); + } } /** diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts index a5a8bc63530..de7dc0cfff9 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.directives.ts @@ -144,7 +144,8 @@ export class IgxItemListDirective { this.timePicker.minuteList.nativeElement.focus(); } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.secondsList) { this.timePicker.secondsList.nativeElement.focus(); - } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1 || listName.indexOf('secondsList') !== -1) && this.timePicker.ampmList) { + } else if ((listName.indexOf('hourList') !== -1 || listName.indexOf('minuteList') !== -1 || + listName.indexOf('secondsList') !== -1) && this.timePicker.ampmList) { this.timePicker.ampmList.nativeElement.focus(); } } @@ -155,14 +156,17 @@ export class IgxItemListDirective { @HostListener('keydown.arrowleft', ['$event']) public onKeydownArrowLeft(event: KeyboardEvent) { event.preventDefault(); - const listName = (event.target as HTMLElement).className; if (listName.indexOf('ampmList') !== -1 && this.timePicker.secondsList) { this.timePicker.secondsList.nativeElement.focus(); - } else if (listName.indexOf('ampmList') !== -1 || listName.indexOf('secondsList') !== -1 && this.timePicker.minuteList) { + } else if (listName.indexOf('secondsList') !== -1 && this.timePicker.secondsList + && listName.indexOf('minutesList') && this.timePicker.minuteList) { + this.timePicker.minuteList.nativeElement.focus(); + } else if (listName.indexOf('ampmList') !== -1 && this.timePicker.minuteList) { this.timePicker.minuteList.nativeElement.focus(); - } else if ((listName.indexOf('ampmList') !== -1 || listName.indexOf('secondsList') !== -1 || listName.indexOf('minuteList') !== -1) && this.timePicker.hourList) { + } else if ((listName.indexOf('ampmList') !== -1 || listName.indexOf('secondsList') !== -1 || + listName.indexOf('minuteList') !== -1) && this.timePicker.hourList) { this.timePicker.hourList.nativeElement.focus(); } } diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.pipes.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.pipes.ts index f7da023140a..11fb564d32f 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.pipes.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.pipes.ts @@ -1,4 +1,4 @@ -import { Pipe, PipeTransform, Inject} from '@angular/core'; +import { Pipe, PipeTransform, Inject } from '@angular/core'; import { IGX_TIME_PICKER_COMPONENT, IgxTimePickerBase } from './time-picker.common'; @@ -6,12 +6,11 @@ import { IGX_TIME_PICKER_COMPONENT, IgxTimePickerBase } from './time-picker.comm * Formats `IgxTimePickerComponent` display value according to the `format` property, * when the input element loses focus. **/ -@Pipe({ name: 'displayFormat'}) +@Pipe({ name: 'displayFormat' }) export class TimeDisplayFormatPipe implements PipeTransform { + constructor(@Inject(IGX_TIME_PICKER_COMPONENT) private timePicker: IgxTimePickerBase) { } - constructor(@Inject(IGX_TIME_PICKER_COMPONENT) private timePicker: IgxTimePickerBase) { } - - transform(value: any): string { + transform(value: any): string { let hour, minutes, seconds, amPM; const maskAmPM = this.timePicker.parseMask(); @@ -43,11 +42,11 @@ export class TimeDisplayFormatPipe implements PipeTransform { const regExp = new RegExp(this.timePicker.promptChar, 'g'); if (format.indexOf('hh') !== -1 || format.indexOf('HH') !== -1 && hour.indexOf(prompt) !== -1) { - hour = hour === prompt + prompt ? '00' : hour.replace(regExp, '0'); + hour = hour === prompt + prompt ? '00' : hour.replace(regExp, '0'); } if (format.indexOf('mm') !== -1 && minutes.indexOf(prompt) !== -1) { - minutes = minutes === prompt + prompt ? '00' : minutes.replace(regExp, '0'); + minutes = minutes === prompt + prompt ? '00' : minutes.replace(regExp, '0'); } if (format.indexOf('ss') !== -1 && seconds.indexOf(prompt) !== -1) { @@ -73,30 +72,30 @@ export class TimeDisplayFormatPipe implements PipeTransform { } if (format.indexOf('tt') !== -1 && (amPM !== 'AM' || amPM !== 'PM')) { - amPM = amPM.indexOf('p') !== -1 || amPM.indexOf('P') !== -1 ? 'PM' : 'AM'; + amPM = amPM.indexOf('p') !== -1 || amPM.indexOf('P') !== -1 ? 'PM' : 'AM'; } - let result = amPM ? `${hour}:${minutes}:${seconds} ${amPM}` : `${hour}:${minutes}:${seconds}`; - + let result = `${hour}:${minutes}:${seconds}`; if (!hour) { - result = result.slice(result.indexOf(':') + 1, result.length); + // remove the hours + result = result.slice(result.indexOf(':') + 1); } - if (!minutes) { - result = result.slice(0, result.indexOf(':')); - - if (seconds) { - result = result + ':' + seconds; + if (hour) { + // get the hours and seconds and concat them + result = result.slice(0, result.indexOf(':')) + + result.slice(result.lastIndexOf(':'), result.length); + } else { + // remove the minutes + result = result.slice(result.indexOf(':') + 1); } } - if (!seconds) { + // remove the seconds result = result.slice(0, result.lastIndexOf(':')); - - if (amPM) { result = result + ' ' + amPM; } } - return result; + return amPM ? `${result} ${amPM}` : result; } } @@ -106,7 +105,6 @@ export class TimeDisplayFormatPipe implements PipeTransform { **/ @Pipe({ name: 'inputFormat' }) export class TimeInputFormatPipe implements PipeTransform { - constructor(@Inject(IGX_TIME_PICKER_COMPONENT) private timePicker: IgxTimePickerBase) { } transform(value: any): string { @@ -156,26 +154,26 @@ export class TimeInputFormatPipe implements PipeTransform { amPM = sections[sections.length - 1]; } - let result = amPM ? `${hour}:${minutes}:${seconds} ${amPM}` : `${hour}:${minutes}:${seconds}`; - + let result = `${hour}:${minutes}:${seconds}`; if (!hour) { - result = result.slice(result.indexOf(':') + 1, result.length); + // remove the hours + result = result.slice(result.indexOf(':') + 1); } - if (!minutes) { - result = result.slice(0, result.indexOf(':')); - - if (seconds) { - result = result + ':' + seconds; + if (hour) { + // get the hours and seconds and concat them + result = result.slice(0, result.indexOf(':')) + + result.slice(result.lastIndexOf(':'), result.length); + } else { + // remove the minutes + result = result.slice(result.indexOf(':') + 1); } } - if (!seconds) { + // remove the seconds result = result.slice(0, result.lastIndexOf(':')); - - if (amPM) { result = result + ' ' + amPM; } } - return result; + return amPM ? `${result} ${amPM}` : result; } } From 1c042dfe57d5526d0c576dcddb914e5dd5ba8c8b Mon Sep 17 00:00:00 2001 From: Boris Date: Fri, 6 Dec 2019 11:08:22 +0200 Subject: [PATCH 5/9] refactor(time-picker): update test components to work with seconds feature --- .../time-picker/time-picker.component.spec.ts | 195 +++++++++--------- 1 file changed, 100 insertions(+), 95 deletions(-) diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts index baf482b1ee2..525fbf90b87 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.spec.ts @@ -1,4 +1,4 @@ -import { Component, ViewChild } from '@angular/core'; +import { Component, ViewChild, NgModule } from '@angular/core'; import { async, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; @@ -10,36 +10,14 @@ import { IgxInputGroupModule } from '../input-group'; import { configureTestSuite } from '../test-utils/configure-suite'; import { InteractionMode } from '../core/enums'; import { IgxIconModule } from '../icon'; -import { IgxOverlayOutletDirective, IgxToggleModule } from '../directives/toggle/toggle.directive'; +import { IgxToggleModule } from '../directives/toggle/toggle.directive'; +// tslint:disable: no-use-before-declare describe('IgxTimePicker', () => { configureTestSuite(); beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ - IgxTimePickerTestComponent, - IgxTimePickerWithPassedTimeComponent, - IgxTimePickerWithPmTimeComponent, - IgxTimePickerWithMInMaxTimeValueComponent, - IgxTimePickerWith24HTimeComponent, - IgxTimePickerWithAMPMLeadingZerosTimeComponent, - IgxTimePickerWithSpinLoopFalseValueComponent, - IgxTimePickerWithItemsDeltaValueComponent, - IgxTimePickerRetemplatedComponent, - IgxTimePickerDropDownComponent, - IgxTimePickerDropDownSingleHourComponent, - IgxTimePickerDropDownNoValueComponent, - IgxTimePickerRetemplatedDropDownComponent, - IgxTimePickerWithOutletComponent - ], - imports: [ - IgxTimePickerModule, - FormsModule, - NoopAnimationsModule, - IgxInputGroupModule, - IgxIconModule, - IgxToggleModule - ] + imports: [IgxTimePickerTestingModule] }).compileComponents(); })); @@ -71,15 +49,16 @@ describe('IgxTimePicker', () => { fixture.detectChanges(); const timePicker = fixture.componentInstance.timePicker; - expect(timePicker.value).toEqual(new Date(2017, 7, 7, 3, 24)); + expect(timePicker.value).toEqual(new Date(2017, 7, 7, 3, 24, 17)); })); it('TimePicker DOM input value', (() => { const fixture = TestBed.createComponent(IgxTimePickerWithPassedTimeComponent); fixture.detectChanges(); - const currentTime = new Date(2017, 7, 7, 3, 24); - const formattedTime = `${currentTime.getHours()}:${currentTime.getMinutes()} ${currentTime.getHours() > 12 ? 'PM' : 'AM'}`; + const currentTime = new Date(2017, 7, 7, 3, 24, 17); + const formattedTime = `${currentTime.getHours()}:${currentTime.getMinutes()}:` + + `${currentTime.getSeconds()} ${currentTime.getHours() > 12 ? 'PM' : 'AM'}`; const dom = fixture.debugElement; @@ -94,9 +73,9 @@ describe('IgxTimePicker', () => { const dom = fixture.debugElement; // get time-picker value - const testElementTIme = fixture.componentInstance.dateValue; - const formatedTestElementTime = - `${testElementTIme.getHours()}:${testElementTIme.getMinutes()} ${testElementTIme.getHours() >= 12 ? 'PM' : 'AM'}`; + const testElementTime = fixture.componentInstance.dateValue; + const formattedTestElementTime = `${testElementTime.getHours()}:${testElementTime.getMinutes()}` + + `:${testElementTime.getSeconds()} ${testElementTime.getHours() >= 12 ? 'PM' : 'AM'}`; const timePickerTarget = dom.query(By.directive(IgxInputDirective)); UIInteractions.clickElement(timePickerTarget); @@ -108,7 +87,7 @@ describe('IgxTimePicker', () => { const formatedTimeFromPopupHeader = `${timeFromPopupHeader[1].innerText.replace(/\n/g, '')} ${timeFromPopupHeader[0].innerText}`; - expect(formatedTimeFromPopupHeader).toBe(formatedTestElementTime); + expect(formatedTimeFromPopupHeader).toBe(formattedTestElementTime); })); it('Dialog selected element position', fakeAsync(() => { @@ -387,6 +366,7 @@ describe('IgxTimePicker', () => { // get time from dialog header const timeFromPopupHeader: any = dom.query(By.css('.igx-time-picker__header')).nativeElement.children; const formatedTimeFromPopupHeader = + // tslint:disable-next-line: max-line-length `${timeFromPopupHeader[1].innerText.replace(/\n/g, '')} ${timeFromPopupHeader[0].innerText}`; args = { key: 'Enter', bubbles: true }; @@ -401,11 +381,9 @@ describe('IgxTimePicker', () => { it('TimePicker Left Right Keyboard navigation', fakeAsync(() => { const fixture = TestBed.createComponent(IgxTimePickerWithPassedTimeComponent); fixture.detectChanges(); - const dom = fixture.debugElement; const initialTime = dom.query(By.directive(IgxInputDirective)).nativeElement.value; - let args = { key: 'ArrowRight', bubbles: true }; const timePickerTarget = dom.query(By.directive(IgxInputDirective)); UIInteractions.clickElement(timePickerTarget); fixture.detectChanges(); @@ -415,45 +393,45 @@ describe('IgxTimePicker', () => { fixture.detectChanges(); expect(document.activeElement.classList).toContain('igx-time-picker__hourList'); - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', document.activeElement, true); fixture.detectChanges(); expect(document.activeElement.classList).toContain('igx-time-picker__minuteList'); - args = { key: 'ArrowLeft', bubbles: true }; - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + UIInteractions.triggerKeyDownEvtUponElem('ArrowLeft', document.activeElement, true); fixture.detectChanges(); - args = { key: 'ArrowRight', bubbles: true }; - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', document.activeElement, true); fixture.detectChanges(); - args = { key: 'ArrowUp', bubbles: true }; - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', document.activeElement, true); fixture.detectChanges(); expect(document.activeElement.children[3].innerHTML.trim()).toBe('23'); - args = { key: 'ArrowRight', bubbles: true }; - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', document.activeElement, true); fixture.detectChanges(); - args = { key: 'ArrowDown', bubbles: true }; - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', document.activeElement, true); + fixture.detectChanges(); + expect(document.activeElement.children[3].innerHTML.trim()).toBe('18'); + + UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', document.activeElement, true); + fixture.detectChanges(); + + UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', document.activeElement, true); fixture.detectChanges(); expect(document.activeElement.children[3].innerHTML.trim()).toBe('PM'); - args = { key: 'ArrowLeft', bubbles: true }; - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + UIInteractions.triggerKeyDownEvtUponElem('ArrowLeft', document.activeElement, true); fixture.detectChanges(); - expect(document.activeElement.classList).toContain('igx-time-picker__minuteList'); + expect(document.activeElement.classList).toContain('igx-time-picker__secondsList'); // get time from dialog header const timeFromPopupHeader: any = dom.query(By.css('.igx-time-picker__header')).nativeElement.children; const formatedTimeFromPopupHeader = `${timeFromPopupHeader[1].innerText.replace(/\n/g, '')} ${timeFromPopupHeader[0].innerText}`; - expect(formatedTimeFromPopupHeader).toBe('3:23 PM'); + expect(formatedTimeFromPopupHeader).toBe('3:23:18 PM'); - args = { key: 'Escape', bubbles: true }; - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', args)); + UIInteractions.triggerKeyDownEvtUponElem('Escape', document.activeElement, true); fixture.detectChanges(); const selectedTime = dom.query(By.directive(IgxInputDirective)).nativeElement.value; @@ -563,15 +541,15 @@ describe('IgxTimePicker', () => { secondsColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); - // move the mouse wheel up and expect the selected element to be 23 - expect(secondsColumn.nativeElement.children[3].innerText).toBe('25'); + // move the mouse wheel up and expect the selected element to be 16 + expect(secondsColumn.nativeElement.children[3].innerText).toBe('16'); event = new WheelEvent('wheel', { deltaX: 0, deltaY: 100 }); secondsColumn.triggerEventHandler('wheel', event); fixture.detectChanges(); - // move the mouse wheel down and expect the selected element to be 24 again - expect(secondsColumn.nativeElement.children[3].innerText).toBe('26'); + // move the mouse wheel down and expect the selected element to be 17 again + expect(secondsColumn.nativeElement.children[3].innerText).toBe('17'); // focus ampm AMPMColumn.nativeElement.focus(); @@ -656,14 +634,14 @@ describe('IgxTimePicker', () => { secondsColumn.triggerEventHandler('panmove', eventDown); fixture.detectChanges(); - // swipe up and expect the selected element to be 25 - expect(secondsColumn.nativeElement.children[3].innerText).toBe('26'); + // swipe up and expect the selected element to be 18 + expect(secondsColumn.nativeElement.children[3].innerText).toBe('18'); secondsColumn.triggerEventHandler('panmove', eventUp); fixture.detectChanges(); - // swipe down and expect the selected element to be 24 again - expect(secondsColumn.nativeElement.children[3].innerText).toBe('27'); + // swipe down and expect the selected element to be 17 again + expect(secondsColumn.nativeElement.children[3].innerText).toBe('17'); // focus ampm AMPMColumn.nativeElement.focus(); @@ -834,7 +812,7 @@ describe('IgxTimePicker', () => { const timeFromPopupHeader: any = fixture.debugElement.query(By.css('.igx-time-picker__header')).nativeElement.children; const formatedTimeFromPopupHeader = `${timeFromPopupHeader[1].innerText.replace(/\n/g, '')} ${timeFromPopupHeader[0].innerText}`; - expect(formatedTimeFromPopupHeader).toBe('12:58 PM'); + expect(formatedTimeFromPopupHeader).toBe('12:58:13 PM'); expect(console.error).not.toHaveBeenCalled(); })); @@ -1678,7 +1656,7 @@ describe('IgxTimePicker', () => { UIInteractions.clearOverlay(); })); - it('Should render dropdown and input group correctly when format conatains only hours.', fakeAsync(() => { + it('Should render dropdown and input group correctly when format contains only hours.', fakeAsync(() => { fixture.componentInstance.format = 'hh tt'; fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0); fixture.detectChanges(); @@ -1698,7 +1676,7 @@ describe('IgxTimePicker', () => { expect(minuteColumn).toBeNull(); })); - it('Should mask editable input correctly when format conatains only hours.', fakeAsync(() => { + it('Should mask editable input correctly when format contains only hours.', fakeAsync(() => { fixture.componentInstance.format = 'hh tt'; fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0); fixture.detectChanges(); @@ -1722,9 +1700,9 @@ describe('IgxTimePicker', () => { expect(input.nativeElement.value).toBe('-- AM'); })); - it('Should navigate dropdown lists correctly when format conatains only hours.', fakeAsync(() => { + it('Should navigate dropdown lists correctly when format contains only hours.', fakeAsync(() => { fixture.componentInstance.format = 'hh tt'; - fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0); + fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0); fixture.detectChanges(); const iconTime = dom.queryAll(By.css('.igx-icon'))[0]; @@ -1753,7 +1731,7 @@ describe('IgxTimePicker', () => { expect(timePicker.value).toEqual(new Date(2018, 10, 27, 16, 45, 0, 0)); })); - it('Should navigate dropdown lists correctly when format conatains only minutes.', fakeAsync(() => { + it('Should navigate dropdown lists correctly when format contains only minutes.', fakeAsync(() => { fixture.componentInstance.format = 'mm tt'; fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0); fixture.detectChanges(); @@ -1769,14 +1747,14 @@ describe('IgxTimePicker', () => { expect(document.activeElement.classList).toContain('igx-time-picker__minuteList'); - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true })); + UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', document.activeElement, true); fixture.detectChanges(); expect(document.activeElement.classList).toContain('igx-time-picker__ampmList'); - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true })); - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })); - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })); + UIInteractions.triggerKeyDownEvtUponElem('ArrowLeft', document.activeElement, true); + UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', document.activeElement, true); + UIInteractions.triggerKeyDownEvtUponElem('Enter', document.activeElement, true); tick(); fixture.detectChanges(); @@ -1784,7 +1762,7 @@ describe('IgxTimePicker', () => { expect(timePicker.value).toEqual(new Date(2018, 10, 27, 17, 46, 0, 0)); })); - it('Should spin editable input correctly when format conatains only hours - 24 hour format.', fakeAsync(() => { + it('Should spin editable input correctly when format contains only hours - 24 hour format.', fakeAsync(() => { fixture.componentInstance.format = 'HH'; fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0); fixture.detectChanges(); @@ -1802,7 +1780,7 @@ describe('IgxTimePicker', () => { expect(timePicker.value).toEqual(new Date(2018, 10, 27, 18, 45, 0, 0)); })); - it('Should spin editable input correctly when format conatains only minutes.', fakeAsync(() => { + it('Should spin editable input correctly when format contains only minutes.', () => { fixture.componentInstance.format = 'mm tt'; fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0); fixture.detectChanges(); @@ -1810,7 +1788,6 @@ describe('IgxTimePicker', () => { expect(input.nativeElement.value).toBe('45 PM'); input.nativeElement.setSelectionRange(0, 0); - tick(); fixture.detectChanges(); UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', input.nativeElement, true); @@ -1818,9 +1795,9 @@ describe('IgxTimePicker', () => { expect(input.nativeElement.value).toBe('46 PM'); expect(timePicker.value).toEqual(new Date(2018, 10, 27, 17, 46, 0, 0)); - })); + }); - it('Should spin editable input AM/PM correctly when format conatains only hours.', fakeAsync(() => { + it('Should spin editable input AM/PM correctly when format contains only hours.', () => { fixture.componentInstance.format = 'hh tt'; fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0); fixture.detectChanges(); @@ -1835,9 +1812,9 @@ describe('IgxTimePicker', () => { expect(input.nativeElement.value).toBe('05 AM'); expect(timePicker.value).toEqual(new Date(2018, 10, 27, 5, 45, 0, 0)); - })); + }); - it('Should render dialog and input group correctly when format conatains only minutes.', fakeAsync(() => { + it('Should render dialog and input group correctly when format contains only minutes.', fakeAsync(() => { fixture.componentInstance.format = 'mm'; fixture.componentInstance.mode = InteractionMode.Dialog; fixture.detectChanges(); @@ -1861,11 +1838,11 @@ describe('IgxTimePicker', () => { const headerHour = dom.query(By.css('.igx-time-picker__header-hour')); const headerAmPm = dom.query(By.css('.igx-time-picker__header-ampm')); - expect(headerHour.nativeElement.innerText.replace(/\n/g, '')).toEqual('4:05'); + expect(headerHour.nativeElement.innerText.replace(/\n/g, '')).toEqual('4:05:0'); expect(headerAmPm.nativeElement.innerText).toEqual(''); })); - it('Should render dialog and input group correctly when format conatains only hours.', fakeAsync(() => { + it('Should render dialog and input group correctly when format contains only hours.', fakeAsync(() => { fixture.componentInstance.format = 'hh tt'; fixture.componentInstance.mode = InteractionMode.Dialog; fixture.detectChanges(); @@ -1890,7 +1867,7 @@ describe('IgxTimePicker', () => { const headerHour = dom.query(By.css('.igx-time-picker__header-hour')); const headerAmPm = dom.query(By.css('.igx-time-picker__header-ampm')); - expect(headerHour.nativeElement.innerText.replace(/\n/g, '')).toEqual('04:5'); + expect(headerHour.nativeElement.innerText.replace(/\n/g, '')).toEqual('04:5:0'); expect(headerAmPm.nativeElement.innerText).toEqual('AM'); })); }); @@ -1898,7 +1875,7 @@ describe('IgxTimePicker', () => { @Component({ template: ` - + ` }) export class IgxTimePickerTestComponent { @@ -1912,8 +1889,8 @@ export class IgxTimePickerTestComponent { ` }) export class IgxTimePickerWithPassedTimeComponent { - public dateValue: Date = new Date(2017, 7, 7, 3, 24); - public customFormat = 'h:mm tt'; + public dateValue: Date = new Date(2017, 7, 7, 3, 24, 17); + public customFormat = 'h:mm:ss tt'; @ViewChild(IgxTimePickerComponent, { static: true }) public timePicker: IgxTimePickerComponent; } @@ -1923,8 +1900,8 @@ export class IgxTimePickerWithPassedTimeComponent { ` }) export class IgxTimePickerWithPmTimeComponent { - public dateValue: Date = new Date(2017, 7, 7, 12, 27); - public customFormat = 'h:mm tt'; + public dateValue: Date = new Date(2017, 7, 7, 12, 27, 23); + public customFormat = 'h:mm:ss tt'; @ViewChild(IgxTimePickerComponent, { static: true }) public timePicker: IgxTimePickerComponent; } @@ -1953,13 +1930,13 @@ export class IgxTimePickerWith24HTimeComponent { @Component({ template: ` + [value]="dateValue" [format]="'h:mm:ss tt'"> ` }) export class IgxTimePickerWithMInMaxTimeValueComponent { - public dateValue: Date = new Date(2017, 7, 7, 4, 27); - public myMinValue = '3:24 AM'; - public myMaxValue = '5:24 AM'; + public dateValue: Date = new Date(2017, 7, 7, 4, 27, 13); + public myMinValue = '3:24:11 AM'; + public myMaxValue = '5:24:28 AM'; @ViewChild(IgxTimePickerComponent, { static: true }) public timePicker: IgxTimePickerComponent; } @@ -1970,9 +1947,9 @@ export class IgxTimePickerWithMInMaxTimeValueComponent { ` }) export class IgxTimePickerWithSpinLoopFalseValueComponent { - public dateValue: Date = new Date(2017, 7, 7, 1, 0); - public customFormat = 'hh:mm tt'; - public customitemsDelta: any = { hours: 2, minutes: 2 }; + public dateValue: Date = new Date(2017, 7, 7, 1, 0, 0); + public customFormat = 'hh:mm:ss tt'; + public customitemsDelta: any = { hours: 2, minutes: 2, seconds: 3 }; @ViewChild(IgxTimePickerComponent, { static: true }) public timePicker: IgxTimePickerComponent; } @@ -1983,9 +1960,9 @@ export class IgxTimePickerWithSpinLoopFalseValueComponent { ` }) export class IgxTimePickerWithItemsDeltaValueComponent { - public dateValue: Date = new Date(2017, 7, 7, 10, 56); - public customFormat = 'hh:mm tt'; - public customitemsDelta: any = { hours: 2, minutes: 2 }; + public dateValue: Date = new Date(2017, 7, 7, 10, 56, 12); + public customFormat = 'hh:mm:ss tt'; + public customitemsDelta: any = { hours: 2, minutes: 2, seconds: 1 }; @ViewChild(IgxTimePickerComponent, { static: true }) public timePicker: IgxTimePickerComponent; } @@ -2090,6 +2067,34 @@ export class IgxTimePickerWithOutletComponent { @ViewChild('timepicker', { static: true }) public timepicker: IgxTimePickerComponent; } +@NgModule({ + declarations: [ + IgxTimePickerTestComponent, + IgxTimePickerWithPassedTimeComponent, + IgxTimePickerWithPmTimeComponent, + IgxTimePickerWithMInMaxTimeValueComponent, + IgxTimePickerWith24HTimeComponent, + IgxTimePickerWithAMPMLeadingZerosTimeComponent, + IgxTimePickerWithSpinLoopFalseValueComponent, + IgxTimePickerWithItemsDeltaValueComponent, + IgxTimePickerRetemplatedComponent, + IgxTimePickerDropDownComponent, + IgxTimePickerDropDownSingleHourComponent, + IgxTimePickerDropDownNoValueComponent, + IgxTimePickerRetemplatedDropDownComponent, + IgxTimePickerWithOutletComponent + ], + imports: [ + IgxTimePickerModule, + FormsModule, + NoopAnimationsModule, + IgxInputGroupModule, + IgxIconModule, + IgxToggleModule + ] +}) +export class IgxTimePickerTestingModule { } + // helper functions function findByInnerText(collection, searchText) { for (const element of collection) { From 4e3ddc580577a77279fc911e433d34ea6e6ac5e1 Mon Sep 17 00:00:00 2001 From: Boris Date: Tue, 10 Dec 2019 09:22:45 +0200 Subject: [PATCH 6/9] refactor(time-picker): determine mask parts --- .../lib/time-picker/time-picker.component.ts | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts index b06374c5245..01010ed6868 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts @@ -933,25 +933,31 @@ export class IgxTimePickerComponent implements private determineCursorPos(): void { this.clearCursorPos(); for (const char of this.format) { - if (char === 'H' || char === 'h') { - this.hours_pos.size === 0 ? this.hours_pos.add(this.format.indexOf(char)) : - this.hours_pos.add(this.format.lastIndexOf(char)); - this.hours_pos.add(this.format.lastIndexOf(char) + 1); - } - if (char === 'M' || char === 'm') { - this.minutes_pos.size === 0 ? this.minutes_pos.add(this.format.indexOf(char)) : - this.minutes_pos.add(this.format.lastIndexOf(char)); - this.minutes_pos.add(this.format.lastIndexOf(char) + 1); - } - if (char === 'S' || char === 's') { - this.seconds_pos.size === 0 ? this.seconds_pos.add(this.format.indexOf(char)) : - this.seconds_pos.add(this.format.lastIndexOf(char)); - this.seconds_pos.add(this.format.lastIndexOf(char) + 1); - } - if (char === 'T' || char === 't') { - this.ampm_pos.size === 0 ? this.ampm_pos.add(this.format.indexOf(char)) : - this.ampm_pos.add(this.format.lastIndexOf(char)); - this.ampm_pos.add(this.format.lastIndexOf(char) + 1); + switch (char) { + case 'H': + case 'h': + this.hours_pos.size === 0 ? this.hours_pos.add(this.format.indexOf(char)) : + this.hours_pos.add(this.format.lastIndexOf(char)); + this.hours_pos.add(this.format.lastIndexOf(char) + 1); + break; + case 'M': + case 'm': + this.minutes_pos.size === 0 ? this.minutes_pos.add(this.format.indexOf(char)) : + this.minutes_pos.add(this.format.lastIndexOf(char)); + this.minutes_pos.add(this.format.lastIndexOf(char) + 1); + break; + case 'S': + case 's': + this.seconds_pos.size === 0 ? this.seconds_pos.add(this.format.indexOf(char)) : + this.seconds_pos.add(this.format.lastIndexOf(char)); + this.seconds_pos.add(this.format.lastIndexOf(char) + 1); + break; + case 'T': + case 't': + this.ampm_pos.size === 0 ? this.ampm_pos.add(this.format.indexOf(char)) : + this.ampm_pos.add(this.format.lastIndexOf(char)); + this.ampm_pos.add(this.format.lastIndexOf(char) + 1); + break; } } } @@ -2022,7 +2028,7 @@ export class IgxTimePickerComponent implements if (this.showAmPmList && (this.showHoursList && this.showMinutesList && this.showSecondsList && this.ampm_pos.has(cursor)) || ((!this.showHoursList || !this.showMinutesList || !this.showSecondsList) && this.ampm_pos.has(cursor)) || - (this.determineFormatParts() && this.ampm_pos.has(cursor))) { + (this.determineMaskParts() && this.ampm_pos.has(cursor))) { const sections = this.displayValue.split(/[\s:]+/); sign = sections[sections.length - 1] === 'AM' ? 1 : -1; currentVal.setHours(currentVal.getHours() + (sign * 12)); @@ -2043,10 +2049,9 @@ export class IgxTimePickerComponent implements }); } - private determineFormatParts(): boolean { - return (this.showHoursList && (!this.showMinutesList || !this.showSecondsList)) || - (this.showMinutesList && (!this.showHoursList || !this.showSecondsList)) || - (this.showSecondsList && (!this.showHoursList || !this.showMinutesList)); + private determineMaskParts(): boolean { + return (this.showHoursList && (!this.showMinutesList || !this.showSecondsList) || + (this.showMinutesList && !this.showSecondsList)); } } From 005bda4ad24ff75f2a079515245c20107fcba8ae Mon Sep 17 00:00:00 2001 From: Boris Date: Tue, 10 Dec 2019 10:02:12 +0200 Subject: [PATCH 7/9] refactor(time-picker): move logic for cursor positioning to separate functions --- .../lib/time-picker/time-picker.component.ts | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts index 01010ed6868..887dd7597e0 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts @@ -2008,27 +2008,16 @@ export class IgxTimePickerComponent implements const mDelta = this.itemsDelta.minutes; const sDelta = this.itemsDelta.seconds; - if (this.showHoursList && this.hours_pos.has(cursor)) { + if (this.cursorOnHours(cursor, this.showHoursList)) { this.value = this._spinHours(currentVal, min, max, hDelta, sign); } - - if (this.showMinutesList && - ((this.showHoursList && this.minutes_pos.has(cursor)) || - (!this.showHoursList && this.minutes_pos.has(cursor)))) { + if (this.cursorOnMinutes(cursor, this.showHoursList, this.showMinutesList)) { this.value = this._spinMinutes(currentVal, mDelta, sign); } - - if (this.showSecondsList && - (this.showHoursList && this.showMinutesList && this.seconds_pos.has(cursor)) || - ((!this.showHoursList || !this.showMinutesList) && this.seconds_pos.has(cursor)) || - (!this.showHoursList && !this.showMinutesList && this.seconds_pos.has(cursor))) { + if (this.cursorOnSeconds(cursor, this.showHoursList, this.showMinutesList, this.showSecondsList)) { this.value = this._spinSeconds(currentVal, sDelta, sign); } - - if (this.showAmPmList && - (this.showHoursList && this.showMinutesList && this.showSecondsList && this.ampm_pos.has(cursor)) || - ((!this.showHoursList || !this.showMinutesList || !this.showSecondsList) && this.ampm_pos.has(cursor)) || - (this.determineMaskParts() && this.ampm_pos.has(cursor))) { + if (this.cursorOnAmPm(cursor, this.showHoursList, this.showMinutesList, this.showSecondsList, this.showAmPmList)) { const sections = this.displayValue.split(/[\s:]+/); sign = sections[sections.length - 1] === 'AM' ? 1 : -1; currentVal.setHours(currentVal.getHours() + (sign * 12)); @@ -2049,9 +2038,35 @@ export class IgxTimePickerComponent implements }); } + private cursorOnHours(cursor: number, showHours: boolean): boolean { + return showHours && this.hours_pos.has(cursor); + } + + private cursorOnMinutes(cursor: number, showHours: boolean, showMinutes: boolean): boolean { + return showMinutes && + (showHours && this.minutes_pos.has(cursor)) || + (!showHours && this.minutes_pos.has(cursor)); + } + + private cursorOnSeconds(cursor: number, showHours: boolean, showMinutes: boolean, showSeconds: boolean): boolean { + return showSeconds && + (showHours && showMinutes && this.seconds_pos.has(cursor)) || + ((!showHours || !showMinutes) && this.seconds_pos.has(cursor)) || + (!showHours && !showMinutes && this.seconds_pos.has(cursor)); + } + + private cursorOnAmPm(cursor: number, showHours: boolean, showMinutes: boolean, + showSeconds: boolean, showAmPm: boolean): boolean { + return showAmPm && + (showHours && showMinutes && showSeconds && this.ampm_pos.has(cursor)) || + ((!showHours || !showMinutes || !showSeconds) && this.ampm_pos.has(cursor)) || + (this.determineMaskParts() && this.ampm_pos.has(cursor)); + } + private determineMaskParts(): boolean { - return (this.showHoursList && (!this.showMinutesList || !this.showSecondsList) || - (this.showMinutesList && !this.showSecondsList)); + return this.showHoursList && + (!this.showMinutesList || !this.showSecondsList) || + (this.showMinutesList && !this.showSecondsList); } } From 0f3bde27679ba55ce152b725828ac7cc72a21625 Mon Sep 17 00:00:00 2001 From: Boris Date: Tue, 10 Dec 2019 13:17:58 +0200 Subject: [PATCH 8/9] refactor(time-picker): remove unneeded function; - rename hours_pos, minutes_pos, seconds_pos, ampm_pos --- .../lib/time-picker/time-picker.component.ts | 64 +++++++++---------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts index 887dd7597e0..0b97fb501ca 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts @@ -653,10 +653,10 @@ export class IgxTimePickerComponent implements private _onOpen = new EventEmitter(); private _onClose = new EventEmitter(); - private hours_pos = new Set(); - private minutes_pos = new Set(); - private seconds_pos = new Set(); - private ampm_pos = new Set(); + private _hoursPos = new Set(); + private _minutesPos = new Set(); + private _secondsPos = new Set(); + private _amPmPos = new Set(); private _onTouchedCallback: () => void = () => { }; private _onChangeCallback: (_: Date) => void = () => { }; @@ -936,37 +936,37 @@ export class IgxTimePickerComponent implements switch (char) { case 'H': case 'h': - this.hours_pos.size === 0 ? this.hours_pos.add(this.format.indexOf(char)) : - this.hours_pos.add(this.format.lastIndexOf(char)); - this.hours_pos.add(this.format.lastIndexOf(char) + 1); + this._hoursPos.size === 0 ? this._hoursPos.add(this.format.indexOf(char)) : + this._hoursPos.add(this.format.lastIndexOf(char)); + this._hoursPos.add(this.format.lastIndexOf(char) + 1); break; case 'M': case 'm': - this.minutes_pos.size === 0 ? this.minutes_pos.add(this.format.indexOf(char)) : - this.minutes_pos.add(this.format.lastIndexOf(char)); - this.minutes_pos.add(this.format.lastIndexOf(char) + 1); + this._minutesPos.size === 0 ? this._minutesPos.add(this.format.indexOf(char)) : + this._minutesPos.add(this.format.lastIndexOf(char)); + this._minutesPos.add(this.format.lastIndexOf(char) + 1); break; case 'S': case 's': - this.seconds_pos.size === 0 ? this.seconds_pos.add(this.format.indexOf(char)) : - this.seconds_pos.add(this.format.lastIndexOf(char)); - this.seconds_pos.add(this.format.lastIndexOf(char) + 1); + this._secondsPos.size === 0 ? this._secondsPos.add(this.format.indexOf(char)) : + this._secondsPos.add(this.format.lastIndexOf(char)); + this._secondsPos.add(this.format.lastIndexOf(char) + 1); break; case 'T': case 't': - this.ampm_pos.size === 0 ? this.ampm_pos.add(this.format.indexOf(char)) : - this.ampm_pos.add(this.format.lastIndexOf(char)); - this.ampm_pos.add(this.format.lastIndexOf(char) + 1); + this._amPmPos.size === 0 ? this._amPmPos.add(this.format.indexOf(char)) : + this._amPmPos.add(this.format.lastIndexOf(char)); + this._amPmPos.add(this.format.lastIndexOf(char) + 1); break; } } } private clearCursorPos() { - this.hours_pos.forEach(v => this.hours_pos.delete(v)); - this.minutes_pos.forEach(v => this.minutes_pos.delete(v)); - this.seconds_pos.forEach(v => this.seconds_pos.delete(v)); - this.ampm_pos.forEach(v => this.ampm_pos.delete(v)); + this._hoursPos.forEach(v => this._hoursPos.delete(v)); + this._minutesPos.forEach(v => this._minutesPos.delete(v)); + this._secondsPos.forEach(v => this._secondsPos.delete(v)); + this._amPmPos.forEach(v => this._amPmPos.delete(v)); } private _scrollItemIntoView(item: string, items: any[], selectedItem: string, isListLoop: boolean, viewType: string): any { @@ -2039,34 +2039,28 @@ export class IgxTimePickerComponent implements } private cursorOnHours(cursor: number, showHours: boolean): boolean { - return showHours && this.hours_pos.has(cursor); + return showHours && this._hoursPos.has(cursor); } private cursorOnMinutes(cursor: number, showHours: boolean, showMinutes: boolean): boolean { return showMinutes && - (showHours && this.minutes_pos.has(cursor)) || - (!showHours && this.minutes_pos.has(cursor)); + (showHours && this._minutesPos.has(cursor)) || + (!showHours && this._minutesPos.has(cursor)); } private cursorOnSeconds(cursor: number, showHours: boolean, showMinutes: boolean, showSeconds: boolean): boolean { return showSeconds && - (showHours && showMinutes && this.seconds_pos.has(cursor)) || - ((!showHours || !showMinutes) && this.seconds_pos.has(cursor)) || - (!showHours && !showMinutes && this.seconds_pos.has(cursor)); + (showHours && showMinutes && this._secondsPos.has(cursor)) || + ((!showHours || !showMinutes) && this._secondsPos.has(cursor)) || + (!showHours && !showMinutes && this._secondsPos.has(cursor)); } private cursorOnAmPm(cursor: number, showHours: boolean, showMinutes: boolean, showSeconds: boolean, showAmPm: boolean): boolean { return showAmPm && - (showHours && showMinutes && showSeconds && this.ampm_pos.has(cursor)) || - ((!showHours || !showMinutes || !showSeconds) && this.ampm_pos.has(cursor)) || - (this.determineMaskParts() && this.ampm_pos.has(cursor)); - } - - private determineMaskParts(): boolean { - return this.showHoursList && - (!this.showMinutesList || !this.showSecondsList) || - (this.showMinutesList && !this.showSecondsList); + (showHours && showMinutes && showSeconds && this._amPmPos.has(cursor)) || + ((!showHours || !showMinutes || !showSeconds) && this._amPmPos.has(cursor)) || + (!showHours && (!showMinutes || !showSeconds) && this._amPmPos.has(cursor)); } } From 1592b34ca0e0e19862c66b959afdac0cdb8ba953 Mon Sep 17 00:00:00 2001 From: Boris Date: Wed, 11 Dec 2019 14:57:57 +0200 Subject: [PATCH 9/9] chore(time-picker): update isSpinLoop comment --- .../src/lib/time-picker/time-picker.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts index 0b97fb501ca..602c81ad7e9 100644 --- a/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts +++ b/projects/igniteui-angular/src/lib/time-picker/time-picker.component.ts @@ -271,7 +271,7 @@ export class IgxTimePickerComponent implements /** * An @Input property that determines the spin behavior. By default `isSpinLoop` is set to true. - *The seconds and minutes and hour spinning will wrap around by default. + * The seconds, minutes and hour spinning will wrap around by default. *```html * *```