ui-lib/lib/ui/date.js

176 lines
4.8 KiB
JavaScript

import { createElement } from "../functions";
export function createDateInput(min, max, element) {
let date;
if (element instanceof HTMLInputElement) {
date = element;
date.classList.add('ui-date-cell');
} else {
date = createElement('input', 'ui-date-cell');
}
date.required = true;
date.type = 'date';
if (min != null) {
date.min = min;
}
if (max != null) {
date.max = max;
}
return date;
}
function toDateValue(dt) {
if (isNaN(dt)) {
return '';
}
const month = String(dt.getMonth() + 1).padStart(2, '0');
const date = String(dt.getDate()).padStart(2, '0');
return `${dt.getFullYear()}-${month}-${date}`;
}
function resolveDate(s) {
if (s instanceof Date) {
return s;
}
const ticks = Number(s);
if (!isNaN(ticks) && ticks > 0) {
return new Date((ticks - 621355968e9) / 1e4);
}
return new Date(s);
}
export function formatDate(date) {
date = resolveDate(date);
if (date instanceof Date && !isNaN(date)) {
return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`;
}
return '';
}
export function setDateValue(element, val) {
if (element.tagName === 'INPUT') {
if (val === '') {
element.value = '';
} else if (isNaN(val)) {
if (/^\d{4}-\d{2}-\d{2}$/.test(val)) {
element.value = val;
} else if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(val)) {
element.value = toDateValue(new Date(val));
} else {
element.value = '';
}
} else {
if (!(val instanceof Date)) {
val = new Date((val - 621355968e9) / 1e4);
}
element.value = toDateValue(val);
}
} else {
element.innerText = formatDate(val);
}
}
export function getDateValue(element, formatter) {
const date = element?.valueAsDate;
if (date instanceof Date && !isNaN(date)) {
const year = date.getFullYear();
if (year < 1900 || year > 9999) {
return '';
}
if (typeof formatter === 'function') {
return formatter(date);
}
return String(date.getTime() * 1e4 + 621355968e9);
}
return '';
}
export class DateSelector {
_var = {
parent: null,
options: null
};
onDateChanged;
constructor(opts) {
opts ??= {};
this._var.options = opts;
}
create(element) {
const opts = this._var.options;
const el = createDateInput(opts.minDate, opts.maxDate, element);
if (element == null) {
el.disabled = opts.enabled === false;
}
el.addEventListener('blur', e => {
const date = this._getDate(e.target.valueAsDate);
if (date == null) {
e.target.value = '';
}
if (typeof this.onDateChanged === 'function') {
this.onDateChanged(date);
}
});
this._var.el = el;
return el;
}
get element() { return this._var.el }
get enabled() { return !this._var.el.disabled }
set enabled(flag) {
this._var.el.disabled = flag === false;
}
get value() { return this._getDate(this._var.el.valueAsDate) }
set value(val) {
setDateValue(this._var.el, val);
}
get minDate() { return this._var.el.min }
set minDate(date) {
this._var.el.min = date;
this._var.options.minDate = date;
}
get maxDate() { return this._var.el.max }
set maxDate(date) {
this._var.el.max = date;
this._var.options.maxDate = date;
}
_getDate(date) {
if (date instanceof Date && !isNaN(date)) {
const year = date.getFullYear();
if (year < 1900 || year > 9999) {
return null;
}
if (typeof this._var.options.valueFormatter === 'function') {
return this._var.options.valueFormatter(date);
}
return date;
}
return null;
}
static resolve(dom = document.body, trigger) {
const dates = dom.querySelectorAll('input[data-type="date"]');
for (let dat of dates) {
const val = dat.value;
const dateSelector = new DateSelector({
minDate: dat.getAttribute('data-min'),
maxDate: dat.getAttribute('data-max')
});
if (typeof trigger === 'function') {
dateSelector.onDateChanged = date => trigger.call(dateSelector, date);
}
dat.removeAttribute('data-type');
dat.removeAttribute('data-min');
dat.removeAttribute('data-max');
dateSelector.create(dat);
dateSelector.value = val;
}
}
}