diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ff5b7bb..ca5ac8a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file +## 2.8.3 (2018-11-02) + +### Fixes + +* fix(timepicker output): fix format appearance, closes [(#62)](https://github.com/Agranom/ngx-material-timepicker/issues/62) +* fix(timepicker clock face): fix touch events, closes [(#61)](https://github.com/Agranom/ngx-material-timepicker/issues/61) +* fix(timepicker dial): change focus on dial (hour <=> minute) + ## 2.8.2 (2018-10-29) ### Fixes diff --git a/package.json b/package.json index 64e06353..af09485d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ngx-material-timepicker", "description": "Handy material design timepicker for angular", - "version": "2.8.2", + "version": "2.8.3", "license": "MIT", "author": "Vitalii Boiko ", "keywords": [ diff --git a/src/app/app.component.html b/src/app/app.component.html index 1716c3bb..3e9b65d8 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -175,7 +175,7 @@

Examples

diff --git a/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.html b/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.html index aed30808..3619caec 100644 --- a/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.html +++ b/src/app/material-timepicker/components/timepicker-dial-control/ngx-material-timepicker-dial-control.component.html @@ -2,4 +2,4 @@ + (blur)="revertTimeAndFormat()" [readonly]="!isEditable" [timepickerAutofocus]="isActive"> 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 df432ad3..f642f83c 100644 --- 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 @@ -6,6 +6,7 @@ import { HostListener, Input, OnChanges, + OnDestroy, Output, SimpleChanges, ViewChild @@ -29,7 +30,7 @@ const CLOCK_HAND_STYLES = { templateUrl: './ngx-material-timepicker-face.component.html', styleUrls: ['./ngx-material-timepicker-face.component.scss'] }) -export class NgxMaterialTimepickerFaceComponent implements AfterViewInit, OnChanges { +export class NgxMaterialTimepickerFaceComponent implements AfterViewInit, OnChanges, OnDestroy { timeUnit = TimeUnit; @@ -49,9 +50,12 @@ export class NgxMaterialTimepickerFaceComponent implements AfterViewInit, OnChan @ViewChild('clockHand') clockHand: ElementRef; private isStarted: boolean; + private touchStartHandler: () => any; + private touchEndHandler: () => any; ngAfterViewInit() { this.setClockHandPosition(); + this.addTouchEvents(); } ngOnChanges(changes: SimpleChanges) { @@ -77,7 +81,6 @@ export class NgxMaterialTimepickerFaceComponent implements AfterViewInit, OnChan return time.time; } - @HostListener('touchstart', ['$event']) @HostListener('mousedown', ['$event']) onMousedown(e: MouseEvent | TouchEvent) { e.preventDefault(); @@ -123,7 +126,6 @@ export class NgxMaterialTimepickerFaceComponent implements AfterViewInit, OnChan } - @HostListener('touchend', ['$event']) @HostListener('mouseup', ['$event']) onMouseup(e: MouseEvent | TouchEvent) { e.preventDefault(); @@ -138,6 +140,23 @@ export class NgxMaterialTimepickerFaceComponent implements AfterViewInit, OnChan return ((this.selectedTime.time === minute) && (minute % (this.minutesGap || 5) === 0)) && !this.isClockFaceDisabled; } + ngOnDestroy() { + this.removeTouchEvents(); + } + + private addTouchEvents(): void { + this.touchStartHandler = this.onMousedown.bind(this); + this.touchEndHandler = this.onMouseup.bind(this); + + this.clockFace.nativeElement.addEventListener('touchstart', this.touchStartHandler); + this.clockFace.nativeElement.addEventListener('touchend', this.touchEndHandler); + } + + private removeTouchEvents(): void { + this.clockFace.nativeElement.removeEventListener('touchstart', this.touchStartHandler); + this.clockFace.nativeElement.removeEventListener('touchend', this.touchEndHandler); + } + private setClockHandPosition(): void { if (this.format === 24) { if (this.selectedTime.time > 12 || this.selectedTime.time === '00') { diff --git a/src/app/material-timepicker/directives/autofocus.directive.ts b/src/app/material-timepicker/directives/autofocus.directive.ts new file mode 100644 index 00000000..f42dc843 --- /dev/null +++ b/src/app/material-timepicker/directives/autofocus.directive.ts @@ -0,0 +1,26 @@ +import {Directive, ElementRef, Inject, Input, OnChanges, OnDestroy, Optional} from '@angular/core'; +import {DOCUMENT} from '@angular/common'; + +@Directive({ + selector: '[timepickerAutofocus]' +}) +export class AutofocusDirective implements OnChanges, OnDestroy { + + @Input('timepickerAutofocus') isFocusActive: boolean; + + private activeElement: HTMLElement; + + constructor(private element: ElementRef, @Optional() @Inject(DOCUMENT) private document: any) { + this.activeElement = this.document.activeElement; + } + + ngOnChanges() { + if (this.isFocusActive) { + this.element.nativeElement.focus(); + } + } + + ngOnDestroy() { + this.activeElement.focus(); + } +} diff --git a/src/app/material-timepicker/directives/focus-anchor.directive.spec.ts b/src/app/material-timepicker/directives/focus-anchor.directive.spec.ts deleted file mode 100644 index 1adc2fc5..00000000 --- a/src/app/material-timepicker/directives/focus-anchor.directive.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {Component, DebugElement} from '@angular/core'; -import {ComponentFixture, inject, TestBed} from '@angular/core/testing'; -import {By} from '@angular/platform-browser'; -import {DOCUMENT} from '@angular/common'; -import {FocusAnchorDirective} from './focus-anchor.directive'; - -@Component({ - template: ` -
-

Focusable element

-
- ` -}) -class TestComponent { -} - -describe('FocusAnchorDirective', () => { - let component: TestComponent; - let fixture: ComponentFixture; - let focusableEl: DebugElement; - - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - declarations: [TestComponent, FocusAnchorDirective] - }).createComponent(TestComponent); - component = fixture.componentInstance; - focusableEl = fixture.debugElement.query(By.directive(FocusAnchorDirective)); - fixture.detectChanges(); - }); - - it('focus should be on the element with focusAnchor directive after view' + - ' init and return to previous active element after destroy element with focusAnchor directive ', - inject([DOCUMENT], (document: Document) => { - const body = document.activeElement; - fixture.whenRenderingDone().then(() => { - expect(document.activeElement).toEqual(focusableEl.nativeElement); - }); - fixture.destroy(); - expect(document.activeElement).toEqual(body); - })); -}); diff --git a/src/app/material-timepicker/directives/focus-anchor.directive.ts b/src/app/material-timepicker/directives/focus-anchor.directive.ts deleted file mode 100644 index 501171fb..00000000 --- a/src/app/material-timepicker/directives/focus-anchor.directive.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {AfterViewInit, Directive, ElementRef, Inject, OnDestroy, Optional} from '@angular/core'; -import {DOCUMENT} from '@angular/common'; - -@Directive({ - selector: '[focusAnchor]' -}) -export class FocusAnchorDirective implements AfterViewInit, OnDestroy { - - private activeElement: HTMLElement; - private element: HTMLElement; - - constructor(@Optional() @Inject(DOCUMENT) private document: any, - elementRef: ElementRef) { - this.element = elementRef.nativeElement; - } - - ngAfterViewInit() { - this.activeElement = this.document.activeElement; - // To avoid an error ExpressionChangedAfterItHasBeenCheckedError - setTimeout(() => this.element.focus()); - } - - ngOnDestroy() { - // To avoid an error ExpressionChangedAfterItHasBeenCheckedError - setTimeout(() => this.activeElement.focus()); - } -} diff --git a/src/app/material-timepicker/directives/ngx-timepicker.directive.ts b/src/app/material-timepicker/directives/ngx-timepicker.directive.ts index f92a9121..26dab0f7 100644 --- a/src/app/material-timepicker/directives/ngx-timepicker.directive.ts +++ b/src/app/material-timepicker/directives/ngx-timepicker.directive.ts @@ -30,43 +30,18 @@ const VALUE_ACCESSOR = { }, }) export class TimepickerDirective implements ControlValueAccessor, OnDestroy, OnChanges { - @Input() - set value(value: string) { - if (!value) { - this._value = ''; - this.updateInputValue(); - return; - } - const time = TimeAdapter.formatTime(value, this._format); - if (TimeAdapter.isTimeAvailable(time, this._min, this._max, 'minutes')) { - this._value = time; - this.updateInputValue(); - return; - } - console.warn('Selected time doesn\'t match min or max value'); - } - get value(): string { - return this._value; + @Input() + set format(value: number) { + this._format = value === 24 ? 24 : 12; } - private _value = ''; - get format(): number { return this._format; } - @Input() - set format(value: number) { - this._format = value === 24 ? 24 : 12; - } - private _format = 12; - get min(): string | Moment { - return this._min; - } - @Input() set min(value: string | Moment) { if (typeof value === 'string') { @@ -76,12 +51,12 @@ export class TimepickerDirective implements ControlValueAccessor, OnDestroy, OnC this._min = value; } - private _min: string | Moment; - - get max(): string | Moment { - return this._max; + get min(): string | Moment { + return this._min; } + private _min: string | Moment; + @Input() set max(value: string | Moment) { if (typeof value === 'string') { @@ -91,9 +66,33 @@ export class TimepickerDirective implements ControlValueAccessor, OnDestroy, OnC this._max = value; } + get max(): string | Moment { + return this._max; + } + private _max: string | Moment; + @Input() + set value(value: string) { + if (!value) { + this._value = ''; + this.updateInputValue(); + return; + } + const time = TimeAdapter.formatTime(value, this._format); + if (TimeAdapter.isTimeAvailable(time, this._min, this._max, 'minutes')) { + this._value = time; + this.updateInputValue(); + return; + } + console.warn('Selected time doesn\'t match min or max value'); + } + get value(): string { + return this._value; + } + + private _value = ''; @Input('ngxTimepicker') set timepicker(picker: NgxMaterialTimepickerComponent) { diff --git a/src/app/material-timepicker/ngx-material-timepicker.component.html b/src/app/material-timepicker/ngx-material-timepicker.component.html index 4b31d754..30813c47 100644 --- a/src/app/material-timepicker/ngx-material-timepicker.component.html +++ b/src/app/material-timepicker/ngx-material-timepicker.component.html @@ -1,7 +1,6 @@
-
+