import './two-datepicker.css'; import { Ut } from "../../utils/Ut"; import { El } from "../../utils/dom"; import { Cancelable } from '../cancelable'; import { DatePicker } from '../date-picker'; import { Boot } from '../../core/Boot'; export class TwoDatePicker { #hasRendered = false; #isOpened = false; #isInput = false; #isToggled = false; constructor(target, opts) { this.target = target; if (this.target.dxWidget() || this.target.dxData('two_datepicker')) { return; } this.target.dxData('two_datepicker', this); this.target.dxWidget(this); Boot.addWidget(this); this.opts = { ... { style : 'normal', disabled : false, fullMonth : true, navDisabled : false, anim : true, dateFormat : 'dd/mm/yyyy', valueFormat : 'dd/mm/yyyy', valSeparator: '-', dateSeparator: '-', locales : 'ro-RO', defaultDate : null, render : true, showOnClick : true }, ... opts }; this.ekey = Ut.nextKey(); if (this.target.tagName.toLowerCase() === 'input') { this.#isInput = true; if (this.target.type === 'text') { this.#isToggled = true; this.target.setAttribute('autocomplete', 'off'); this.target.inputmode = 'none'; this.target.readOnly = true; new Cancelable(this.target); } this.#bindTargetEvents(); } const dpOpts = { style : this.opts.style, disabled : this.opts.disabled, fullMonth : this.opts.fullMonth, navDisabled : this.opts.navDisabled, locales : this.opts.locales, dateFormat : this.opts.dateFormat, valueFormat : this.opts.valueFormat, render : false }; let tokenVal = []; if (this.#isInput) { const defaultVal = this.target.value.trim(); if (defaultVal) { tokenVal = defaultVal.split(this.opts.dateSeparator); } } if (this.opts.defaultDate && !tokenVal.length) { tokenVal = this.opts.defaultDate.split(this.opts.valSeparator); } const hasVal = tokenVal.length === 2; this.firstDp = new DatePicker(El('div', { className: 'ui-col' }), { ... dpOpts, defaultDate: hasVal ? tokenVal[0] : null, onSelect: (_, val) => this.#selectDate(0, val) }); this.secondDp = new DatePicker(El('div', { className: 'ui-col' }), { ... dpOpts, defaultDate: hasVal ? tokenVal[1] : null, disabled: !hasVal, onSelect: (_, val) => this.#selectDate(1, val) }); if (!this.#isToggled && this.opts.render) { this.#initUi(); } } render() { if (this.#hasRendered) { return; } this.#initUi(); } #bindTargetEvents() { const that = this; if (this.#isInput) { // this.target.dxOn('keydown.two_datepicker paste.two_datepicker', e => e.preventDefault()); this.target.dxOn('restore.two_datepicker', (_, t) => this.restoreValue(t.value, this.opts.dateSeparator)); } if (this.#isToggled && this.opts.showOnClick) { this.target.dxOn('click.two_datepicker', e => { e.stopPropagation(); //if (!that.opts.hiddenMode) { that.show(); //} }); } } #bindUiEvents() { const that = this; if (!this.#isToggled) { return; } document.dxOn(`pointerdown.twodatepicker.${this.ekey}`, e => !this.target.contains(e.target) && !this.el.contains(e.target) && this.hide() ); let tm = null; // Resize, Scroll, Orientation window Handlers window.dxOn(`resize.two_datepicker.${this.ekey} orientationchange.two_datepicker.${this.ekey}`, _ => { if (tm) { clearTimeout(tm); tm = null; } tm = setTimeout(_ => that.#reposition(), 100); }); } #initUi() { this.el = El('div', { className: 'sp-two-datepicker' }); this.firstDp.render(); this.secondDp.render(); this.el.append(this.firstDp.target); this.el.append(this.secondDp.target); if (this.#isInput) { if (this.#isToggled) { this.el.classList.add('toggled', 'hidden'); document.body.append(this.el); } else { this.target.after(this.el); } this.target.setAttribute('autocomplete', 'off'); } else { this.target.append(this.el); } this.#bindUiEvents(); this.#hasRendered = true; Ut.trigger(this.opts.onInit, this); } #selectDate(index, val) { Ut.trigger(this.opts.onSelect, this, index, val); if (index === 0) { this.secondDp.enable(); this.secondDp.clear(); this.secondDp.setDateRange({ minDate: this.firstDp.selectedDate }); return; } this.#setValue(); this.hide(); Ut.trigger(this.opts.onChange, this); this.target.dxTrigger('changed'); } #setValue() { const clear = !this.firstDp.selectedDate || !this.secondDp.selectedDate; this.value = !clear ? `${this.firstDp.value}${this.opts.valSeparator}${this.secondDp.value}` : ''; this.displayValue = !clear ? `${this.firstDp.displayValue}${this.opts.dateSeparator}${this.secondDp.displayValue}` : ''; if (this.#isInput) { this.target.value = this.displayValue; } } show() { if (this.#isOpened) { return; } if (!this.#hasRendered) { this.#initUi(); if (this.value) { this.secondDp.setDateRange({ minDate: this.firstDp.selectedDate }); this.secondDp.enable(); } } this.el.classList.remove('hidden'); if (this.opts.anim) { this.el.classList.add('visible'); } this.#reposition(); this.#isOpened = true; Ut.trigger(this.opts.onShow, this); } hide() { if (this.#isOpened) { this.el.classList.add('hidden'); if (this.opts.anim) { this.el.classList.remove('visible'); } this.#isOpened = false; Ut.trigger(this.opts.onHide, this); } } #reposition() { let left = Math.round(this.target.dxOffset().left); if ((this.el.clientWidth + left) > window.innerWidth) { left = 0; } this.el.dxCss({ top : (Math.round(this.target.dxOffset().top) + this.target.clientHeight + 2) + 'px', left : left + 'px', }); } clear() { this.firstDp.clear(); this.secondDp.clear(); this.secondDp.disable(); this.#setValue(); if (this.#isToggled) { this.target.dxData('cancelable').iconHandler.classList.add('hide'); this.hide(); } } getValue() { return this.value; } restoreValue(val, separator = this.opts.valSeparator) { if (!val) { return false; } if (!Array.isArray(val)) { val = val.split(separator); } if (val.length != 2) { return false; } const [ firstDate, secDate ] = val; this.firstDp.restoreValue(firstDate); this.secondDp.restoreValue(secDate); this.#setValue(); if (this.#hasRendered) { this.secondDp.setDateRange({ minDate: this.firstDp.selectedDate }); this.secondDp.enable(); } Ut.trigger(this.opts.onChange, this); this.target.dxTrigger('changed'); return true; } destroy() { this.firstDp.destroy(); this.secondDp.destroy(); if (this.#hasRendered) { this.el.remove(); if (this.#isToggled) { document.dxOff(`pointerdown.twodatepicker.${this.ekey}`); window.dxOff(`resize.two_datepicker.${this.ekey} orientationchange.two_datepicker.${this.ekey}`); } } this.target.dxRemoveData('two_datepicker'); this.target.dxRemoveWidget(); Ut.trigger(this.opts.onDestroy, this); } }