updates
This commit is contained in:
@@ -4,22 +4,26 @@ import { Ut } from "../../utils/Ut";
|
||||
import { El } from "../../utils/dom";
|
||||
import { Cancelable } from '../cancelable';
|
||||
import { DatePicker } from '../date-picker';
|
||||
import { Stack } from '../../core/Stack';
|
||||
import { Boot } from '../../core/Boot';
|
||||
|
||||
export class TwoDatePicker {
|
||||
|
||||
/**
|
||||
* TwoDatePicker Constructor
|
||||
*/
|
||||
constructor(target, opts, events) {
|
||||
#hasRendered = false;
|
||||
#isOpened = false;
|
||||
#isInput = false;
|
||||
#isToggled = false;
|
||||
|
||||
constructor(target, opts) {
|
||||
|
||||
this.target = target;
|
||||
|
||||
if (this.target.dxData('two_datepicker')) {
|
||||
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',
|
||||
@@ -27,320 +31,331 @@ export class TwoDatePicker {
|
||||
fullMonth : true,
|
||||
navDisabled : false,
|
||||
anim : true,
|
||||
dateFormat : 'dd/mm/yyyy',
|
||||
valueFormat : 'dd-mm-yyyy',
|
||||
valSeparator: '-',
|
||||
dateSeparator: ' - ',
|
||||
locales : 'ro-RO',
|
||||
cancelable : true,
|
||||
hiddenMode : false,
|
||||
defaultDate : null,
|
||||
render : true,
|
||||
showOnClick : true
|
||||
}, ... opts };
|
||||
|
||||
this.events = events || {};
|
||||
this.ekey = Ut.nextKey();
|
||||
|
||||
this.isDisabled = this.opts.disabled;
|
||||
if (this.target.tagName.toLowerCase() === 'input') {
|
||||
|
||||
if (this.target.tagName.toLowerCase() == 'input') {
|
||||
this.#isInput = true;
|
||||
|
||||
this.isInput = true;
|
||||
if (this.target.type === 'text') {
|
||||
|
||||
this.#isToggled = 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();
|
||||
}
|
||||
|
||||
this.create();
|
||||
|
||||
Stack.add(this);
|
||||
|
||||
this.setEvents();
|
||||
|
||||
this.restoreValue(this.target.dxVal());
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Create UI
|
||||
*/
|
||||
create() {
|
||||
|
||||
const that = this;
|
||||
|
||||
this.ui = El('div', { className: 'sp-two-datepicker' });
|
||||
|
||||
let firstCol = El('div', { className: 'ui-col' });
|
||||
let secondCol = El('div', { className: 'ui-col' });
|
||||
|
||||
this.ui.append(firstCol);
|
||||
this.ui.append(secondCol);
|
||||
|
||||
const dpOpts = {
|
||||
style : this.opts.style,
|
||||
disabled : this.opts.disabled,
|
||||
fullMonth : this.opts.fullMonth,
|
||||
navDisabled : this.opts.navDisabled,
|
||||
locales : this.opts.locales
|
||||
locales : this.opts.locales,
|
||||
dateFormat : this.opts.dateFormat,
|
||||
valueFormat : this.opts.valueFormat,
|
||||
render : false
|
||||
};
|
||||
|
||||
this.datepicker = [];
|
||||
let tokenVal = [];
|
||||
|
||||
new DatePicker(firstCol, dpOpts, {
|
||||
init: datepicker => that.datepicker[0] = datepicker,
|
||||
onSelect: (_, val) => this.selectDate(0, val)
|
||||
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)
|
||||
});
|
||||
|
||||
new DatePicker(secondCol, dpOpts, {
|
||||
init: datepicker => that.datepicker[1] = datepicker,
|
||||
onSelect: (_, val) => this.selectDate(1, 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.isInput) {
|
||||
if (!this.#isToggled && this.opts.render) {
|
||||
this.#initUi();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isToggled) {
|
||||
render() {
|
||||
|
||||
this.ui.classList.add('toggled', 'hidden');
|
||||
if (this.#hasRendered) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.opts.cancelable && !this.target.dxData('cancelable') ) {
|
||||
new Cancelable(this.target);
|
||||
}
|
||||
this.#initUi();
|
||||
}
|
||||
|
||||
document.body.append(this.ui);
|
||||
#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.ui);
|
||||
this.target.after(this.el);
|
||||
}
|
||||
|
||||
this.target.setAttribute('autocomplete', 'off');
|
||||
}
|
||||
else {
|
||||
this.target.append(this.ui);
|
||||
this.target.append(this.el);
|
||||
}
|
||||
|
||||
this.#bindUiEvents();
|
||||
|
||||
this.#hasRendered = true;
|
||||
|
||||
Ut.trigger(this.opts.onInit, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Select Value
|
||||
*/
|
||||
selectDate(index, val) {
|
||||
#selectDate(index, val) {
|
||||
|
||||
Ut.trigger(this.opts.onSelect, this, index, val);
|
||||
|
||||
const firstDp = this.datepicker[0];
|
||||
const secondDp = this.datepicker[1];
|
||||
|
||||
if (index == 0) {
|
||||
if (index === 0) {
|
||||
|
||||
secondDp.clear();
|
||||
secondDp.minDate = firstDp.selectedDate;
|
||||
|
||||
if (firstDp.month != secondDp.month) {
|
||||
this.secondDp.enable();
|
||||
this.secondDp.clear();
|
||||
|
||||
this.secondDp.setDateRange({ minDate: this.firstDp.selectedDate });
|
||||
|
||||
secondDp.year = firstDp.year;
|
||||
secondDp.month = firstDp.month;
|
||||
|
||||
secondDp.makeUI();
|
||||
}
|
||||
else {
|
||||
secondDp.setDateRange({ minDate: firstDp.selectedDate });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!firstDp.selectedDate) {
|
||||
this.target.value = '';
|
||||
return;
|
||||
}
|
||||
this.#setValue();
|
||||
|
||||
this.target.value = `${this.dateFormat(firstDp.selectedDate)} - ${this.dateFormat(secondDp.selectedDate)}`;
|
||||
this.hide();
|
||||
|
||||
Ut.trigger(this.opts.onChange, this);
|
||||
this.target.dxTrigger('changed');
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatepicker, Date Format
|
||||
*/
|
||||
dateFormat(date) {
|
||||
return date.toLocaleDateString(this.opts.locales, {
|
||||
day : '2-digit',
|
||||
month : '2-digit',
|
||||
year : 'numeric'
|
||||
});
|
||||
//.replace(/\./g, '/');
|
||||
};
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Show UI
|
||||
*/
|
||||
show() {
|
||||
|
||||
this.ui.classList.remove('hidden');
|
||||
|
||||
if (this.opts.anim) {
|
||||
this.ui.classList.add('visible');
|
||||
if (this.#isOpened) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setPosition();
|
||||
if (!this.#hasRendered) {
|
||||
|
||||
this.isOpen = true;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Hide UI
|
||||
*/
|
||||
hide() {
|
||||
|
||||
if (this.isOpen) {
|
||||
if (this.#isOpened) {
|
||||
|
||||
this.ui.classList.add('hidden');
|
||||
this.el.classList.add('hidden');
|
||||
|
||||
if (this.opts.anim) {
|
||||
this.ui.classList.remove('visible');
|
||||
this.el.classList.remove('visible');
|
||||
}
|
||||
|
||||
this.isOpen = false;
|
||||
this.#isOpened = false;
|
||||
|
||||
Ut.trigger(this.opts.onHide, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Set UI Posituion
|
||||
*/
|
||||
setPosition() {
|
||||
#reposition() {
|
||||
|
||||
let left = Math.round(this.target.dxOffset().left);
|
||||
|
||||
if ((this.ui.clientWidth + left) > window.innerWidth) {
|
||||
if ((this.el.clientWidth + left) > window.innerWidth) {
|
||||
left = 0;
|
||||
}
|
||||
|
||||
this.ui.dxCss({
|
||||
this.el.dxCss({
|
||||
top : (Math.round(this.target.dxOffset().top) + this.target.clientHeight + 2) + 'px',
|
||||
left : left + 'px',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Clear Val
|
||||
*/
|
||||
clear() {
|
||||
|
||||
this.firstDp.clear();
|
||||
|
||||
if (this.isToggled) {
|
||||
this.secondDp.clear();
|
||||
this.secondDp.disable();
|
||||
|
||||
if (this.opts.cancelable) {
|
||||
this.target.dxData('cancelable').iconHandler.classList.add('hide');
|
||||
}
|
||||
this.#setValue();
|
||||
|
||||
if (this.#isToggled) {
|
||||
this.target.dxData('cancelable').iconHandler.classList.add('hide');
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isInput) {
|
||||
this.target.dxVal('');
|
||||
getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
restoreValue(val, separator = this.opts.valSeparator) {
|
||||
|
||||
if (!val) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Array.isArray(val)) {
|
||||
val = val.split(separator);
|
||||
}
|
||||
|
||||
this.datepicker[0].clear();
|
||||
this.datepicker[1].clear();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Restore Selected Val
|
||||
*/
|
||||
restoreValue(dates) {
|
||||
|
||||
if (!dates || !dates.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [ fromDate, toDate ] = dates;
|
||||
|
||||
if (fromDate.getTime() <= toDate.getTime()) {
|
||||
this.datepicker[0].restoreValue(fromDate);
|
||||
this.datepicker[1].restoreValue(toDate);
|
||||
this.datepicker[1].setDateRange({ minDate: fromDate });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Set Events
|
||||
*/
|
||||
setEvents() {
|
||||
|
||||
let that = this;
|
||||
|
||||
// Restore Selected - Handler
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
if (this.isToggled) {
|
||||
|
||||
// Click on UI - fixed Handler
|
||||
|
||||
this.ui.dxOn('click', e => e.stopPropagation());
|
||||
|
||||
this.target.dxOn('click.two_datepicker', e => {
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
if (!that.opts.hiddenMode) {
|
||||
that.show();
|
||||
}
|
||||
});
|
||||
|
||||
// Clear Icon Handler
|
||||
|
||||
if (this.opts.cancelable) {
|
||||
|
||||
this.target.dxOn('clear', _ => {
|
||||
that.clear();
|
||||
Ut.trigger(that.opts.onChange, that, null, false);
|
||||
});
|
||||
}
|
||||
|
||||
// Click outside - Handler
|
||||
|
||||
document.body.dxOn('click.two_datepicker' + this.ekey, _ => this.hide());
|
||||
|
||||
let tm = null;
|
||||
|
||||
// Resize window Handler
|
||||
|
||||
window.dxOn('scroll.two_datepicker resize.two_datepicker' + this.ekey + ' orientationchange.two_datepicker' + this.ekey, _ => {
|
||||
|
||||
if (tm) {
|
||||
clearTimeout(tm);
|
||||
tm = null;
|
||||
}
|
||||
|
||||
tm = setTimeout(_ => that.setPosition(), 100);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TwoDatePicker, Destroy Widget
|
||||
*/
|
||||
destroy() {
|
||||
|
||||
this.datepicker[0].destroy();
|
||||
this.datepicker[1].destroy();
|
||||
this.firstDp.destroy();
|
||||
this.secondDp.destroy();
|
||||
|
||||
this.ui.remove();
|
||||
if (this.#hasRendered) {
|
||||
|
||||
this.el.remove();
|
||||
|
||||
if (this.isToggled) {
|
||||
|
||||
this.target.dxOff('click.two_datepicker keydown.two_datepicker paste.two_datepicker restore.two_datepicker');
|
||||
|
||||
document.body.dxOff('click.two_datepicker' + this.ekey);
|
||||
window.dxOff('scroll.two_datepicker resize.two_datepicker' + this.ekey + ' orientationchange.two_datepicker' + this.ekey);
|
||||
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');
|
||||
|
||||
Stack.delete(this);
|
||||
this.target.dxRemoveWidget();
|
||||
|
||||
Ut.trigger(this.opts.onDestroy, this);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user