import { Directive, ElementRef, Input, OnInit, EventEmitter, Output, forwardRef, ChangeDetectorRef, KeyValueDiffer, KeyValueDiffers, DoCheck, OnDestroy, HostListener, HostBinding, Inject, ContentChild } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; declare var $: any; import * as moment from 'moment'; @Directive({ selector: '[NgTempusdominusBootstrapInput]', exportAs: 'NgTempusdominusBootstrapInput', providers: [ {provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgTempusdominusBootstrapInputDirective), multi: true} ] }) export class NgTempusdominusBootstrapInputDirective implements OnInit, OnDestroy, DoCheck { _value: moment.Moment; private _options: any = {}; @Input() set options(value) { if (value !== null) { this._options = value; } } get options(): any { return this._options; } @Output() click: EventEmitter = new EventEmitter(); private dpinitialized: boolean; private inputOnly: boolean; dpElement; private optionsDiffer: KeyValueDiffer; private _onTouched: any = () => { } private _onChange: any = () => { } constructor( private changeDetector: ChangeDetectorRef, protected el: ElementRef, private differs: KeyValueDiffers ) { this.dpinitialized = false; const $parent = $(el.nativeElement.parentNode); this.inputOnly = !$parent.hasClass('input-group'); this.dpElement = $parent.hasClass('input-group') ? $parent : $(el.nativeElement); } @HostListener('blur') onBlur() { this._onTouched(); } @HostListener('focus') onFocus() { if (this.inputOnly) { this.dpElement.datetimepicker('toggle'); } } /** * For click outside of input, for input only * @param event event object * @param targetElement target element object */ @HostListener('document:click', ['$event', '$event.target']) outsideClick(event, targetElement: HTMLElement): void { if (!targetElement || !this.inputOnly || this.options.inline) { return; } const clickedInside = this.el.nativeElement.contains(targetElement); if (!clickedInside) { this.dpElement.datetimepicker('hide'); } } get value() { return this._value || null; } set value(val) { this._value = val; this._onChange(val); if (val) { this._onTouched(); } this.changeDetector.markForCheck(); } writeValue(value) { // if we have a previous value and current value is falsy // clear the picker if (this._value && !value) { this.value = null; this.dpElement.datetimepicker('clear'); } this.value = value; this.setDpValue(value); } registerOnChange(fn) { this._onChange = fn; } registerOnTouched(fn: () => any): void { this._onTouched = fn; } private setDpValue(val) { if (!this.dpinitialized) { return; } if (val) { this.dpElement.datetimepicker('date', this.value); } } setDisabledState(isDisabled: boolean): void { if (isDisabled) { this.dpElement.datetimepicker('disable'); return; } this.dpElement.datetimepicker('enable'); } ngOnInit(): void { this.dpinitialized = true; this.dpElement.datetimepicker(this.options); this.dpElement.on('change.datetimepicker', (e) => { if (e.date && e.date !== this.value) { this.value = e.date || null; } else { const date = moment(e.target.value, this.options.format); if (date.isValid()) { this.value = date; } } }); this.dpElement.on('click', () => { this.click.emit(); }); this.optionsDiffer = this.differs.find(this.options).create(); } ngDoCheck() { if (this.dpinitialized) { const changes = this.optionsDiffer.diff(this.options); if (changes) { $.map(this.options, (value, key) => { this.dpElement.datetimepicker(key, value); }); } } } ngOnDestroy(): void { this.dpElement.datetimepicker('destroy'); } toggle(): void { this.dpElement.datetimepicker('toggle'); } } /** * Allows the datepicker to be toggled via click. * */ @Directive({ selector: '[NgTempusdominusBootstrapToggle]' }) export class NgTempusdominusBootstrapToggleDirective { @HostBinding('style.cursor') cursor: String = 'pointer'; @HostListener('click') click() { this.toggleOpen(); } constructor( @Inject(forwardRef(() => NgTempusdominusBootstrapDirective)) public tempusDominus, elementRef: ElementRef ) { } toggleOpen() { this.tempusDominus.toggle(); } } /** * Container * */ @Directive({ selector: '[NgTempusdominusBootstrap]' }) export class NgTempusdominusBootstrapDirective { @ContentChild(NgTempusdominusBootstrapInputDirective) private _input: NgTempusdominusBootstrapInputDirective; /** * For click outside of container, * @param event event object * @param targetElement target element object */ @HostListener('document:click', ['$event', '$event.target']) outsideClick(event, targetElement: HTMLElement): void { if (!targetElement) { return; } const clickedInside = this.el.nativeElement.contains(targetElement); if (!clickedInside) { this._input.dpElement.datetimepicker('hide'); } } constructor(private el: ElementRef) { } toggle() { this._input.toggle(); } }