From 8c0ade5eb4a6fa5359b67856fdb05daf01db1b3c Mon Sep 17 00:00:00 2001 From: SendilKumar N Date: Sat, 23 Jul 2016 22:36:55 +0800 Subject: [PATCH] feat(timepicker): Added support for keyboard and mouse events fix #459 based on #468 --- src/timepicker/timepicker.spec.ts | 261 ++++++++++++++++++++++++++++++ src/timepicker/timepicker.ts | 71 ++++++-- 2 files changed, 321 insertions(+), 11 deletions(-) diff --git a/src/timepicker/timepicker.spec.ts b/src/timepicker/timepicker.spec.ts index f93eec16da..1b272ef732 100644 --- a/src/timepicker/timepicker.spec.ts +++ b/src/timepicker/timepicker.spec.ts @@ -12,6 +12,19 @@ import {NgbTimepicker} from './timepicker'; const createTestComponent = (html: string) => createGenericTestComponent(html, TestComponent) as ComponentFixture; +function createKeyDownEvent(key: 'ArrowUp' | 'ArrowDown') { + const event = {key: key, preventDefault: () => {}}; + spyOn(event, 'preventDefault'); + return event; +} + +function createMouseWheelEvent(detail: number) { + const event = {detail: detail, preventDefault: () => {}}; + spyOn(event, 'preventDefault'); + return event; +} + + function getTimepicker(el: HTMLElement) { return el.querySelector('ngb-timepicker'); } @@ -234,6 +247,72 @@ describe('ngb-timepicker', () => { }); })); + + it('should increment / decrement hours on key up/down', async(() => { + const html = ``; + + const fixture = createTestComponent(html); + fixture.componentInstance.model = {hour: 10, minute: 30, second: 0}; + fixture.detectChanges(); + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + return fixture.whenStable(); + }) + .then(() => { + + const inputs = fixture.debugElement.queryAll(By.css('input')); + + expectToDisplayTime(fixture.nativeElement, '10:30'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + + const upEvent = createKeyDownEvent('ArrowUp'); + inputs[0].triggerEventHandler('keydown.ArrowUp', upEvent); // H+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '11:30'); + expect(fixture.componentInstance.model).toEqual({hour: 11, minute: 30, second: 0}); + + const downEvent = createKeyDownEvent('ArrowDown'); + inputs[0].triggerEventHandler('keydown.ArrowDown', downEvent); // H- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:30'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + }); + })); + + + it('should increment / decrement hours on mouse wheel up/down', async(() => { + const html = ``; + + const fixture = createTestComponent(html); + fixture.componentInstance.model = {hour: 10, minute: 30, second: 0}; + fixture.detectChanges(); + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + return fixture.whenStable(); + }) + .then(() => { + + const inputs = fixture.debugElement.queryAll(By.css('input')); + + expectToDisplayTime(fixture.nativeElement, '10:30'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + + const upScroll = createMouseWheelEvent(50); + inputs[0].triggerEventHandler('mousewheel', upScroll); // H+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '11:30'); + expect(fixture.componentInstance.model).toEqual({hour: 11, minute: 30, second: 0}); + + const downScroll = createMouseWheelEvent(-50); + inputs[0].triggerEventHandler('mousewheel', downScroll); // H- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:30'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + }); + })); + it('should wrap hours', async(() => { const html = ``; @@ -294,6 +373,70 @@ describe('ngb-timepicker', () => { }); })); + it('should increment / decrement minutes on key up/down', async(() => { + const html = ``; + + const fixture = createTestComponent(html); + fixture.componentInstance.model = {hour: 10, minute: 30, second: 0}; + fixture.detectChanges(); + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + return fixture.whenStable(); + }) + .then(() => { + + const inputs = fixture.debugElement.queryAll(By.css('input')); + + expectToDisplayTime(fixture.nativeElement, '10:30'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + + const upEvent = createKeyDownEvent('ArrowUp'); + inputs[1].triggerEventHandler('keydown.ArrowUp', upEvent); // M+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:31'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 31, second: 0}); + + const downEvent = createKeyDownEvent('ArrowDown'); + inputs[1].triggerEventHandler('keydown.ArrowDown', downEvent); // M- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:30'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + }); + })); + + it('should increment / decrement minutes on mouse wheel up/down', async(() => { + const html = ``; + + const fixture = createTestComponent(html); + fixture.componentInstance.model = {hour: 10, minute: 30, second: 0}; + fixture.detectChanges(); + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + return fixture.whenStable(); + }) + .then(() => { + + const inputs = fixture.debugElement.queryAll(By.css('input')); + + expectToDisplayTime(fixture.nativeElement, '10:30'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + + const upScroll = createMouseWheelEvent(50); + inputs[1].triggerEventHandler('mousewheel', upScroll); // M+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:31'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 31, second: 0}); + + const downScroll = createMouseWheelEvent(-50); + inputs[1].triggerEventHandler('mousewheel', downScroll); // M- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:30'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + }); + })); + it('should wrap minutes', async(() => { const html = ``; @@ -351,6 +494,69 @@ describe('ngb-timepicker', () => { }); })); + it('should increment / decrement seconds on key up/down', async(() => { + const html = ``; + + const fixture = createTestComponent(html); + fixture.componentInstance.model = {hour: 10, minute: 30, second: 0}; + fixture.detectChanges(); + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + return fixture.whenStable(); + }) + .then(() => { + const inputs = fixture.debugElement.queryAll(By.css('input')); + + expectToDisplayTime(fixture.nativeElement, '10:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + + const upEvent = createKeyDownEvent('ArrowUp'); + inputs[2].triggerEventHandler('keydown.ArrowUp', upEvent); // S+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:30:01'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 1}); + + const downEvent = createKeyDownEvent('ArrowDown'); + inputs[2].triggerEventHandler('keydown.ArrowDown', downEvent); // S- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + }); + })); + + it('should increment / decrement minutes on mouse wheel up/down', async(() => { + const html = ``; + + const fixture = createTestComponent(html); + fixture.componentInstance.model = {hour: 10, minute: 30, second: 0}; + fixture.detectChanges(); + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + return fixture.whenStable(); + }) + .then(() => { + + const inputs = fixture.debugElement.queryAll(By.css('input')); + + expectToDisplayTime(fixture.nativeElement, '10:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + + const upScroll = createMouseWheelEvent(50); + inputs[2].triggerEventHandler('mousewheel', upScroll); // S+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:30:01'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 1}); + + const downScroll = createMouseWheelEvent(-50); + inputs[2].triggerEventHandler('mousewheel', downScroll); // H- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '10:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 10, minute: 30, second: 0}); + }); + })); + it('should wrap seconds', async(() => { const html = ``; @@ -746,6 +952,61 @@ describe('ngb-timepicker', () => { }); })); + it('should not change the value on mousewheel up/down, when it is disabled', async(() => { + const html = ``; + + const fixture = createTestComponent(html); + fixture.componentInstance.model = {hour: 13, minute: 30, second: 0}; + fixture.detectChanges(); + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + return fixture.whenStable(); + }) + .then(() => { + const inputs = fixture.debugElement.queryAll(By.css('input')); + + expectToDisplayTime(fixture.nativeElement, '13:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 13, minute: 30, second: 0}); + + const upScroll = createMouseWheelEvent(50); + const downScroll = createMouseWheelEvent(-50); + + expectToDisplayTime(fixture.nativeElement, '13:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 13, minute: 30, second: 0}); + + inputs[0].triggerEventHandler('mousewheel', upScroll); // H+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '13:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 13, minute: 30, second: 0}); + + inputs[0].triggerEventHandler('mousewheel', downScroll); // H- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '13:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 13, minute: 30, second: 0}); + + inputs[1].triggerEventHandler('mousewheel', upScroll); // M+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '13:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 13, minute: 30, second: 0}); + + inputs[1].triggerEventHandler('mousewheel', downScroll); // M- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '13:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 13, minute: 30, second: 0}); + + inputs[2].triggerEventHandler('mousewheel', upScroll); // S+ + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '13:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 13, minute: 30, second: 0}); + + inputs[2].triggerEventHandler('mousewheel', downScroll); // S- + fixture.detectChanges(); + expectToDisplayTime(fixture.nativeElement, '13:30:00'); + expect(fixture.componentInstance.model).toEqual({hour: 13, minute: 30, second: 0}); + }); + })); + it('should have disabled class, when it is disabled', () => { const html = ``; diff --git a/src/timepicker/timepicker.ts b/src/timepicker/timepicker.ts index 9f1d7ab3a3..45e74159cb 100644 --- a/src/timepicker/timepicker.ts +++ b/src/timepicker/timepicker.ts @@ -1,7 +1,6 @@ import {Component, Input, forwardRef, OnChanges, SimpleChanges} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; - -import {isNumber, padNumber, toInteger, isDefined} from '../util/util'; +import {isNumber, padNumber, toInteger, toString, isDefined} from '../util/util'; import {NgbTime} from './ngb-time'; import {NgbTimepickerConfig} from './timepicker-config'; @@ -58,14 +57,14 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
-   - @@ -73,7 +72,7 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {