From b0ab6cab0f5de3ca76e721d98c7b8b3fe712016a Mon Sep 17 00:00:00 2001 From: SAndreeva Date: Mon, 7 Jan 2019 18:28:32 +0200 Subject: [PATCH 1/4] fix(time picker): cursor flickering in IE #2337 --- .../src/lib/directives/mask/mask.directive.ts | 4 +++ .../time-picker/time-picker.component.html | 1 - .../time-picker/time-picker.component.spec.ts | 29 ++++++++--------- .../lib/time-picker/time-picker.component.ts | 31 +++++++++++++++---- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/mask/mask.directive.ts b/projects/igniteui-angular/src/lib/directives/mask/mask.directive.ts index cf0d61b1ea3..4b0ac45b2d0 100644 --- a/projects/igniteui-angular/src/lib/directives/mask/mask.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/mask/mask.directive.ts @@ -212,6 +212,10 @@ export class IgxMaskDirective implements OnInit, ControlValueAccessor { public onKeydown(event): void { const key = event.keyCode || event.charCode; + if (isIE() && this._stopPropagation) { + this._stopPropagation = false; + } + if (key === KEYS.Ctrl) { this._ctrlDown = true; } 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 388b20af257..fb0cc2b19c7 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 @@ -11,7 +11,6 @@ [focusedValuePipe]="inputFormat" [promptChar]="promptChar" [value]="displayValue" - (keydown)="onKeydown($event)" (input)="onInput($event)" (blur)="onBlur($event)" (focus)="onFocus($event)" 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 0b9c0c4ab43..cb7ee88925d 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 @@ -922,7 +922,7 @@ describe('IgxTimePicker', () => { expect(input.nativeElement.value).toBe('4:5 AM'); })); - it('should correct spin (arrow buttons) on empty value (dropdown mode)', (() => { + it('should correct spin (arrow buttons) on empty value (dropdown mode)', fakeAsync(() => { const fixture = TestBed.createComponent(IgxTimePickerDropDownNoValueComponent); fixture.detectChanges(); @@ -941,12 +941,11 @@ describe('IgxTimePicker', () => { fixture.detectChanges(); UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', input.nativeElement, true); - fixture.detectChanges(); - - input.nativeElement.setSelectionRange(1, 1); + tick(100); fixture.detectChanges(); UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', input.nativeElement, true); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('01:00 AM', 'Hours spin failed'); @@ -1009,7 +1008,7 @@ describe('IgxTimePicker', () => { expect(input.nativeElement.value).toEqual(customValue); })); - it('should increase and decrease hours/minutes/AMPM, where the caret is, using arrows and mousewheel', (() => { + it('should increase and decrease hours/minutes/AMPM, where the caret is, using arrows and mousewheel', fakeAsync(() => { fixture.detectChanges(); // initial input value is 05:45 PM @@ -1022,16 +1021,14 @@ describe('IgxTimePicker', () => { // press arrow down UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', input.nativeElement, true); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('04:45 PM', 'ArrowDown on hours failed'); - // position caret at the hours - input.nativeElement.setSelectionRange(1, 1); - fixture.detectChanges(); - // mousewheel up UIInteractions.simulateWheelEvent(input.nativeElement, 0, -10); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('05:45 PM', 'MouseWheel Up on hours dailed'); @@ -1040,14 +1037,14 @@ describe('IgxTimePicker', () => { // position caret at the minutes and mousewheel down input.nativeElement.setSelectionRange(3, 3); UIInteractions.simulateWheelEvent(input.nativeElement, 0, 10); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('05:44 PM', 'MouseWheel Down on minutes failed'); - input.nativeElement.setSelectionRange(3, 3); - fixture.detectChanges(); // press arrow up UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', input.nativeElement, true); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('05:45 PM', 'ArrowUp on minutes failed'); @@ -1056,23 +1053,25 @@ describe('IgxTimePicker', () => { // position caret at AMPM and arrow down input.nativeElement.setSelectionRange(7, 7); UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', input.nativeElement, true); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('05:45 AM', 'ArrowDown on AMPM failed'); - input.nativeElement.setSelectionRange(7, 7); - fixture.detectChanges(); // mousewheel up UIInteractions.simulateWheelEvent(input.nativeElement, 0, -10); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('05:45 PM', 'MouseWheel Up on AMPM failed'); // test full hours input.nativeElement.setSelectionRange(0, 0); + tick(100); fixture.detectChanges(); UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', input.nativeElement, true); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('06:45 PM', 'MouseWheel Up on AMPM failed'); @@ -1185,7 +1184,7 @@ describe('IgxTimePicker', () => { expect(input.nativeElement.value).toBe(customValue, 'SpinLoop did not stop on AMPM'); })); - it('should spinloop on correct time after max or min values', (() => { + it('should spinloop on correct time after max or min values', fakeAsync(() => { fixture.detectChanges(); const customValue = '08:05 AM'; @@ -1207,6 +1206,7 @@ describe('IgxTimePicker', () => { fixture.detectChanges(); UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', input.nativeElement, true); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('11:05 AM', 'SpinLoop Down wrong time'); @@ -1224,6 +1224,7 @@ describe('IgxTimePicker', () => { fixture.detectChanges(); UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', input.nativeElement, true); + tick(100); fixture.detectChanges(); expect(input.nativeElement.value).toBe('09:03 AM', 'SpinLoop Up wrong time'); 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 e3af01ee839..d13bc66b3b8 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 @@ -16,7 +16,9 @@ import { ViewChild, Inject, ContentChild, - Injectable + Injectable, + Renderer, + AfterViewInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { HAMMER_GESTURE_CONFIG, HammerGestureConfig } from '@angular/platform-browser'; @@ -30,14 +32,14 @@ import { IgxMinuteItemDirective, IgxTimePickerTemplateDirective } from './time-picker.directives'; -import { Subject } from 'rxjs'; +import { Subject, fromEvent, interval, animationFrameScheduler } from 'rxjs'; import { EditorProvider } from '../core/edit-provider'; import { IgxTimePickerBase, IGX_TIME_PICKER_COMPONENT, TimePickerInteractionMode } from './time-picker.common'; import { IgxOverlayService } from '../services/overlay/overlay'; import { NoOpScrollStrategy } from '../services/overlay/scroll'; import { ConnectedPositioningStrategy } from '../services/overlay/position'; import { HorizontalAlignment, VerticalAlignment, PositionSettings, OverlaySettings } from '../services/overlay/utilities'; -import { takeUntil, filter } from 'rxjs/operators'; +import { takeUntil, filter, throttle } from 'rxjs/operators'; import { IgxButtonModule } from '../directives/button/button.directive'; import { IgxMaskModule } from '../directives/mask/mask.directive'; import { IgxOverlayOutletDirective } from '../directives/toggle/toggle.directive'; @@ -94,7 +96,8 @@ export class IgxTimePickerComponent implements ControlValueAccessor, EditorProvider, OnInit, - OnDestroy { + OnDestroy, + AfterViewInit { /** * An @Input property that sets the value of the `id` attribute. @@ -655,7 +658,8 @@ export class IgxTimePickerComponent implements }; } - constructor(@Inject(IgxOverlayService) private overlayService: IgxOverlayService) { + constructor(@Inject(IgxOverlayService) private overlayService: IgxOverlayService, + private _renderer: Renderer) { this.overlayService.onClosed.pipe( filter(event => event.id === this._overlayId), @@ -708,6 +712,18 @@ export class IgxTimePickerComponent implements this._dialogOverlaySettings = {}; } + /** + * @hidden + */ + public ngAfterViewInit(): void { + if (this.mode === TimePickerInteractionMode.dropdown) { + fromEvent(this.input.nativeElement, 'keydown').pipe( + throttle(() => interval(0, animationFrameScheduler)), + takeUntil(this._destroy$) + ).subscribe((res) => this.onKeydown(res)); + } + } + /** * @hidden */ @@ -1600,7 +1616,10 @@ export class IgxTimePickerComponent implements displayVal = this._formatTime(this.value, this.format); } - this.displayValue = this.inputFormat.transform(displayVal); + // minor hack for preventing cursor jumping in IE + const normalizedValue = this.inputFormat.transform(displayVal); + this._renderer.setElementProperty(this.input.nativeElement, 'value', normalizedValue); + this._setCursorPosition(cursor); requestAnimationFrame(() => { this._setCursorPosition(cursor); From 3d9ba9c1ee01210a51ad0efd19a08095cb3f9f71 Mon Sep 17 00:00:00 2001 From: SAndreeva Date: Tue, 8 Jan 2019 11:48:37 +0200 Subject: [PATCH 2/4] fix(time picker): address comments from review #2337 --- .../src/lib/time-picker/time-picker.component.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 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 d13bc66b3b8..a3c65207297 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 @@ -47,6 +47,7 @@ import { TimeDisplayFormatPipe, TimeInputFormatPipe } from './time-picker.pipes' import { ITimePickerResourceStrings, TimePickerResourceStringsEN } from '../core/i18n/time-picker-resources'; import { CurrentResourceStrings } from '../core/i18n/resources'; import { KEYS } from '../core/utils'; +import { animationFrame } from 'rxjs/internal/scheduler/animationFrame'; let NEXT_ID = 0; @@ -1617,8 +1618,8 @@ export class IgxTimePickerComponent implements } // minor hack for preventing cursor jumping in IE - const normalizedValue = this.inputFormat.transform(displayVal); - this._renderer.setElementProperty(this.input.nativeElement, 'value', normalizedValue); + this._displayValue = this.inputFormat.transform(displayVal); + this._renderer.setElementProperty(this.input.nativeElement, 'value', this._displayValue); this._setCursorPosition(cursor); requestAnimationFrame(() => { From 1fd13129a332996d87040ba97997341915b5bc67 Mon Sep 17 00:00:00 2001 From: SAndreeva Date: Tue, 8 Jan 2019 12:04:51 +0200 Subject: [PATCH 3/4] feat(time picker): clean up imports #2337 --- .../src/lib/time-picker/time-picker.component.ts | 1 - 1 file changed, 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 a3c65207297..10994098734 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 @@ -47,7 +47,6 @@ import { TimeDisplayFormatPipe, TimeInputFormatPipe } from './time-picker.pipes' import { ITimePickerResourceStrings, TimePickerResourceStringsEN } from '../core/i18n/time-picker-resources'; import { CurrentResourceStrings } from '../core/i18n/resources'; import { KEYS } from '../core/utils'; -import { animationFrame } from 'rxjs/internal/scheduler/animationFrame'; let NEXT_ID = 0; From 21f5bd154d381385567d8f11a0fbbea7e6ddf798 Mon Sep 17 00:00:00 2001 From: SAndreeva Date: Tue, 8 Jan 2019 15:48:28 +0200 Subject: [PATCH 4/4] fix(time picker): remove renderer #2337 --- .../src/lib/time-picker/time-picker.component.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 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 10994098734..20fd40f3642 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 @@ -17,7 +17,6 @@ import { Inject, ContentChild, Injectable, - Renderer, AfterViewInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @@ -658,8 +657,7 @@ export class IgxTimePickerComponent implements }; } - constructor(@Inject(IgxOverlayService) private overlayService: IgxOverlayService, - private _renderer: Renderer) { + constructor(@Inject(IgxOverlayService) private overlayService: IgxOverlayService) { this.overlayService.onClosed.pipe( filter(event => event.id === this._overlayId), @@ -1618,7 +1616,7 @@ export class IgxTimePickerComponent implements // minor hack for preventing cursor jumping in IE this._displayValue = this.inputFormat.transform(displayVal); - this._renderer.setElementProperty(this.input.nativeElement, 'value', this._displayValue); + this.input.nativeElement.value = this._displayValue; this._setCursorPosition(cursor); requestAnimationFrame(() => {