diff --git a/.travis.yml b/.travis.yml index a8279236..3b62b835 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ node_js: - '10' script: +- npm run lint - npm run test - npm run build diff --git a/CHANGELOG.md b/CHANGELOG.md index 695df28c..6c24cad4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ All notable changes to this project will be documented in this file +## 2.13.0 (2019-02-16) + +### Features + +* feat(ngx-material-timepicker): add `hourSelected` event emitter [(dd43874)](https://github.com/Agranom/ngx-material-timepicker/commit/dd4387407284788438a79283139a9a4f6e4fff44), +closes [(#108)](https://github.com/Agranom/ngx-material-timepicker/issues/108) + +* feat(ngx-material-timepicker): add `opened` event emitter [(5bc9cc0)](https://github.com/Agranom/ngx-material-timepicker/commit/5bc9cc088482ba1aeee32af2c97a0ece86dc1205), +closes [(#112)](https://github.com/Agranom/ngx-material-timepicker/issues/112) + +* feat(ngx-material-timepicker-dial): add possibility to set a custom hint template [(479f311)](https://github.com/Agranom/ngx-material-timepicker/commit/479f311cee74db79372263a19911cf5b0e73b8b8), +relates to [(#103)](https://github.com/Agranom/ngx-material-timepicker/issues/103) + +### Fixes + +* fix(clock face): fix bug with dead zone in 12 or 00 time section [(07a8618)](https://github.com/Agranom/ngx-material-timepicker/commit/07a861897842a8e7225a2a9d4613083481587df1), + closes [(#109)](https://github.com/Agranom/ngx-material-timepicker/issues/109) + +### Improvements + +* improvement(ngx-material-timepicker-dial): show/hide dial hint onFocus/onBlur dial control [(c96da39)](https://github.com/Agranom/ngx-material-timepicker/commit/c96da391ef37931947d0db8b65b9a987bb59b4eb), + relates to [(#103)](https://github.com/Agranom/ngx-material-timepicker/issues/103) + ## 2.12.0 (2019-01-26) ### Features diff --git a/README.md b/README.md index 2ae89e50..960291a9 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ Selector: `ngx-material-timepicker` cancelBtnTmpl: TemplateRef | Set if you want to change cancel button to your custom one. | | @Input() confirmBtnTmpl: TemplateRef | Set if you want to change confirm button to your custom one. | +| @Input() + editableHintTmpl: TemplateRef | Set if you want to change dial hint to your custom one. Works only if `enableKeyboardInput = true` | | @Input() ESC: boolean | Disable or enable closing timepicker by ESC. | | @Input() @@ -91,8 +93,12 @@ Selector: `ngx-material-timepicker` preventOverlayClick: boolean | Set `true` to prevent closing the timepicker by overlay click. Uses `false` by default | | @Output() timeSet: EventEmitter\ | Emits time when that was set. | +| @Output() + opened: EventEmitter\ | Emits after timepicker was opened. | | @Output() closed: EventEmitter\ | Emits after timepicker was closed. | +| @Output() + hourSelected: EventEmitter\ | Emits after hour was selected. | **NgxMaterialTimepickerToggleComponent** diff --git a/package-lock.json b/package-lock.json index 663cfe72..0e2b6eae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ngx-material-timepicker", - "version": "2.11.2", + "version": "2.12.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3087,7 +3087,6 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, - "optional": true, "requires": { "hoek": "2.x.x" } @@ -3350,8 +3349,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==", - "dev": true, - "optional": true + "dev": true }, "buffer-xor": { "version": "1.0.3", @@ -6850,8 +6848,7 @@ "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true, - "optional": true + "dev": true }, "home-or-tmp": { "version": "3.0.0", @@ -7085,7 +7082,6 @@ "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", "dev": true, - "optional": true, "requires": { "httpreq": ">=0.4.22", "underscore": "~1.7.0" @@ -7095,8 +7091,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", - "dev": true, - "optional": true + "dev": true }, "https-browserify": { "version": "1.0.0", @@ -7784,8 +7779,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true, - "optional": true + "dev": true }, "is-redirect": { "version": "1.0.0", @@ -8516,15 +8510,13 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", - "dev": true, - "optional": true + "dev": true }, "libmime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", "dev": true, - "optional": true, "requires": { "iconv-lite": "0.4.15", "libbase64": "0.1.0", @@ -8535,8 +8527,7 @@ "version": "0.4.15", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", - "dev": true, - "optional": true + "dev": true } } }, @@ -8544,8 +8535,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", - "dev": true, - "optional": true + "dev": true }, "license-webpack-plugin": { "version": "1.5.0", @@ -9954,15 +9944,13 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=", - "dev": true, - "optional": true + "dev": true }, "nodemailer-shared": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", "dev": true, - "optional": true, "requires": { "nodemailer-fetch": "1.6.0" } @@ -9995,8 +9983,7 @@ "version": "0.1.10", "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", - "dev": true, - "optional": true + "dev": true }, "nopt": { "version": "3.0.6", @@ -12828,7 +12815,6 @@ "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", "dev": true, - "optional": true, "requires": { "httpntlm": "1.6.1", "nodemailer-shared": "1.1.0" @@ -14364,8 +14350,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", - "dev": true, - "optional": true + "dev": true }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", diff --git a/package.json b/package.json index d0540ee3..59a0ccbf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ngx-material-timepicker", "description": "Handy material design timepicker for angular", - "version": "2.12.0", + "version": "2.13.0", "license": "MIT", "author": "Vitalii Boiko ", "keywords": [ diff --git a/src/app/app.component.html b/src/app/app.component.html index d084afca..55925157 100755 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -2,8 +2,10 @@

Material Time Picker

+ GitHub icon + @@ -28,8 +30,8 @@

Examples

- + [ngxTimepicker]="defaultPicker" readonly> +
Examples

+ @@ -101,8 +104,10 @@

Examples

+ + @@ -176,7 +181,17 @@

Examples

- + +
+
+ + + +

Custom hint

+
@@ -184,7 +199,7 @@

Examples

- +
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 6068f09d..94047151 100755 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,5 +1,5 @@ /* tslint:disable:max-line-length */ -import {Component} from '@angular/core'; +import { Component } from '@angular/core'; import { NgxMaterialTimepickerTheme } from './material-timepicker/models/ngx-material-timepicker-theme.interface'; @Component({ @@ -136,6 +136,16 @@ export class AppComponent { clockFaceTimeInactiveColor: '#fff' } }; + +
+ + + +

Custom hint

+
+
`; darkTheme: NgxMaterialTimepickerTheme = { diff --git a/src/app/material-timepicker/components/timepicker-12-hours-face/ngx-material-timepicker-12-hours-face.component.html b/src/app/material-timepicker/components/timepicker-12-hours-face/ngx-material-timepicker-12-hours-face.component.html index e45d6130..4861aaea 100755 --- a/src/app/material-timepicker/components/timepicker-12-hours-face/ngx-material-timepicker-12-hours-face.component.html +++ b/src/app/material-timepicker/components/timepicker-12-hours-face/ngx-material-timepicker-12-hours-face.component.html @@ -1,2 +1,2 @@ + (timeChange)="hourChange.next($event)" (timeSelected)="onTimeSelected($event)"> diff --git a/src/app/material-timepicker/components/timepicker-24-hours-face/ngx-material-timepicker-24-hours-face.component.html b/src/app/material-timepicker/components/timepicker-24-hours-face/ngx-material-timepicker-24-hours-face.component.html index d4511936..fe8cc650 100755 --- a/src/app/material-timepicker/components/timepicker-24-hours-face/ngx-material-timepicker-24-hours-face.component.html +++ b/src/app/material-timepicker/components/timepicker-24-hours-face/ngx-material-timepicker-24-hours-face.component.html @@ -1,3 +1,3 @@ + (timeSelected)="onTimeSelected($event)"> diff --git a/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.spec.ts b/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.spec.ts index 7931f9b2..79ef20c9 100755 --- a/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.spec.ts +++ b/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.spec.ts @@ -1,4 +1,4 @@ -import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { NgxMaterialTimepickerDialControlComponent } from './ngx-material-timepicker-dial-control.component'; import { NO_ERRORS_SCHEMA, SimpleChanges } from '@angular/core'; import { TimeUnit } from '../../models/time-unit.enum'; @@ -17,9 +17,10 @@ describe('NgxMaterialTimepickerDialControlComponent', () => { component = fixture.componentInstance; }); - it('should set current time to previous time and change time unit', fakeAsync(() => { - let timeUnit = null; - component.timeUnitChanged.subscribe(unit => timeUnit = unit); + it('should set current time to previous time, change time unit and emit focus event', async (() => { + let counter = 0; + component.timeUnitChanged.subscribe(unit => expect(unit).toBe(TimeUnit.MINUTE)); + component.focused.subscribe(() => expect(++counter).toBe(1)); component.time = '10'; expect(component.previousTime).toBeUndefined(); @@ -27,7 +28,6 @@ describe('NgxMaterialTimepickerDialControlComponent', () => { component.saveTimeAndChangeTimeUnit({preventDefault: () => null} as FocusEvent, TimeUnit.MINUTE); expect(component.previousTime).toBe('10'); - expect(timeUnit).toBe(TimeUnit.MINUTE); })); it('should emit changed time if it exists and available', fakeAsync(() => { @@ -102,7 +102,9 @@ describe('NgxMaterialTimepickerDialControlComponent', () => { expect(component.time).toBe('4'); }); - it('should format time if editable', () => { + it('should format time if editable and emit unfocused event', async(() => { + let counter = 0; + component.isEditable = true; component.time = '2'; component.previousTime = 4; @@ -111,15 +113,16 @@ describe('NgxMaterialTimepickerDialControlComponent', () => { component.formatTime(); expect(component.time).toBe('02'); + component.unfocused.subscribe(() => expect(++counter).toBe(1)); component.time = ''; component.formatTime(); - expect(component.time).toBe('04'); + expect(component.time).toBe('04'); component.time = '5'; component.isEditable = false; component.formatTime(); expect(component.time).toBe('5'); - }); + })); describe('onKeyDown', () => { let counter = 0; diff --git a/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.ts b/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.ts index 787c09b7..bf7e8f13 100755 --- a/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.ts +++ b/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.ts @@ -22,6 +22,8 @@ export class NgxMaterialTimepickerDialControlComponent implements OnChanges { @Output() timeUnitChanged = new EventEmitter(); @Output() timeChanged = new EventEmitter(); + @Output() focused = new EventEmitter(); + @Output() unfocused = new EventEmitter(); private get selectedTime(): ClockFaceTime { if (!!this.time) { @@ -42,6 +44,7 @@ export class NgxMaterialTimepickerDialControlComponent implements OnChanges { event.preventDefault(); this.previousTime = this.time; this.timeUnitChanged.next(unit); + this.focused.next(); } updateTime(): void { @@ -56,6 +59,7 @@ export class NgxMaterialTimepickerDialControlComponent implements OnChanges { if (this.isEditable) { const time = this.time || this.previousTime; this.time = new TimeFormatterPipe().transform(+time, this.timeUnit); + this.unfocused.next(); } } diff --git a/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.html b/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.html index e18f32b4..9b37d536 100755 --- a/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.html +++ b/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.html @@ -5,7 +5,9 @@ [isActive]="activeTimeUnit === timeUnit.HOUR" [isEditable]="isEditable" (timeUnitChanged)="changeTimeUnit($event)" - (timeChanged)="changeHour($event)"> + (timeChanged)="changeHour($event)" + (focused)="showHint()" + (unfocused)="hideHint()"> : @@ -14,7 +16,9 @@ [isEditable]="isEditable" [minutesGap]="minutesGap" (timeUnitChanged)="changeTimeUnit($event)" - (timeChanged)="changeMinute($event)"> + (timeChanged)="changeMinute($event)" + (focused)="showHint()" + (unfocused)="hideHint()">
@@ -25,8 +29,11 @@ [hours]="hours" [minutes]="minutes" [selectedHour]="hour" (periodChanged)="changePeriod($event)"> -
+
+ - * use arrows () to change the time + + * use arrows () to change the time +
diff --git a/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.scss b/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.scss index 781d793c..673c72b8 100755 --- a/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.scss +++ b/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.scss @@ -2,6 +2,7 @@ .timepicker-dial { text-align: right; + &__container { display: flex; align-items: center; @@ -31,6 +32,12 @@ } } + &__hint-container { + &--hidden { + visibility: hidden; + } + } + &__hint { display: inline-block; font-size: 10px; @@ -38,10 +45,12 @@ @supports (color: var(--dial-active-color)) { color: var(--dial-active-color); } + span { font-size: 14px; } } + } @media (max-device-width: 1023px) and (orientation: landscape) { diff --git a/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.spec.ts b/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.spec.ts index 34fff75b..fe627ed0 100755 --- a/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.spec.ts +++ b/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.spec.ts @@ -1,9 +1,9 @@ -import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; -import {NgxMaterialTimepickerDialComponent} from './ngx-material-timepicker-dial.component'; -import {NO_ERRORS_SCHEMA, SimpleChanges} from '@angular/core'; -import {TimepickerTime} from '../../timepicker-time.namespace'; -import {TimePeriod} from '../../models/time-period.enum'; -import {TimeUnit} from '../../models/time-unit.enum'; +import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { NgxMaterialTimepickerDialComponent } from './ngx-material-timepicker-dial.component'; +import { NO_ERRORS_SCHEMA, SimpleChanges } from '@angular/core'; +import { TimepickerTime } from '../../timepicker-time.namespace'; +import { TimePeriod } from '../../models/time-period.enum'; +import { TimeUnit } from '../../models/time-unit.enum'; describe('NgxMaterialTimepickerDialComponent', () => { let fixture: ComponentFixture; @@ -121,4 +121,20 @@ describe('NgxMaterialTimepickerDialComponent', () => { expect(minute).toEqual({time: 20, angle: 60}); })); + it('should set isHintVisible true', () => { + expect(component.isHintVisible).toBeFalsy(); + + component.showHint(); + + expect(component.isHintVisible).toBeTruthy(); + }); + + it('should set isHintVisible false', () => { + component.isHintVisible = true; + + component.hideHint(); + + expect(component.isHintVisible).toBeFalsy(); + }); + }); diff --git a/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.ts b/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.ts index 527f5b4e..07f356ad 100755 --- a/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.ts +++ b/src/app/material-timepicker/components/timepicker-dial/ngx-material-timepicker-dial.component.ts @@ -1,9 +1,9 @@ -import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, TemplateRef} from '@angular/core'; -import {TimePeriod} from '../../models/time-period.enum'; -import {TimeUnit} from '../../models/time-unit.enum'; -import {TimepickerTime} from '../../timepicker-time.namespace'; -import {ClockFaceTime} from '../../models/clock-face-time.interface'; -import {Moment} from 'moment'; +import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, TemplateRef } from '@angular/core'; +import { TimePeriod } from '../../models/time-period.enum'; +import { TimeUnit } from '../../models/time-unit.enum'; +import { TimepickerTime } from '../../timepicker-time.namespace'; +import { ClockFaceTime } from '../../models/clock-face-time.interface'; +import { Moment } from 'moment'; @Component({ selector: 'ngx-material-timepicker-dial', @@ -18,6 +18,8 @@ export class NgxMaterialTimepickerDialComponent implements OnChanges { hours: ClockFaceTime[]; minutes: ClockFaceTime[]; + isHintVisible: boolean; + @Input() editableHintTmpl: TemplateRef; @Input() hour: number | string; @Input() minute: number | string; @@ -74,4 +76,12 @@ export class NgxMaterialTimepickerDialComponent implements OnChanges { changeMinute(minute: ClockFaceTime): void { this.minuteChanged.next(minute); } + + showHint(): void { + this.isHintVisible = true; + } + + hideHint(): void { + this.isHintVisible = false; + } } diff --git a/src/app/material-timepicker/components/timepicker-face/ngx-material-timepicker-face.component.spec.ts b/src/app/material-timepicker/components/timepicker-face/ngx-material-timepicker-face.component.spec.ts index 2cda5f32..e9ae41d2 100755 --- a/src/app/material-timepicker/components/timepicker-face/ngx-material-timepicker-face.component.spec.ts +++ b/src/app/material-timepicker/components/timepicker-face/ngx-material-timepicker-face.component.spec.ts @@ -1,10 +1,10 @@ -import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; -import {NgxMaterialTimepickerFaceComponent} from './ngx-material-timepicker-face.component'; -import {ElementRef, NO_ERRORS_SCHEMA, SimpleChanges} from '@angular/core'; -import {ClockFaceTime} from '../../models/clock-face-time.interface'; -import {StyleSanitizerPipe} from '../../pipes/style-sanitizer.pipe'; -import {TimeUnit} from '../../models/time-unit.enum'; -import {MinutesFormatterPipe} from '../../pipes/minutes-formatter.pipe'; +import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { NgxMaterialTimepickerFaceComponent } from './ngx-material-timepicker-face.component'; +import { ElementRef, NO_ERRORS_SCHEMA, SimpleChanges } from '@angular/core'; +import { ClockFaceTime } from '../../models/clock-face-time.interface'; +import { StyleSanitizerPipe } from '../../pipes/style-sanitizer.pipe'; +import { TimeUnit } from '../../models/time-unit.enum'; +import { MinutesFormatterPipe } from '../../pipes/minutes-formatter.pipe'; describe('NgxMaterialTimepickerFaceComponent', () => { @@ -276,18 +276,15 @@ describe('NgxMaterialTimepickerFaceComponent', () => { expect(selectedTime).toEqual({time: 1, angle: 5}); })); - it('should emit selected time once user stop interaction with clock face', fakeAsync(() => { - let counter = 0; + it('should emit selected time once user stop interaction with clock face', async(() => { const mouseCords: MouseEventInit = {clientX: 20, clientY: 20}; component.faceTime = minutesFaceTime; component.unit = TimeUnit.MINUTE; - component.timeSelected.subscribe(() => counter++); + component.timeSelected.subscribe((time) => expect(time).toBe(55)); component.onMouseup(mouseClickEvent); component.selectTime(new MouseEvent('click', mouseCords)); - tick(); - expect(counter).toBe(1); })); it(`should return 'true' or 'false' whether hour is selected or not`, () => { diff --git a/src/app/material-timepicker/components/timepicker-face/ngx-material-timepicker-face.component.ts b/src/app/material-timepicker/components/timepicker-face/ngx-material-timepicker-face.component.ts index d22c5fb6..0d296cd1 100755 --- a/src/app/material-timepicker/components/timepicker-face/ngx-material-timepicker-face.component.ts +++ b/src/app/material-timepicker/components/timepicker-face/ngx-material-timepicker-face.component.ts @@ -46,7 +46,7 @@ export class NgxMaterialTimepickerFaceComponent implements AfterViewInit, OnChan @Input() minutesGap: number; @Output() timeChange = new EventEmitter(); - @Output() timeSelected = new EventEmitter(); + @Output() timeSelected = new EventEmitter(); @ViewChild('clockFace') clockFace: ElementRef; @ViewChild('clockHand') clockHand: ElementRef; @@ -114,15 +114,16 @@ export class NgxMaterialTimepickerFaceComponent implements AfterViewInit, OnChan const roundedAngle = isInnerClockChosen ? roundAngle(circleAngle, angleStep) + 360 : roundAngle(circleAngle, angleStep); + const angle = roundedAngle === 0 ? 360 : roundedAngle; - const selectedTime = this.faceTime.find(val => val.angle === roundedAngle); + const selectedTime = this.faceTime.find(val => val.angle === angle); if (selectedTime && !selectedTime.disabled) { this.timeChange.next(selectedTime); /* To let know whether user ended interaction with clock face */ if (!this.isStarted) { - this.timeSelected.next(); + this.timeSelected.next(selectedTime.time); } } diff --git a/src/app/material-timepicker/components/timepicker-hours-face/ngx-material-timepicker-hours-face.spec.ts b/src/app/material-timepicker/components/timepicker-hours-face/ngx-material-timepicker-hours-face.spec.ts index 34977b48..d0577f31 100755 --- a/src/app/material-timepicker/components/timepicker-hours-face/ngx-material-timepicker-hours-face.spec.ts +++ b/src/app/material-timepicker/components/timepicker-hours-face/ngx-material-timepicker-hours-face.spec.ts @@ -1,4 +1,4 @@ -import {ComponentFixture, TestBed} from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import {Component} from '@angular/core'; import {NgxMaterialTimepickerHoursFace} from './ngx-material-timepicker-hours-face'; @@ -42,4 +42,18 @@ describe('NgxMaterialTimepickerHoursFace', () => { it('should generate array with 24 items', () => { expect(component24.hoursList.length).toBe(24); }); + + it('should emit selected hour (12hr format)', async(() => { + const time = 10; + + component12.hourSelected.subscribe(hour => expect(hour).toBe(time)); + component12.onTimeSelected(time); + })); + + it('should emit selected hour (24hr format)', async(() => { + const time = 15; + + component24.hourSelected.subscribe(hour => expect(hour).toBe(time)); + component24.onTimeSelected(time); + })); }); diff --git a/src/app/material-timepicker/components/timepicker-hours-face/ngx-material-timepicker-hours-face.ts b/src/app/material-timepicker/components/timepicker-hours-face/ngx-material-timepicker-hours-face.ts index b248b7c1..a32480c0 100755 --- a/src/app/material-timepicker/components/timepicker-hours-face/ngx-material-timepicker-hours-face.ts +++ b/src/app/material-timepicker/components/timepicker-hours-face/ngx-material-timepicker-hours-face.ts @@ -12,11 +12,15 @@ export class NgxMaterialTimepickerHoursFace { @Input() format: number; @Output() hourChange = new EventEmitter(); - @Output() hourSelected = new EventEmitter(); + @Output() hourSelected = new EventEmitter(); hoursList: ClockFaceTime[] = []; protected constructor(format: number) { this.hoursList = TimepickerTime.getHours(format); } + + onTimeSelected(time: number): void { + this.hourSelected.next(time); + } } diff --git a/src/app/material-timepicker/directives/ngx-timepicker.directive.ts b/src/app/material-timepicker/directives/ngx-timepicker.directive.ts index 2102161f..7ef60a06 100755 --- a/src/app/material-timepicker/directives/ngx-timepicker.directive.ts +++ b/src/app/material-timepicker/directives/ngx-timepicker.directive.ts @@ -7,6 +7,7 @@ import {TimeAdapter} from '../services/time-adapter'; const VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, + // tslint:disable-next-line useExisting: forwardRef(() => TimepickerDirective), multi: true }; diff --git a/src/app/material-timepicker/ngx-material-timepicker.component.html b/src/app/material-timepicker/ngx-material-timepicker.component.html index e8a42b89..54f55389 100755 --- a/src/app/material-timepicker/ngx-material-timepicker.component.html +++ b/src/app/material-timepicker/ngx-material-timepicker.component.html @@ -24,7 +24,7 @@ [minTime]="minTime" [maxTime]="maxTime" [format]="format" - (hourSelected)="changeTimeUnit(timeUnit.MINUTE)"> + (hourSelected)="onHourSelected($event)"> + (hourSelected)="onHourSelected($event)"> { let fixture: ComponentFixture; @@ -98,11 +98,14 @@ describe('NgxMaterialTimepickerComponent', () => { expect(component.selectedPeriod).toBe(TimePeriod.AM); }); - it(`should set isOpened 'true' and change animationState to 'enter' on open call`, () => { + it(`should set isOpened 'true', change animationState to 'enter' and emit event on open call`, async(() => { + let counter = 0; + + component.opened.subscribe(() => expect(++counter).toBe(1)); component.open(); expect(component.isOpened).toBeTruthy(); expect(component.animationState).toBe(AnimationState.ENTER); - }); + })); it('should change animationState to \'leave\' on close call', () => { component.close(); @@ -199,6 +202,17 @@ describe('NgxMaterialTimepickerComponent', () => { expect(component.minutesGap).toBeUndefined(); }); + it('should change timeUnit to MINUTE and emit selected hour', async(() => { + const hour = 10; + + expect(component.activeTimeUnit).toBe(TimeUnit.HOUR); + + component.hourSelected.subscribe(h => expect(h).toBe(hour)); + component.onHourSelected(hour); + + expect(component.activeTimeUnit).toBe(TimeUnit.MINUTE); + })); + describe('Timepicker subscriptions', () => { const hour = {time: 11, angle: 360}; const minute = {time: 44, angle: 36}; diff --git a/src/app/material-timepicker/ngx-material-timepicker.component.ts b/src/app/material-timepicker/ngx-material-timepicker.component.ts index ddb6f632..f63acd16 100755 --- a/src/app/material-timepicker/ngx-material-timepicker.component.ts +++ b/src/app/material-timepicker/ngx-material-timepicker.component.ts @@ -74,7 +74,9 @@ export class NgxMaterialTimepickerComponent implements OnInit, OnDestroy { } @Output() timeSet = new EventEmitter(); + @Output() opened = new EventEmitter(); @Output() closed = new EventEmitter(); + @Output() hourSelected = new EventEmitter(); @ViewChild('timepickerww') timepickerComponent: ElementRef; @@ -133,6 +135,11 @@ export class NgxMaterialTimepickerComponent implements OnInit, OnDestroy { this.timepickerService.hour = hour; } + onHourSelected(hour: number): void { + this.changeTimeUnit(TimeUnit.MINUTE); + this.hourSelected.next(hour); + } + onMinuteChange(minute: ClockFaceTime): void { this.timepickerService.minute = minute; } @@ -141,11 +148,11 @@ export class NgxMaterialTimepickerComponent implements OnInit, OnDestroy { this.timepickerService.period = period; } - changeTimeUnit(unit: TimeUnit) { + changeTimeUnit(unit: TimeUnit): void { this.activeTimeUnit = unit; } - setTime() { + setTime(): void { this.timeSet.next(this.timepickerService.getFullTime(this.format)); this.close(); } @@ -155,12 +162,13 @@ export class NgxMaterialTimepickerComponent implements OnInit, OnDestroy { time, this.minTime as Moment, this.maxTime as Moment, this.format, this.minutesGap); } - open() { + open(): void { this.isOpened = true; this.animationState = AnimationState.ENTER; + this.opened.next(); } - close() { + close(): void { this.animationState = AnimationState.LEAVE; } diff --git a/src/app/material-timepicker/services/ngx-material-timepicker.service.spec.ts b/src/app/material-timepicker/services/ngx-material-timepicker.service.spec.ts index 419909d4..01a2350e 100755 --- a/src/app/material-timepicker/services/ngx-material-timepicker.service.spec.ts +++ b/src/app/material-timepicker/services/ngx-material-timepicker.service.spec.ts @@ -3,6 +3,7 @@ import {ClockFaceTime} from '../models/clock-face-time.interface'; import {NgxMaterialTimepickerService} from './ngx-material-timepicker.service'; import {TimePeriod} from '../models/time-period.enum'; import * as moment from 'moment'; +import { TimeAdapter } from './time-adapter'; describe('NgxMaterialTimepickerService', () => { const DEFAULT_HOUR: ClockFaceTime = { @@ -104,4 +105,14 @@ describe('NgxMaterialTimepickerService', () => { expect(selectedMinute).toEqual({...DEFAULT_MINUTE, time: 10}); expect(selectedPeriod).toBe(TimePeriod.AM); }); + + it('should call console error', () => { + const minutesGap = 5; + const min = TimeAdapter.convertTimeToMoment('11:00 pm'); + const max = TimeAdapter.convertTimeToMoment('11:50 pm'); + const spy = spyOn(console, 'error'); + + timepickerService.setDefaultTimeIfAvailable('11:43 pm', min, max, 12, minutesGap); + expect(spy).toHaveBeenCalled(); + }); });