Files
david/src/widgets/two-datepicker/TwoDatepicker.js
T
2026-02-16 04:29:59 +02:00

362 lines
7.0 KiB
JavaScript

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);
}
}