1 | import { Directive, ElementRef, EventEmitter, Input, Output, Renderer2, ViewContainerRef } from '@angular/core';
|
2 | import { ComponentLoaderFactory } from 'ngx-bootstrap/component-loader';
|
3 | import { BehaviorSubject, Subject } from 'rxjs';
|
4 | import { filter, takeUntil } from 'rxjs/operators';
|
5 | import { BsDatepickerConfig } from './bs-datepicker.config';
|
6 | import { BsDatepickerContainerComponent } from './themes/bs/bs-datepicker-container.component';
|
7 | import { checkBsValue } from './utils/bs-calendar-utils';
|
8 | export class BsDatepickerDirective {
|
9 | constructor(_config, _elementRef, _renderer, _viewContainerRef, cis) {
|
10 | this._config = _config;
|
11 | this._elementRef = _elementRef;
|
12 | this._renderer = _renderer;
|
13 | |
14 |
|
15 |
|
16 | this.placement = 'bottom';
|
17 | |
18 |
|
19 |
|
20 |
|
21 | this.triggers = 'click';
|
22 | |
23 |
|
24 |
|
25 | this.outsideClick = true;
|
26 | |
27 |
|
28 |
|
29 | this.container = 'body';
|
30 | this.outsideEsc = true;
|
31 | this.isDestroy$ = new Subject();
|
32 | |
33 |
|
34 |
|
35 | this.isDisabled = false;
|
36 | |
37 |
|
38 |
|
39 | this.bsValueChange = new EventEmitter();
|
40 | this._subs = [];
|
41 | this._dateInputFormat$ = new Subject();
|
42 |
|
43 | Object.assign(this, this._config);
|
44 | this._datepicker = cis.createLoader(_elementRef, _viewContainerRef, _renderer);
|
45 | this.onShown = this._datepicker.onShown;
|
46 | this.onHidden = this._datepicker.onHidden;
|
47 | this.isOpen$ = new BehaviorSubject(this.isOpen);
|
48 | }
|
49 | |
50 |
|
51 |
|
52 | get isOpen() {
|
53 | return this._datepicker.isShown;
|
54 | }
|
55 | set isOpen(value) {
|
56 | this.isOpen$.next(value);
|
57 | }
|
58 | |
59 |
|
60 |
|
61 | set bsValue(value) {
|
62 | if (this._bsValue && value && this._bsValue.getTime() === value.getTime()) {
|
63 | return;
|
64 | }
|
65 | if (!this._bsValue && value) {
|
66 | const now = new Date();
|
67 | value.setMilliseconds(now.getMilliseconds());
|
68 | value.setSeconds(now.getSeconds());
|
69 | value.setMinutes(now.getMinutes());
|
70 | value.setHours(now.getHours());
|
71 | }
|
72 | this._bsValue = value;
|
73 | this.bsValueChange.emit(value);
|
74 | }
|
75 | get dateInputFormat$() {
|
76 | return this._dateInputFormat$;
|
77 | }
|
78 | get bsConfig() {
|
79 | return this._bsConfig;
|
80 | }
|
81 | |
82 |
|
83 |
|
84 | set bsConfig(bsConfig) {
|
85 | this._bsConfig = bsConfig;
|
86 | this.setConfig();
|
87 | this._dateInputFormat$.next(bsConfig && bsConfig.dateInputFormat);
|
88 | }
|
89 | ngOnInit() {
|
90 | this._datepicker.listen({
|
91 | outsideClick: this.outsideClick,
|
92 | outsideEsc: this.outsideEsc,
|
93 | triggers: this.triggers,
|
94 | show: () => this.show()
|
95 | });
|
96 | this.setConfig();
|
97 | }
|
98 | ngOnChanges(changes) {
|
99 | if (!this._datepickerRef || !this._datepickerRef.instance) {
|
100 | return;
|
101 | }
|
102 | if (changes.minDate) {
|
103 | this._datepickerRef.instance.minDate = this.minDate;
|
104 | }
|
105 | if (changes.maxDate) {
|
106 | this._datepickerRef.instance.maxDate = this.maxDate;
|
107 | }
|
108 | if (changes.daysDisabled) {
|
109 | this._datepickerRef.instance.daysDisabled = this.daysDisabled;
|
110 | }
|
111 | if (changes.datesDisabled) {
|
112 | this._datepickerRef.instance.datesDisabled = this.datesDisabled;
|
113 | }
|
114 | if (changes.datesEnabled) {
|
115 | this._datepickerRef.instance.datesEnabled = this.datesEnabled;
|
116 | }
|
117 | if (changes.isDisabled) {
|
118 | this._datepickerRef.instance.isDisabled = this.isDisabled;
|
119 | }
|
120 | if (changes.dateCustomClasses) {
|
121 | this._datepickerRef.instance.dateCustomClasses = this.dateCustomClasses;
|
122 | }
|
123 | if (changes.dateTooltipTexts) {
|
124 | this._datepickerRef.instance.dateTooltipTexts = this.dateTooltipTexts;
|
125 | }
|
126 | }
|
127 | ngAfterViewInit() {
|
128 | this.isOpen$.pipe(filter(isOpen => isOpen !== this.isOpen), takeUntil(this.isDestroy$))
|
129 | .subscribe(() => this.toggle());
|
130 | }
|
131 | |
132 |
|
133 |
|
134 |
|
135 | show() {
|
136 | if (this._datepicker.isShown) {
|
137 | return;
|
138 | }
|
139 | this.setConfig();
|
140 | this._datepickerRef = this._datepicker
|
141 | .provide({ provide: BsDatepickerConfig, useValue: this._config })
|
142 | .attach(BsDatepickerContainerComponent)
|
143 | .to(this.container)
|
144 | .position({ attachment: this.placement })
|
145 | .show({ placement: this.placement });
|
146 |
|
147 | this._subs.push(this.bsValueChange.subscribe((value) => {
|
148 | if (this._datepickerRef) {
|
149 | this._datepickerRef.instance.value = value;
|
150 | }
|
151 | }));
|
152 |
|
153 | if (this._datepickerRef) {
|
154 | this._subs.push(this._datepickerRef.instance.valueChange.subscribe((value) => {
|
155 | this.bsValue = value;
|
156 | this.hide();
|
157 | }));
|
158 | }
|
159 | }
|
160 | |
161 |
|
162 |
|
163 |
|
164 | hide() {
|
165 | if (this.isOpen) {
|
166 | this._datepicker.hide();
|
167 | }
|
168 | for (const sub of this._subs) {
|
169 | sub.unsubscribe();
|
170 | }
|
171 | if (this._config.returnFocusToInput) {
|
172 | this._renderer.selectRootElement(this._elementRef.nativeElement).focus();
|
173 | }
|
174 | }
|
175 | |
176 |
|
177 |
|
178 |
|
179 | toggle() {
|
180 | if (this.isOpen) {
|
181 | return this.hide();
|
182 | }
|
183 | this.show();
|
184 | }
|
185 | |
186 |
|
187 |
|
188 | setConfig() {
|
189 | this._config = Object.assign({}, this._config, this.bsConfig, {
|
190 | value: checkBsValue(this._bsValue, this.maxDate || this.bsConfig && this.bsConfig.maxDate),
|
191 | isDisabled: this.isDisabled,
|
192 | minDate: this.minDate || this.bsConfig && this.bsConfig.minDate,
|
193 | maxDate: this.maxDate || this.bsConfig && this.bsConfig.maxDate,
|
194 | daysDisabled: this.daysDisabled || this.bsConfig && this.bsConfig.daysDisabled,
|
195 | dateCustomClasses: this.dateCustomClasses || this.bsConfig && this.bsConfig.dateCustomClasses,
|
196 | dateTooltipTexts: this.dateTooltipTexts || this.bsConfig && this.bsConfig.dateTooltipTexts,
|
197 | datesDisabled: this.datesDisabled || this.bsConfig && this.bsConfig.datesDisabled,
|
198 | datesEnabled: this.datesEnabled || this.bsConfig && this.bsConfig.datesEnabled,
|
199 | minMode: this.minMode || this.bsConfig && this.bsConfig.minMode
|
200 | });
|
201 | }
|
202 | ngOnDestroy() {
|
203 | this._datepicker.dispose();
|
204 | this.isOpen$.next(false);
|
205 | if (this.isDestroy$) {
|
206 | this.isDestroy$.next();
|
207 | this.isDestroy$.complete();
|
208 | }
|
209 | }
|
210 | }
|
211 | BsDatepickerDirective.decorators = [
|
212 | { type: Directive, args: [{
|
213 | selector: '[bsDatepicker]',
|
214 | exportAs: 'bsDatepicker'
|
215 | },] }
|
216 | ];
|
217 | BsDatepickerDirective.ctorParameters = () => [
|
218 | { type: BsDatepickerConfig },
|
219 | { type: ElementRef },
|
220 | { type: Renderer2 },
|
221 | { type: ViewContainerRef },
|
222 | { type: ComponentLoaderFactory }
|
223 | ];
|
224 | BsDatepickerDirective.propDecorators = {
|
225 | placement: [{ type: Input }],
|
226 | triggers: [{ type: Input }],
|
227 | outsideClick: [{ type: Input }],
|
228 | container: [{ type: Input }],
|
229 | outsideEsc: [{ type: Input }],
|
230 | onShown: [{ type: Output }],
|
231 | onHidden: [{ type: Output }],
|
232 | isDisabled: [{ type: Input }],
|
233 | minDate: [{ type: Input }],
|
234 | maxDate: [{ type: Input }],
|
235 | minMode: [{ type: Input }],
|
236 | daysDisabled: [{ type: Input }],
|
237 | datesDisabled: [{ type: Input }],
|
238 | datesEnabled: [{ type: Input }],
|
239 | dateCustomClasses: [{ type: Input }],
|
240 | dateTooltipTexts: [{ type: Input }],
|
241 | bsValueChange: [{ type: Output }],
|
242 | isOpen: [{ type: Input }],
|
243 | bsValue: [{ type: Input }],
|
244 | bsConfig: [{ type: Input }]
|
245 | };
|
246 |
|
\ | No newline at end of file |