web-ui-pack
Version:
Web package with UI elements
261 lines (260 loc) • 9.4 kB
JavaScript
import dateCompareWithoutTime from "../helpers/dateCompareWithoutTime";
import dateCopyTime from "../helpers/dateCopyTime";
import dateFromString from "../helpers/dateFromString";
import dateToString from "../helpers/dateToString";
import localeInfo from "../objects/localeInfo";
import WUPTimeObject from "../objects/timeObject";
import WUPBaseComboControl from "./baseCombo";
import WUPCalendarControl from "./calendar";
WUPCalendarControl.$use();
const tagName = "wup-date";
export default class WUPDateControl extends WUPBaseComboControl {
#ctr = this.constructor;
static get $style() {
return `${super.$style}
:host {
--ctrl-icon-img: var(--wup-icon-date);
}
:host > [menu] {
overflow: hidden;
}
:host > [menu] > wup-calendar {
margin: 0;
}`;
}
static get mappedAttributes() {
const m = super.mappedAttributes;
m.min = { type: 4 };
m.max = { type: 4 };
m.firstweekday = { type: 1 };
m.startwith = { type: 2 };
m.sync = { type: 6 };
return m;
}
static $defaults = {
...WUPBaseComboControl.$defaults,
...WUPCalendarControl.$defaults,
validationRules: {
...WUPBaseComboControl.$defaults.validationRules,
min: (v, setV, c) => (v === undefined || dateCompareWithoutTime(v, setV, c._opts.utc) === -1) &&
__wupln(`Min value is ${c.valueToInput(setV)}`, "validation"),
max: (v, setV, c) => (v === undefined || dateCompareWithoutTime(v, setV, c._opts.utc) === 1) &&
__wupln(`Max value is ${c.valueToInput(setV)}`, "validation"),
exclude: (v, setV, c) => (v === undefined || setV.some((d) => dateCompareWithoutTime(v, d, c._opts.utc) === 0)) &&
__wupln(`This value is disabled`, "validation"),
},
format: "",
sync: null,
};
get $initValue() {
return super.$initValue;
}
set $initValue(v) {
super.$initValue = v;
this.setTimeValue(this.refTime, v, 5);
}
constructor() {
super();
this.#ctr.$defaults.firstWeekDay ||= localeInfo.firstWeekDay;
this._opts.firstWeekDay ||= this.#ctr.$defaults.firstWeekDay;
this.#ctr.$defaults.format ||= localeInfo.date.toLowerCase();
this._opts.format ||= this.#ctr.$defaults.format;
}
parse(text) {
if (!text) {
return undefined;
}
return WUPCalendarControl.$parse(text, !!this._opts.utc);
}
parseInput(text) {
const format = `${this._opts.format.toUpperCase()} hh:mm:ss.fff${this._opts.utc ? "Z" : ""}`;
const v = dateFromString(text, format, { throwOutOfRange: true }) ?? undefined;
return v;
}
canParseInput(_text) {
return !this.refMask || this.refMask.isCompleted;
}
valueToStorage(v) {
return dateToString(v, `yyyy-MM-dd${this._opts.utc ? "Z" : ""}`);
}
gotChanges(propsChanged) {
WUPCalendarControl.prototype.gotChangesSharable.call(this);
this._opts.format ||= "YYYY-MM-DD";
if (this._opts.format.toUpperCase().includes("MMM")) {
this.throwError(`'MMM' in format isn't supported`);
this._opts.format = "YYYY-MM-DD";
}
this._opts.mask ||= this._opts.format
.replace(/[yY]/g, "0")
.replace(/dd|DD/, "00")
.replace(/[dD]/, "#0")
.replace(/mm|MM/, "00")
.replace(/[mM]/, "#0");
this._opts.maskholder ||= this._opts.format.replace(/([mMdD]){1,2}/g, "$1$1");
const el = this.refTime;
if (el) {
if (this._opts.name && !el.$options.name) {
el.$options.name = "";
}
this.setTimeValidations(el);
}
super.gotChanges(propsChanged);
}
get validations() {
const vls = super.validations;
if (this._opts.min)
vls.min = this._opts.min;
if (this._opts.max)
vls.max = this._opts.max;
if (this._opts.exclude)
vls.exclude = this._opts.exclude;
return vls;
}
renderMenu(popup, menuId) {
popup.$options.minWidthByTarget = false;
const el = document.createElement("wup-calendar");
el.renderInput = () => {
el.$refLabel.remove();
return { menuId };
};
el.focusItem = (a) => this.focusMenuItem(a);
el.focus = () => true;
el.gotFocus.call(el, new FocusEvent("focusin"));
el.setInputValue = () => { };
el.gotFormChanges = () => { };
el.$refInput = this.$refInput;
el.$options.validations = this.validations.required ? { required: true } : undefined;
el.$options.startWith = this._opts.startWith;
el.$options.exclude = this._opts.exclude;
el.$options.max = this._opts.max;
el.$options.min = this._opts.min;
el.$options.utc = this._opts.utc;
el.$options.name = undefined;
el.$options.validationCase = 0;
const v = this.$value;
el.$initValue = v && !Number.isNaN(v.valueOf()) ? v : undefined;
el.setValue = (val, reason) => {
const r = WUPCalendarControl.prototype.setValue.call(el, val, reason);
if (reason === 4) {
this.selectValue(el.$value);
}
return r;
};
el.$onChange = (e) => e.stopPropagation();
popup.appendChild(el);
return el;
}
setValue(v, reason, skipInput = false) {
const elTime = this.refTime;
if (v) {
let isCopied = false;
if (skipInput) {
const prev = this.$value || this.$initValue;
prev && dateCopyTime(v, prev, this._opts.utc);
isCopied = !!prev;
}
if (!isCopied && reason !== 1 && reason !== 5) {
const vt = elTime?.$value;
if (vt) {
v = vt.copyToDate(v, this._opts.utc);
}
}
}
const isChanged = super.setValue(v, reason, skipInput);
if (isChanged) {
const c = this.$refPopup?.firstElementChild;
if (c) {
c._isStopChanges = true;
c.$value = v && !Number.isNaN(v.valueOf()) ? v : undefined;
setTimeout(() => (c._isStopChanges = false));
}
}
if (elTime) {
this.setTimeValidations(elTime);
if (reason === 1) {
this.setTimeValue(elTime, v, reason);
}
else if (elTime.$value) {
!elTime.$isEmpty && elTime.$validate();
}
}
return isChanged;
}
valueToInput(v) {
if (v === undefined) {
return "";
}
return dateToString(v, this._opts.format.toUpperCase() + (this._opts.utc ? "Z" : ""));
}
focusMenuItem(next) {
const el = this.$refPopup?.firstElementChild;
if (el) {
Object.getPrototypeOf(el).focusItem.call(el, next);
}
else {
this.$refInput.removeAttribute("aria-activedescendant");
}
this._focusedMenuItem = next;
}
focusMenuItemByKeydown(e) {
const clnd = this.$refPopup?.firstElementChild;
clnd.gotKeyDown.call(clnd, e);
}
get refTime() {
const s = this._opts.sync;
if (s && typeof s === "string") {
this._opts.sync = this.findBySelector(s);
}
return this._opts.sync;
}
setTimeValue(elTime, v, reason) {
if (!elTime) {
return;
}
delete elTime.setValue;
const t = v && new WUPTimeObject(v, this._opts.utc);
switch (reason) {
case 5:
elTime.$initValue = t;
break;
case 1:
elTime.$value = t;
break;
}
const orig = Object.getPrototypeOf(elTime).setValue;
elTime.setValue = (...args) => {
const isChanged = orig.call(elTime, ...args);
const dt = this.$value;
if (isChanged && dt) {
(elTime.$value || new WUPTimeObject(0, 0)).copyToDate(dt, this._opts.utc);
}
return isChanged;
};
}
setTimeValidations(elTime) {
const v = this.$value;
const obj = {};
const vld = this._opts.validations;
if (v) {
["min", "max"].forEach((k) => {
const dFrom = this._opts[k] || (vld && vld[k]);
if (dFrom) {
if (typeof dFrom === "function") {
this.throwError("Impossible to sync [min] with time. Expected Date instead of function");
return;
}
const c = dateCompareWithoutTime(v, dFrom, this._opts.utc);
obj[k] = c === 0 ? new WUPTimeObject(dFrom, this._opts.utc) : obj[k];
}
});
}
const o = elTime.$options;
o.min = obj.min;
o.max = obj.max;
o.validations ||= {};
o.validations.required = !!vld?.required;
o.validations.min = undefined;
o.validations.max = undefined;
}
}
customElements.define(tagName, WUPDateControl);