This commit is contained in:
2025-12-29 07:09:03 +02:00
parent eb3a761a71
commit d80513a8a0
22 changed files with 958 additions and 1393 deletions
+10 -3
View File
@@ -422,9 +422,16 @@ export class App extends Boot {
static destroyOldGlobalEvents() { static destroyOldGlobalEvents() {
if (App.section) { if (App.section) {
window.dxOff(`${App.section}*`);
document.dxOff(`${App.section}*`); Ut.each(App.widgetStack, wtList => wtList.forEach(wt => wt.destroy() ) );
document.body.dxOff(`${App.section}*`);
App.widgetStack = {};
Ut.resetKey();
window.dxOff(`.${App.section}`);
document.dxOff(`.${App.section}`);
document.body.dxOff(`.${App.section}`);
} }
// Destroy all TinyMce Instances // Destroy all TinyMce Instances
+10 -6
View File
@@ -26,11 +26,15 @@ export class Boot {
// Static Section Vars // Static Section Vars
static vars = {}; static vars = {};
// Widget Stack Object
static widgetStack = {};
static ready(callback) { static ready(callback) {
dxReady(() => { dxReady(() => {
Boot.lang = document.documentElement.getAttribute('lang') ?? 'en'; Boot.lang = document.documentElement.getAttribute('lang') ?? 'en';
Boot.isApp = document.documentElement.classList.contains('app');
import(`/js/${Boot.lang}/interface.js`).then((mod) => { import(`/js/${Boot.lang}/interface.js`).then((mod) => {
@@ -100,13 +104,13 @@ export class Boot {
EvtOptions.section = id; EvtOptions.section = id;
} }
/**
* Add Widget To Stack
*/
static addWidget = ref => Boot.isApp && (Boot.widgetStack[ref.constructor.name] ??= []).push(ref);
/** /**
* App Log * App Log
*/ */
static log(err) { static log = err => Boot.DEBUG && console.log(err);
if (Boot.DEBUG) {
console.log(err);
}
}
} }
-4
View File
@@ -531,10 +531,6 @@ export class Render {
input.readOnly = true; input.readOnly = true;
} }
if (field.rewrite == '1') {
input.dataset.value = '';
}
if (field.required == '1') { if (field.required == '1') {
input.required = true; input.required = true;
} }
-41
View File
@@ -1,41 +0,0 @@
export class Stack {
static widgets = {};
/**
* Registers a widget instance in the global registry.
*
* @param {Object} ref - Widget instance to register.
* @returns {void}
*/
static add(ref) {
const name = ref.constructor.name;
Stack.widgets[name] ??= new Map();
// ref.ekey = crypto.randomUUID();
ref.ekey = Stack.widgets[name].size;
Stack.widgets[name].set(ref.ekey, ref);
}
/**
* Removes a widget instance from the global registry.
*
* @param {Object} ref - Widget instance to remove.
* @returns {void}
*/
static delete(ref) {
const name = ref.constructor.name;
if (!this.widgets[name]?.has(ref.ekey)) {
return;
}
this.widgets[name].delete(ref.ekey);
ref.ekey = null;
}
}
+8 -3
View File
@@ -2,8 +2,11 @@ const stamp = Date.now();
export class Ut { export class Ut {
static EventsUID = 'Events' + stamp; static EventsUID = `Events_${stamp}`;
static DataUID = 'Data' + stamp; static DataUID = `Data_${stamp}`;
static WidgetUID = `Widget_${stamp}`;
static evKey = 0;
static isSet = (val) => typeof val !== 'undefined'; static isSet = (val) => typeof val !== 'undefined';
static isFn = (val) => typeof val === 'function'; static isFn = (val) => typeof val === 'function';
@@ -18,6 +21,9 @@ export class Ut {
static each = (obj, callback, context) => obj && Object.keys(obj).forEach(key => callback.call(context ?? this, obj[key], key) ); static each = (obj, callback, context) => obj && Object.keys(obj).forEach(key => callback.call(context ?? this, obj[key], key) );
static tplString = (str, context) => new Function('return `' + str + '`;').call(context || {}); static tplString = (str, context) => new Function('return `' + str + '`;').call(context || {});
static nextKey = () => ++Ut.evKey;
static resetKey = () => Ut.evKey = 0;
static extendNode(name, value) { static extendNode(name, value) {
@@ -60,7 +66,6 @@ export class Ut {
moveevent : ('ontouchstart' in window) ? 'touchmove' : 'mousemove' moveevent : ('ontouchstart' in window) ? 'touchmove' : 'mousemove'
} }
/** /**
* Redirect * Redirect
*/ */
+91 -46
View File
@@ -139,10 +139,9 @@
events.split(' ').forEach(function(evt) { events.split(' ').forEach(function(evt) {
evt = evt.split('.'); const i = evt.indexOf('.');
const eName = i === -1 ? evt : evt.slice(0, i);
let eName = evt[0]; const namespace = nsPref + (i === -1 ? '*' : evt.slice(i + 1) );
let namespace = nsPref + (evt[1] || '*');
if (!this[ Ut.EventsUID ][ eName ]) { if (!this[ Ut.EventsUID ][ eName ]) {
this[ Ut.EventsUID ][ eName ] = []; this[ Ut.EventsUID ][ eName ] = [];
@@ -169,10 +168,9 @@
events.split(' ').forEach(function(evt) { events.split(' ').forEach(function(evt) {
evt = evt.split('.'); const i = evt.indexOf('.');
const eName = i === -1 ? evt : evt.slice(0, i);
let eName = evt[0]; const namespace = nsPref + (i === -1 ? '*' : evt.slice(i + 1) );
let namespace = nsPref + (evt[1] || '*');
if (!this[ Ut.EventsUID ][ eName ]) { if (!this[ Ut.EventsUID ][ eName ]) {
this[ Ut.EventsUID ][ eName ] = []; this[ Ut.EventsUID ][ eName ] = [];
@@ -201,9 +199,9 @@
this[ Ut.EventsUID ][ eName ].push([ namespace, selector, _handler ]); this[ Ut.EventsUID ][ eName ].push([ namespace, selector, _handler ]);
if (eName.startsWith('swipe')) { // if (eName.startsWith('swipe')) {
// new SwipeEvents(this, eName, target, _handler, opts); // new SwipeEvents(this, eName, target, _handler, opts);
} //}
this.addEventListener(eName, _handler, opts); this.addEventListener(eName, _handler, opts);
@@ -213,58 +211,73 @@
return this; return this;
}, },
/** /**
* Remove an event handler. * Remove an event handler.
*/ */
off(events, selector) { off(events, selector) {
let nsPref = (EvtOptions.nsEvent && EvtOptions.section) ? (EvtOptions.section + '.') : ''; const target = this;
if (!this[Ut.EventsUID]) { if (!target[Ut.EventsUID]) {
return this; return target;
} }
if (!events) { events = events ?? [ '' ];
this.replaceWith(this.cloneNode(true));
return this;
}
events.split(' ').forEach(function(evt) { events.split(' ').forEach(event => {
evt = evt.split('.'); const eventToken = event.split('.');
let eName = evt[0]; let [ eventName, eventNs ] = eventToken;
let namespace = nsPref + (evt[1] || '*');
let eList = this[Ut.EventsUID][eName]; if (eventName === '') {
if (eList) { const eventRoot = target[Ut.EventsUID];
let i = eList.length; Ut.each(eventRoot, (eventList, realEventName) => {
let i = (eventList && eventList.length) || 0;
while (i--) {
const eventData = eventList[i];
if ((eventToken.length === 1 || eventNs === eventData[0] || eventData[0].startsWith(`${eventNs}.`)) && (!selector || eventData[1] === selector) ) {
target.removeEventListener(realEventName, eventData[2]);
eventList.splice(i, 1);
}
}
});
return;
}
if (EvtOptions.nsEvent && EvtOptions.section) {
eventNs = `${eventNs}.${EvtOptions.section}`;
}
const eventList = target[Ut.EventsUID][ eventName ];
let i = (eventList && eventList.length) || 0;
while(i--) { while(i--) {
let et = eList[i]; const eventData = eventList[i];
if ((et[0] == namespace || namespace == nsPref + '*') && (!selector || (et[1] == selector)) ) { if ((eventToken.length === 1 || eventNs === eventData[0] || eventData[0].startsWith(`${eventNs}.`)) && (!selector || eventData[1] === selector) ) {
//if (customEvents[eName]) { //if (customEvents[eventName]) {
// customEvents[eName].destroy.call(this, eName, et[1]); // customEvents[eventName].destroy.call(this, eventName, eventData[1]);
//} //}
//if (eventName.startsWith('swipe')) {}
if (eName.startsWith('swipe')) { this.removeEventListener(eventName, eventData[2]);
eventList.splice(i, 1);
}
this.removeEventListener(eName, et[2]);
eList.splice(i, 1);
} }
} }
} });
}, this);
return this; return target;
}, },
/** /**
@@ -506,6 +519,7 @@
left: rect.left + win.scrollX left: rect.left + win.scrollX
}; };
}, },
/** /**
* Store / Retreive Arbitrary Data * Store / Retreive Arbitrary Data
*/ */
@@ -521,6 +535,34 @@
return this; return this;
}, },
/**
* Store / Retreive Arbitrary Widget Data
*/
widget(data) {
if (data) {
this[ Ut.WidgetUID ] = data;
return this;
}
return this[ Ut.WidgetUID ] || null;
},
/**
* Get Widget Data Value
*/
nval() {
return this[ Ut.WidgetUID ]?.getValue();
},
/**
* Remove widget data
*/
removeWidget() {
delete this[ Ut.WidgetUID ];
return this;
},
/** /**
* Remove Arbitrary Data * Remove Arbitrary Data
@@ -994,9 +1036,12 @@
continue; continue;
} }
if ('value' in target.dataset) { const widget = domUtils.widget.call(target);
if (widget) {
widget.restoreValue(Ut.unescape(val));
target.dataset.value = Ut.unescape(val);
target.value = Ut.unescape(data[key + '_value'] ?? val); target.value = Ut.unescape(data[key + '_value'] ?? val);
if (domUtils.data.call(target, 'datepicker')) { if (domUtils.data.call(target, 'datepicker')) {
+4 -2
View File
@@ -272,8 +272,10 @@ export class Validator {
let value; let value;
let displayedVal = null; let displayedVal = null;
if ('value' in el.dataset) { const widget = el.dxWidget();
value = el.dataset.value;
if (widget) {
value = widget.getValue();
displayedVal = el.value.trim(); displayedVal = el.value.trim();
} }
else { else {
+22 -23
View File
@@ -3,7 +3,6 @@ import './autocomplete.css';
import { Ut } from '../../utils/Ut' import { Ut } from '../../utils/Ut'
import { El } from '../../utils/dom'; import { El } from '../../utils/dom';
import { Rc } from '../../core/Rc'; import { Rc } from '../../core/Rc';
import { Stack } from '../../core/Stack';
import { Cancelable } from '../cancelable' import { Cancelable } from '../cancelable'
export class Autocomplete { export class Autocomplete {
@@ -16,13 +15,14 @@ export class Autocomplete {
this.target = target; this.target = target;
this.reqOpts = {}; this.reqOpts = {};
if (this.target.dxData('autocomplete')) { if (this.target.dxWidget() || this.target.dxData('autocomplete')) {
return; return;
} }
this.target.dxData('autocomplete', this); this.target.dxData('autocomplete', this);
this.target.dxWidget(this);
Stack.add(this); this.ekey = Ut.nextKey();
this.opts = { ... { this.opts = { ... {
optionHeight: 32, optionHeight: 32,
@@ -30,8 +30,6 @@ export class Autocomplete {
selectionColor: 'green' selectionColor: 'green'
}, ... opts }; }, ... opts };
this.target.dataset.value = '';
this.selected = null; this.selected = null;
this.count = 0; this.count = 0;
this.index = -1; this.index = -1;
@@ -81,7 +79,7 @@ export class Autocomplete {
this.ui.wrapper.dxOn('click', '.ac-option', (e, t) => this.clickOptionHandler(e, t)); this.ui.wrapper.dxOn('click', '.ac-option', (e, t) => this.clickOptionHandler(e, t));
// Click outside // Click outside
document.body.dxOn('click.autocomplete', e => e.target != this.target && this.clearOptions()); document.body.dxOn('click.autocomplete', e => e.target != this.target && this.clear());
} }
/** /**
@@ -89,12 +87,12 @@ export class Autocomplete {
*/ */
processData(val) { processData(val) {
this.clearOptions(); this.clear();
let found = true; let found = true;
let matchId = ''; let matchId = '';
for (let id in this.data) { for (let id in this.data) {
let name = this.data[id]; let name = this.data[id];
@@ -130,14 +128,13 @@ export class Autocomplete {
if (found && !matchId) { if (found && !matchId) {
matchId = id; matchId = id;
this.value = matchId;
} }
} }
} }
let changed = this.target.dataset.value != matchId; let changed = this.value != matchId;
this.target.dataset.value = matchId; this.value = matchId;
if (changed) { if (changed) {
Ut.trigger(this.opts.onChange, this); Ut.trigger(this.opts.onChange, this);
@@ -217,7 +214,7 @@ export class Autocomplete {
e.stopPropagation(); e.stopPropagation();
if (this.selected) { if (this.selected) {
this.updateVal(this.selected.dataset.id); this.restoreValue(this.selected.dataset.id);
} }
} }
} }
@@ -227,28 +224,31 @@ export class Autocomplete {
*/ */
clickOptionHandler(e, t) { clickOptionHandler(e, t) {
e.stopPropagation(); e.stopPropagation();
this.updateVal(t.dataset.id); this.restoreValue(t.dataset.id);
} }
/** /**
* Autocomplete, Update Val * Autocomplete, Update Val
*/ */
updateVal(id) { restoreValue(id) {
this.value = id; this.value = id;
if (id == this.target.dataset.value) { if (id == this.value) {
this.clearOptions(); this.clear();
return; return;
} }
this.target.dataset.value = id;
this.target.value = this.data[id]; this.target.value = this.data[id];
Ut.trigger(this.opts.onChange, this); Ut.trigger(this.opts.onChange, this);
this.target.dxTrigger('changed'); this.target.dxTrigger('changed');
this.clearOptions(); this.clear();
}
getValue() {
return this.value;
} }
/** /**
@@ -282,14 +282,14 @@ export class Autocomplete {
*/ */
updateOptions(data) { updateOptions(data) {
this.clearOptions(); this.clear();
this.data = data; this.data = data;
} }
/** /**
* Autocomplete Clear Options * Autocomplete Clear Options
*/ */
clearOptions() { clear() {
this.selected = null; this.selected = null;
this.count = 0; this.count = 0;
@@ -308,15 +308,14 @@ export class Autocomplete {
this.ui.wrapper.remove(); this.ui.wrapper.remove();
delete this.target.dataset.value; this.target.dxRemoveWidget();
document.body.dxOff('click.autocomplete' + this.ekey); document.body.dxOff('click.autocomplete' + this.ekey);
this.target.dxOff('input.autocomplete' + this.ekey + ' keydown.autocomplete' + this.ekey + ' click.autocomplete' + this.ekey); this.target.dxOff('input.autocomplete' + this.ekey + ' keydown.autocomplete' + this.ekey + ' click.autocomplete' + this.ekey);
Stack.delete(this);
this.target.dxRemoveData('autocomplete'); this.target.dxRemoveData('autocomplete');
this.target.dxRemoveWidget();
Ut.trigger(this.opts.onDestroy, this); Ut.trigger(this.opts.onDestroy, this);
} }
+1 -3
View File
@@ -48,9 +48,7 @@ export class Cancelable {
this.target.value = this.emptyVal; this.target.value = this.emptyVal;
if ('value' in this.target.dataset) { this.target.dxWidget()?.clear();
this.target.dataset.value = '';
}
this.iconHandler.classList.add('hide'); this.iconHandler.classList.add('hide');
+8 -9
View File
@@ -1,7 +1,7 @@
import './counter.css'; import './counter.css';
import { El } from '../../utils/dom'; import { El } from '../../utils/dom';
import { Stack } from '../../core/Stack'; import { Ut } from '../../utils/Ut';
//////////////////////// ////////////////////////
// Chars Counter // Chars Counter
@@ -29,14 +29,14 @@ export class Counter {
this.indicator = El('div', { className: 'indicator' }); this.indicator = El('div', { className: 'indicator' });
this.counter = El('span', { className: 'counter' }, '0'); this.counter = El('span', { className: 'counter' }, '0');
this.ui = El('div', { className: 'sp-chars-counter' }, this.el = El('div', { className: 'sp-chars-counter' },
El('div', { className: 'progress-bar' }, this.indicator), El('div', { className: 'progress-bar' }, this.indicator),
El('div', { className: 'label' }, this.counter, ' / '+ this.opts.limit) El('div', { className: 'label' }, this.counter, ' / '+ this.opts.limit)
); );
this.target.after(this.ui); this.target.after(this.el);
Stack.add(this); this.ekey = Ut.nextKey();
this.setEvents(); this.setEvents();
} }
@@ -67,16 +67,15 @@ export class Counter {
setEvents() { setEvents() {
// Input - Handler // Input - Handler
this.target.dxOn('input.counter' + this.ekey, this.update.bind(this)); this.target.dxOn(`input.counter.${this.ekey}`, this.update.bind(this));
} }
/** /**
* Counter, Destroy * Counter, Destroy
*/ */
destroy() { destroy() {
this.target.dxOff('input.counter' + this.ekey); this.target.dxOff(`input.counter${this.ekey}`);
Stack.delete(this); this.el.remove();
this.ui.remove();
} }
} }
File diff suppressed because it is too large Load Diff
+2 -4
View File
@@ -2,7 +2,7 @@ import './dialog.css';
import { El } from '../../utils/dom' import { El } from '../../utils/dom'
import { Overlay } from '../overlay'; import { Overlay } from '../overlay';
import { Stack } from '../../core/Stack'; import { Ut } from '../../utils/Ut';
//////////////////// ////////////////////
// Dialog // Dialog
@@ -33,7 +33,7 @@ export class Dialog {
this.events = events || {}; this.events = events || {};
Stack.add(this); this.ekey = Ut.nextKey();
this.create(); this.create();
@@ -226,8 +226,6 @@ export class Dialog {
document.dxOff('keydown.dialog' + this.ekey + ' mouseup.dialog' + this.ekey); document.dxOff('keydown.dialog' + this.ekey + ' mouseup.dialog' + this.ekey);
Stack.delete(this);
that.target.dxRemoveData('dialog'); that.target.dxRemoveData('dialog');
Ut.trigger(that.events.destroy); Ut.trigger(that.events.destroy);
+123 -121
View File
@@ -2,178 +2,180 @@ import './dropdown.css';
import { Ut } from '../../utils/Ut'; import { Ut } from '../../utils/Ut';
import { El } from '../../utils/dom'; import { El } from '../../utils/dom';
import { Boot } from '../../core/Boot';
////////////////////
// DopDown Menu
////////////////////
export class Dropdown { export class Dropdown {
/** #isOpen = false;
* Dropdown Constructor #hasRendered = false;
*/
constructor(target, opts) {
this.target = target; constructor(target, opts) {
if (this.target.dxData('dropdown')) { this.target = target;
return;
}
this.target.dxData('dropdown', this); if (this.target.dxData('dropdown')) {
return;
}
this.opts = { ... { items: [] }, ... opts }; this.target.dxData('dropdown', this);
Boot.addWidget(this);
this.isOpened = false; this.opts = { ... { items: [] }, ... opts };
this.isBusy = false;
this.create(); this.el = null;
this.setEvents(); this.ekey = Ut.nextKey();
}
/** this.#bindTargetEvents();
* Dropdown, Create UI }
*/
create() {
this.ui = El('div', { className: 'sp-dropdown hide' }); #bindTargetEvents() {
if (this.opts.cls) { const that = this;
this.ui.classList.add(this.opts.cls);
}
const list = El('ul'); this.target.dxOn('focus.dropdown', e => {
if (this.opts.items.length) { e.stopPropagation();
this.ui.append(list);
}
this.items = []; Ut.trigger(that.opts.onFocus, this);
this.opts.items.forEach(item => { if (!that.#hasRendered) {
this.items.push( this.#render();
list.appendChild( El('li', { className: 'color-'+ (item.color || 'black'), 'data-id': item.id }, }
(item.icon ? El('i', { className: 'fa fa-'+ item.icon }) : null),
item.name
))
);
});
this.target.after(this.ui); if (!that.#isOpen) {
that.show();
return;
}
that.hide();
});
}
Ut.trigger(this.opts.onInit, this); #bindUiEvents() {
}
/** const that = this;
* Dropdown, Set UI Position
*/ // Click on Item Handler
setPosition() { this.el.dxOn('click', 'li', (_, t) => {
let left = Math.round(this.target.offsetLeft); that.hide();
if ((this.ui.clientWidth + left) > window.innerWidth) { Ut.trigger(that.opts.items[ t.dxIndex(that.items) ].handler);
left = 0;
}
this.ui.style.top = (Math.round(this.target.offsetTop) + this.target.clientHeight + 2) + 'px'; Ut.trigger(that.opts.onChange, t.dataset.id, this);
this.ui.style.left = left + 'px'; });
}
// PointerDown Handler
document.dxOn('pointerdown.dropdown', e => !this.target.contains(e.target) && !this.el.contains(e.target) && this.hide() );
/** let tm = null;
* Dropdown, Show UI
*/
show() {
if (this.isBusy || this.isOpened) { // Resize & Orientation Handler
return; window.dxOn(`resize.dropdown.${this.ekey} orientationchange.dropdown.${this.ekey}`, _ => {
}
Ut.trigger(this.opts.onShow, this); if (tm) {
clearTimeout(tm);
tm = null;
}
this.setPosition(); tm = setTimeout(_ => that.#reposition(), 100);
});
}
this.ui.classList.remove('hide'); #render() {
this.ui.classList.add('opened');
this.target.classList.add('dropdown-opened');
this.isOpened = true; this.el = El('div', { className: 'sp-dropdown hide' });
}
/** if (this.opts.cls) {
* Dropdown, Hide UI this.el.classList.add(this.opts.cls);
*/ }
hide() {
if (!this.isOpened) { const list = El('ul');
return;
}
Ut.trigger(this.opts.onHide, this); if (this.opts.items.length) {
this.el.append(list);
}
let that = this; this.items = [];
this.ui.addEventListener('transitionend', _ => !this.ui.classList.contains('opened') && this.ui.classList.add('hide'), { once: true }); this.opts.items.forEach(item => {
this.items.push(
list.appendChild( El('li', { className: 'color-'+ (item.color || 'black'), 'data-id': item.id },
(item.icon ? El('i', { className: 'fa fa-'+ item.icon }) : null),
item.name
))
);
});
this.ui.classList.remove('opened'); document.body.append(this.el);
this.target.classList.remove('dropdown-opened');
this.isOpened = false; this.#bindUiEvents();
};
/** this.#hasRendered = true;
* Dropdown, Set Evensts
*/
setEvents() {
let that = this; Ut.trigger(this.opts.onInit, this);
}
document.body.dxOn('click.dropdown', _ => that.hide()); #reposition() {
this.target.dxOn('click', e => { const r = this.target.getBoundingClientRect();
e.stopPropagation(); const scrollX = window.scrollX || 0;
const scrollY = window.scrollY || 0;
if (!that.ui.classList.contains('opened')) { this.el.style.left = Math.round(r.left + scrollX) + 'px';
that.show(); this.el.style.top = Math.round(r.bottom + scrollY + 2) + 'px';
} }
else {
that.hide();
}
});
this.ui.dxOn('click', 'li', (_, t) => { show() {
Ut.trigger(that.opts.items[ t.dxIndex(that.items) ].handler);
Ut.trigger(that.opts.onChange, t.dataset.id, this);
});
let tm = null; if (this.#isOpen) {
return;
}
window.dxOn('resize.dropdown' + this.ekey + ' orientationchange.dropdown' + this.ekey, _ => { this.#reposition();
if (tm) { this.el.classList.remove('hide');
clearTimeout(tm); this.el.classList.add('opened');
tm = null;
}
tm = setTimeout(_ => that.setPosition(), 100); this.#isOpen = true;
});
}
/** Ut.trigger(this.opts.onShow, this);
* Dropdown, Destroy }
*/
destroy() {
this.ui.remove(); hide() {
if (!this.#isOpen) {
return;
}
document.body.dxOff('click.dropdown'); this.el.addEventListener('transitionend', _ => this.el.classList.add('hide'),
window.dxOff('resize.dropdown' + this.ekey + ' orientationchange.dropdown' + this.ekey); { once: true }
);
this.target.dxRemoveData('dropdown'); this.el.classList.remove('opened');
Ut.trigger(this.events.destroy, this); this.#isOpen = false;
return this.target; Ut.trigger(this.opts.onHide, this);
} };
destroy() {
if (this.#hasRendered) {
this.el.remove();
document.dxOff(`pointerdown.dropdown.${this.ekey}`);
window.dxOff(`resize.dropdown.${this.ekey} orientationchange.dropdown.${this.ekey}`);
}
this.target.dxOff(`focus.dropdown.${this.ekey}`);
this.target.dxRemoveData('dropdown');
Ut.trigger(this.opts.onDestroy, this);
}
} }
+6 -5
View File
@@ -12,6 +12,8 @@
opacity: 0; opacity: 0;
transition: all 0.3s; transition: all 0.3s;
transform: translateY(20px); transform: translateY(20px);
-webkit-user-select: none;
user-select: none;
} }
.sp-dropdown.opened { .sp-dropdown.opened {
@@ -20,7 +22,6 @@
} }
.sp-dropdown ul { .sp-dropdown ul {
margin: 2px 0 0;
font-size: 14px; font-size: 14px;
color: #212529; color: #212529;
background-color: #fff; background-color: #fff;
@@ -41,6 +42,10 @@
cursor: pointer; cursor: pointer;
} }
.sp-dropdown li:hover {
background-color: #ebebeb;
}
.sp-dropdown.dp-interval li { .sp-dropdown.dp-interval li {
padding: 8px 12px 8px 12px; padding: 8px 12px 8px 12px;
font-size: 13px; font-size: 13px;
@@ -54,8 +59,4 @@
display: block; display: block;
font-size: 16px; font-size: 16px;
margin-right: 8px; margin-right: 8px;
}
.sp-dropdown li:hover {
opacity: 0.75;
} }
+1 -5
View File
@@ -2,7 +2,6 @@ import './hours.css';
import { Ut } from '../../utils/Ut'; import { Ut } from '../../utils/Ut';
import { El } from '../../utils/dom'; import { El } from '../../utils/dom';
import { Stack } from '../../core/Stack';
import { Render } from '../../core/Render'; import { Render } from '../../core/Render';
//////////////////// ////////////////////
@@ -28,7 +27,7 @@ export class Hours {
this.makeUi(); this.makeUi();
Stack.add(this); this.ekey = Ut.nextKey();
this.hour = this.ui.dxFind('select[name=hour]'); this.hour = this.ui.dxFind('select[name=hour]');
this.min = this.ui.dxFind('select[name=min]'); this.min = this.ui.dxFind('select[name=min]');
@@ -109,8 +108,6 @@ export class Hours {
this.target.dxOn('click.hours', function(e) { this.target.dxOn('click.hours', function(e) {
e.stopPropagation(); e.stopPropagation();
Stack.widgets.DatePicker.forEach(datepicker => datepicker.hide() );
that.isVisible = true; that.isVisible = true;
@@ -182,7 +179,6 @@ export class Hours {
document.body.dxOff('click.hours'); document.body.dxOff('click.hours');
window.dxOff('resize.hours' + this.ekey + ' orientationchange.hours' + this.ekey + ' keyup.hours' + this.ekey); window.dxOff('resize.hours' + this.ekey + ' orientationchange.hours' + this.ekey + ' keyup.hours' + this.ekey);
Stack.delete(this);
this.target.dxRemoveData('hours'); this.target.dxRemoveData('hours');
return this.target; return this.target;
+133 -205
View File
@@ -2,235 +2,163 @@ import { Ut } from '../../utils/Ut';
import { Boot } from '../../core/Boot'; import { Boot } from '../../core/Boot';
import { TwoDatePicker } from '../two-datepicker/TwoDatepicker'; import { TwoDatePicker } from '../two-datepicker/TwoDatepicker';
import { Dropdown } from '../dropdown'; import { Dropdown } from '../dropdown';
import { Stack } from '../../core/Stack';
//////////////////// ////////////////////
// IntervalPicker // IntervalPicker
//////////////////// ////////////////////
export class IntervalPicker { export class IntervalPicker {
/** /**
* Intervalpicker, Constructor * Intervalpicker, Constructor
*/ */
constructor(target, opts) { constructor(target, opts) {
this.target = target; this.target = target;
this.opts = { ... { this.opts = { ... {
separator : ' - ', locales : 'ro-RO',
locales : 'ro-RO', style : 'normal',
style : 'normal', disabled : false,
disabled : 1 dateFormat : 'dd-mm-yyyy',
}, ... opts }; valueFormat : 'dd-mm-yyyy',
valSeparator: '-',
dateSeparator: ' - '
}, ... opts };
if (this.target.dxData('intervalpicker')) { if (this.target.dxData('intervalpicker')) {
return; return;
} }
this.target.dxData('intervalpicker', this); this.target.dxData('intervalpicker', this);
this.widget = Boot.intData.widget.intervalpicker.children; this.widget = Boot.intData.widget.intervalpicker.children;
this.create(); this.create();
}
Stack.add(this); /**
} * Intervalpicker, Create
*/
create() {
let that = this;
/** let options = Ut.objVal(this.widget.form).children.field.interval.option;
* Intervalpicker, Date Format let items = [];
*/
dateFormat(date) { for (let id in options) {
return date.toLocaleDateString(this.opts.locales, { items.push({ id: id, name: options[id] });
day : '2-digit', }
month : '2-digit',
year : 'numeric'
});
//.replace(/\./g, '/');
};
/** this.twoDatePicker = new TwoDatePicker(this.target, {
* Intervalpicker, Create anim: false,
*/ render: false,
create() { showOnClick: false,
style: this.opts.style,
let that = this; disabled: this.opts.disabled,
dateFormat : 'dd-mm-yyyy',
valueFormat : 'dd-mm-yyyy',
valSeparator: '-',
dateSeparator: ' - '
});
let options = Ut.objVal(this.widget.form).children.field.interval.option; this.dropdown = new Dropdown(this.target, {
let items = []; items: items,
cls: 'dp-interval',
for (let id in options) { onChange: id => {
items.push({ id: id, name: options[id] });
}
new TwoDatePicker(this.target, { const date = new Date();
anim: false,
hiddenMode: true,
style: this.opts.style,
disabled: this.opts.disabled
}, {
init: twoDatePicker => that.twoDatePicker = twoDatePicker,
onChange: function(twoDatePicker, val, index) {
const firstDp = twoDatePicker.datepicker[0]; switch (id) {
const secondDp = twoDatePicker.datepicker[1]; case '0':
that.interval = [ date, date ];
break;
case '1':
that.interval = [ null, new Date(date) ];
date.setDate(date.getDate() - 1);
that.interval[0] = date;
break;
case '2':
that.interval = [ null, new Date(date) ];
date.setDate(date.getDate() - 7);
that.interval[0] = date;
break;
case '3':
that.interval = [ null, new Date(date) ];
date.setDate(date.getDate() - 30);
that.interval[0] = date;
break;
case '4':
date.setDate(1);
that.interval = [ new Date(date), null ];
date.setMonth(date.getMonth() + 1);
date.setDate(0);
that.interval[1] = date;
break;
case '5':
date.setDate(1);
date.setMonth(date.getMonth() - 1);
that.interval = [ new Date(date), null ];
date.setMonth(date.getMonth() + 1);
date.setDate(0);
that.interval[1] = date;
break;
case '6':
date.setDate(1);
date.setMonth(0);
that.interval = [ new Date(date), null ];
date.setFullYear(date.getFullYear() + 1);
date.setDate(0);
that.interval[1] = date;
break;
case '7':
date.setFullYear(date.getFullYear() - 1);
date.setMonth(0);
date.setDate(1);
that.interval = [ new Date(date), null ];
date.setFullYear(date.getFullYear() + 1);
date.setDate(0);
that.interval[1] = date;
break;
case '8':
setTimeout(_ => that.twoDatePicker.show());
break;
}
if (!val) { if (id != '8') {
that.interval = null; that.updateInput();
} }
}
if (index == 0) { });
}
secondDp.clear();
secondDp.minDate = firstDp.selectedDate;
if (firstDp.month != secondDp.month) {
secondDp.year = firstDp.year;
secondDp.month = firstDp.month;
secondDp.makeUI();
}
else {
secondDp.setDateRange({ minDate: firstDp.selectedDate });
}
}
else {
if (!firstDp.selectedDate) {
return;
}
that.target.dxVal(that.dateFormat(firstDp.selectedDate)
+ that.opts.separator
+ that.dateFormat(secondDp.selectedDate)
);
twoDatePicker.hide();
that.target.dxTrigger('changed');
}
},
onHide: _ => that.dropdown.isBusy = false
});
const twoDp = this.target.dxData('two_datepicker'); /**
* Intervalpicker, Update Input
*/
updateInput() {
new Dropdown(this.target, { if (!this.interval || !this.interval.length) {
items: items, return;
cls: 'dp-interval', }
onInit: dropdown => that.dropdown = dropdown,
onShow: _ => {
Stack.widgets.IntervalPicker.forEach(intPicker => { this.twoDatePicker.restoreValue(this.interval);
if (intPicker.dropdown.isOpened) { this.target.dxTrigger('changed');
intPicker.dropdown.hide(); Ut.trigger(this.opts.onSelect, this);
} }
if (intPicker.dropdown.isBusy) { /**
intPicker.twoDatePicker.hide(); * Intervalpicker, Destroy
} */
}); destroy() {
},
onChange: id => {
const date = new Date(); this.twoDatePicker.destroy();
this.dropdown.destroy();
switch (id) { this.target.dxRemoveData('intervalpicker');
case '0': }
that.interval = [ date, date ];
break;
case '1':
that.interval = [ null, new Date(date) ];
date.setDate(date.getDate() - 1);
that.interval[0] = date;
break;
case '2':
that.interval = [ null, new Date(date) ];
date.setDate(date.getDate() - 7);
that.interval[0] = date;
break;
case '3':
that.interval = [ null, new Date(date) ];
date.setDate(date.getDate() - 30);
that.interval[0] = date;
break;
case '4':
date.setDate(1);
that.interval = [ new Date(date), null ];
date.setMonth(date.getMonth() + 1);
date.setDate(0);
that.interval[1] = date;
break;
case '5':
date.setDate(1);
date.setMonth(date.getMonth() - 1);
that.interval = [ new Date(date), null ];
date.setMonth(date.getMonth() + 1);
date.setDate(0);
that.interval[1] = date;
break;
case '6':
date.setDate(1);
date.setMonth(0);
that.interval = [ new Date(date), null ];
date.setFullYear(date.getFullYear() + 1);
date.setDate(0);
that.interval[1] = date;
break;
case '7':
date.setFullYear(date.getFullYear() - 1);
date.setMonth(0);
date.setDate(1);
that.interval = [ new Date(date), null ];
date.setFullYear(date.getFullYear() + 1);
date.setDate(0);
that.interval[1] = date;
break;
case '8':
that.dropdown.isBusy = true;
twoDp.restoreValue(that.interval);
setTimeout(_ => twoDp.show());
break;
}
that.updateInput();
}
});
}
/**
* Intervalpicker, Update Input
*/
updateInput() {
if (!this.interval) {
return;
}
const val = this.interval.map(date => this.dateFormat(date)).join(this.opts.separator);
this.target.value = val;
this.target.dxTrigger('changed');
Ut.trigger(this.opts.onSelect, val, this);
}
/**
* Intervalpicker, Destroy
*/
destroy() {
this.twoDatePicker.destroy();
this.dropdown.destroy();
Stack.delete(this);
this.target.dxRemoveData('intervalpicker');
}
} }
+1 -4
View File
@@ -3,7 +3,6 @@ import './lightbox.css';
import { Ut } from '../../utils/Ut'; import { Ut } from '../../utils/Ut';
import { $ } from '../../utils/dom'; import { $ } from '../../utils/dom';
import { Boot } from '../../core/Boot'; import { Boot } from '../../core/Boot';
import { Stack } from '../../core/Stack';
//////////////////// ////////////////////
// LightBox // LightBox
@@ -162,7 +161,7 @@ export class Lightbox {
this.arrowRight.classList.toggle('hide', this.square.length == this.index + 1); this.arrowRight.classList.toggle('hide', this.square.length == this.index + 1);
this.arrowLeft.classList.toggle('hide', !this.index); this.arrowLeft.classList.toggle('hide', !this.index);
Stack.add(this); this.ekey = Ut.nextKey();
} }
hidden() { hidden() {
@@ -318,8 +317,6 @@ export class Lightbox {
this.target.dxOff('click.lightbox'); this.target.dxOff('click.lightbox');
document.dxOff('keyup.lightbox' + this.ekey + ' resize.lightbox' + this.ekey + ' orientationchange.lightbox' + this.ekey); document.dxOff('keyup.lightbox' + this.ekey + ' resize.lightbox' + this.ekey + ' orientationchange.lightbox' + this.ekey);
Stack.delete(this);
this.target.dxRemoveData('lightbox'); this.target.dxRemoveData('lightbox');
} }
} }
+1 -8
View File
@@ -2,7 +2,6 @@ import './popover.css';
import { Ut } from '../../utils/Ut'; import { Ut } from '../../utils/Ut';
import { El, $ } from "../../utils/dom"; import { El, $ } from "../../utils/dom";
import { Stack } from '../../core/Stack';
import { Overlay } from '../overlay'; import { Overlay } from '../overlay';
export class Popover { export class Popover {
@@ -29,15 +28,11 @@ export class Popover {
closeBtn : false closeBtn : false
}, ... opts }; }, ... opts };
Stack.widgets.Popover ??= new Map();
if (!this.opts.multiple) { if (!this.opts.multiple) {
// Destroy old instances // Destroy old instances
Stack.widgets.Popover.forEach(popover => popover.destroy()); Boot.widgetStack?.Popover.forEach(popover => popover.destroy());
} }
Stack.add(this);
this.create(); this.create();
this.setPosition(); this.setPosition();
@@ -166,8 +161,6 @@ export class Popover {
this.target.dxRemoveData('popover'); this.target.dxRemoveData('popover');
Stack.delete(this);
Ut.trigger(this.opts.onDestroy, this); Ut.trigger(this.opts.onDestroy, this);
} }
} }
+5 -7
View File
@@ -1,9 +1,9 @@
import './popup.css'; import './popup.css';
import { Boot } from '../../core/Boot';
import { Ut } from '../../utils/Ut'; import { Ut } from '../../utils/Ut';
import { El } from '../../utils/dom'; import { El } from '../../utils/dom';
import { Overlay } from '../overlay'; import { Overlay } from '../overlay';
import { Stack } from '../../core/Stack';
import { Render } from '../../core/Render'; import { Render } from '../../core/Render';
//////////////////// ////////////////////
@@ -39,11 +39,13 @@ export class Popup {
this.opened = false; this.opened = false;
this.ekey = Ut.nextKey();
if (!this.opts.multiple) { if (!this.opts.multiple) {
Stack.widgets.Popup?.forEach((popup, key) => { Boot.widgetStack?.Popup?.forEach(popup => {
if (key == this.ekey - 1) { if (popup.ekey < this.ekey) { // [?]
that.opened = true; that.opened = true;
popup.destroy(_ => that.init()); popup.destroy(_ => that.init());
} }
@@ -64,8 +66,6 @@ export class Popup {
*/ */
init() { init() {
Stack.add(this);
this._plugins = []; this._plugins = [];
this.create(); this.create();
@@ -221,8 +221,6 @@ export class Popup {
that._plugins.forEach(widget => widget.destroy()); that._plugins.forEach(widget => widget.destroy());
Stack.delete(this);
that.target.dxRemoveData('popup'); that.target.dxRemoveData('popup');
Ut.trigger(callback); Ut.trigger(callback);
+5 -8
View File
@@ -1,7 +1,7 @@
import './select-box.css'; import './select-box.css';
import { El } from '../../utils/dom'; import { El } from '../../utils/dom';
import { Stack } from '../../core/Stack'; import { Ut } from '../../utils/Ut';
export class SelectBox { export class SelectBox {
@@ -19,7 +19,7 @@ export class SelectBox {
this.labels = El('div', { className: 'labels hide' }); this.labels = El('div', { className: 'labels hide' });
this.choices = El('div', { className: 'choices' }); this.choices = El('div', { className: 'choices' });
this.ui = El('div', { className: 'sp-form-control sp-select-box' }, this.el = El('div', { className: 'sp-form-control sp-select-box' },
this.choices, this.choices,
this.labels this.labels
); );
@@ -30,9 +30,9 @@ export class SelectBox {
this.labels.append(el.parentElement); this.labels.append(el.parentElement);
}, this); }, this);
parent.append(this.ui); parent.append(this.el);
Stack.add(this); this.ekey = Ut.nextKey();
this.setEvents(); this.setEvents();
} }
@@ -44,7 +44,7 @@ export class SelectBox {
let that = this; let that = this;
this.ui.dxOn('click', function(e) { this.el.dxOn('click', function(e) {
e.stopPropagation(); e.stopPropagation();
that.labels.classList.toggle('hide'); that.labels.classList.toggle('hide');
}); });
@@ -85,10 +85,7 @@ export class SelectBox {
* Select Box, Destroy * Select Box, Destroy
*/ */
destroy() { destroy() {
window.dxOff('resize.selectbox' + this.ekey + ' orientationchange.selectbox' + this.ekey); window.dxOff('resize.selectbox' + this.ekey + ' orientationchange.selectbox' + this.ekey);
document.dxOff('click.selectbox' + this.ekey); document.dxOff('click.selectbox' + this.ekey);
Stack.delete(this);
} }
} }
+231 -216
View File
@@ -4,22 +4,26 @@ import { Ut } from "../../utils/Ut";
import { El } from "../../utils/dom"; import { El } from "../../utils/dom";
import { Cancelable } from '../cancelable'; import { Cancelable } from '../cancelable';
import { DatePicker } from '../date-picker'; import { DatePicker } from '../date-picker';
import { Stack } from '../../core/Stack'; import { Boot } from '../../core/Boot';
export class TwoDatePicker { export class TwoDatePicker {
/** #hasRendered = false;
* TwoDatePicker Constructor #isOpened = false;
*/ #isInput = false;
constructor(target, opts, events) { #isToggled = false;
constructor(target, opts) {
this.target = target; this.target = target;
if (this.target.dxData('two_datepicker')) { if (this.target.dxWidget() || this.target.dxData('two_datepicker')) {
return; return;
} }
this.target.dxData('two_datepicker', this); this.target.dxData('two_datepicker', this);
this.target.dxWidget(this);
Boot.addWidget(this);
this.opts = { ... { this.opts = { ... {
style : 'normal', style : 'normal',
@@ -27,320 +31,331 @@ export class TwoDatePicker {
fullMonth : true, fullMonth : true,
navDisabled : false, navDisabled : false,
anim : true, anim : true,
dateFormat : 'dd/mm/yyyy',
valueFormat : 'dd-mm-yyyy',
valSeparator: '-',
dateSeparator: ' - ',
locales : 'ro-RO', locales : 'ro-RO',
cancelable : true, defaultDate : null,
hiddenMode : false, render : true,
showOnClick : true
}, ... opts }; }, ... 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.target.setAttribute('autocomplete', 'off');
this.isToggled = true; 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 = { const dpOpts = {
style : this.opts.style, style : this.opts.style,
disabled : this.opts.disabled, disabled : this.opts.disabled,
fullMonth : this.opts.fullMonth, fullMonth : this.opts.fullMonth,
navDisabled : this.opts.navDisabled, 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, { if (this.#isInput) {
init: datepicker => that.datepicker[0] = datepicker,
onSelect: (_, val) => this.selectDate(0, val) 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, { this.secondDp = new DatePicker(El('div', { className: 'ui-col' }), {
init: datepicker => that.datepicker[1] = datepicker, ... dpOpts,
onSelect: (_, val) => this.selectDate(1, val) 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') ) { this.#initUi();
new Cancelable(this.target); }
}
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 { else {
this.target.after(this.ui); this.target.after(this.el);
} }
this.target.setAttribute('autocomplete', 'off'); this.target.setAttribute('autocomplete', 'off');
} }
else { else {
this.target.append(this.ui); this.target.append(this.el);
} }
this.#bindUiEvents();
this.#hasRendered = true;
Ut.trigger(this.opts.onInit, this); Ut.trigger(this.opts.onInit, this);
} }
/** #selectDate(index, val) {
* TwoDatePicker, Select Value
*/
selectDate(index, val) {
Ut.trigger(this.opts.onSelect, this, index, val); Ut.trigger(this.opts.onSelect, this, index, val);
const firstDp = this.datepicker[0]; if (index === 0) {
const secondDp = this.datepicker[1];
if (index == 0) {
secondDp.clear(); this.secondDp.enable();
secondDp.minDate = firstDp.selectedDate; this.secondDp.clear();
if (firstDp.month != secondDp.month) { this.secondDp.setDateRange({ minDate: this.firstDp.selectedDate });
secondDp.year = firstDp.year;
secondDp.month = firstDp.month;
secondDp.makeUI();
}
else {
secondDp.setDateRange({ minDate: firstDp.selectedDate });
}
return; return;
} }
if (!firstDp.selectedDate) { this.#setValue();
this.target.value = '';
return;
}
this.target.value = `${this.dateFormat(firstDp.selectedDate)} - ${this.dateFormat(secondDp.selectedDate)}`;
this.hide(); this.hide();
Ut.trigger(this.opts.onChange, this); Ut.trigger(this.opts.onChange, this);
this.target.dxTrigger('changed'); this.target.dxTrigger('changed');
} }
/** #setValue() {
* TwoDatepicker, Date Format
*/ const clear = !this.firstDp.selectedDate || !this.secondDp.selectedDate;
dateFormat(date) {
return date.toLocaleDateString(this.opts.locales, { this.value = !clear ? `${this.firstDp.value}${this.opts.valSeparator}${this.secondDp.value}` : '';
day : '2-digit', this.displayValue = !clear ? `${this.firstDp.displayValue}${this.opts.dateSeparator}${this.secondDp.displayValue}` : '';
month : '2-digit',
year : 'numeric' if (this.#isInput) {
}); this.target.value = this.displayValue;
//.replace(/\./g, '/'); }
}; }
/**
* TwoDatePicker, Show UI
*/
show() { show() {
this.ui.classList.remove('hidden'); if (this.#isOpened) {
return;
if (this.opts.anim) {
this.ui.classList.add('visible');
} }
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); Ut.trigger(this.opts.onShow, this);
} }
/**
* TwoDatePicker, Hide UI
*/
hide() { hide() {
if (this.isOpen) { if (this.#isOpened) {
this.ui.classList.add('hidden'); this.el.classList.add('hidden');
if (this.opts.anim) { 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); Ut.trigger(this.opts.onHide, this);
} }
} }
/** #reposition() {
* TwoDatePicker, Set UI Posituion
*/
setPosition() {
let left = Math.round(this.target.dxOffset().left); let left = Math.round(this.target.dxOffset().left);
if ((this.ui.clientWidth + left) > window.innerWidth) { if ((this.el.clientWidth + left) > window.innerWidth) {
left = 0; left = 0;
} }
this.ui.dxCss({ this.el.dxCss({
top : (Math.round(this.target.dxOffset().top) + this.target.clientHeight + 2) + 'px', top : (Math.round(this.target.dxOffset().top) + this.target.clientHeight + 2) + 'px',
left : left + 'px', left : left + 'px',
}); });
} }
/**
* TwoDatePicker, Clear Val
*/
clear() { clear() {
this.firstDp.clear();
if (this.isToggled) { this.secondDp.clear();
this.secondDp.disable();
if (this.opts.cancelable) { this.#setValue();
this.target.dxData('cancelable').iconHandler.classList.add('hide');
}
if (this.#isToggled) {
this.target.dxData('cancelable').iconHandler.classList.add('hide');
this.hide(); this.hide();
} }
}
if (this.isInput) { getValue() {
this.target.dxVal(''); 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(); if (val.length != 2) {
this.datepicker[1].clear(); 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() { destroy() {
this.datepicker[0].destroy(); this.firstDp.destroy();
this.datepicker[1].destroy(); this.secondDp.destroy();
this.ui.remove(); if (this.#hasRendered) {
this.el.remove();
if (this.isToggled) { if (this.#isToggled) {
document.dxOff(`pointerdown.twodatepicker.${this.ekey}`);
this.target.dxOff('click.two_datepicker keydown.two_datepicker paste.two_datepicker restore.two_datepicker'); window.dxOff(`resize.two_datepicker.${this.ekey} orientationchange.two_datepicker.${this.ekey}`);
}
document.body.dxOff('click.two_datepicker' + this.ekey);
window.dxOff('scroll.two_datepicker resize.two_datepicker' + this.ekey + ' orientationchange.two_datepicker' + this.ekey);
} }
this.target.dxRemoveData('two_datepicker'); this.target.dxRemoveData('two_datepicker');
this.target.dxRemoveWidget();
Stack.delete(this);
Ut.trigger(this.opts.onDestroy, this); Ut.trigger(this.opts.onDestroy, this);
} }
@@ -4,7 +4,7 @@
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
border-radius: 4px; border-radius: 4px;
overflow: hidden; background-color: #fff;
} }
.sp-two-datepicker .ui-col:last-child { .sp-two-datepicker .ui-col:last-child {