113 lines
3.0 KiB
JavaScript
113 lines
3.0 KiB
JavaScript
export const $ = (sel, root = document) => root.querySelector(sel);
|
|
export const $$ = (sel, root = document) =>
|
|
Array.from(root.querySelectorAll(sel));
|
|
|
|
export function el(tag, attrs = {}, children = []) {
|
|
const node = document.createElement(tag);
|
|
Object.entries(attrs).forEach(([k, v]) => {
|
|
if (k === "class") node.className = v;
|
|
else if (k.startsWith("on") && typeof v === "function")
|
|
node.addEventListener(k.slice(2), v);
|
|
else if (v !== undefined && v !== null) node.setAttribute(k, v);
|
|
});
|
|
for (const ch of Array.isArray(children) ? children : [children]) {
|
|
if (typeof ch === "string") node.appendChild(document.createTextNode(ch));
|
|
else if (ch) node.appendChild(ch);
|
|
}
|
|
return node;
|
|
}
|
|
|
|
export function formToJSON(form) {
|
|
const data = {};
|
|
const coerceNumberIfNeeded = (key, value) => {
|
|
const field = form.elements.namedItem(key);
|
|
let isNumber = false;
|
|
let integerOnly = false;
|
|
|
|
const inspect = (el) => {
|
|
if (!el) return;
|
|
if (el.getAttribute && el.getAttribute("data-type") === "number") {
|
|
isNumber = true;
|
|
}
|
|
if (el.getAttribute && el.getAttribute("data-integer") === "true") {
|
|
isNumber = true;
|
|
integerOnly = true;
|
|
}
|
|
if (el.tagName === "INPUT") {
|
|
const type = (el.type || "").toLowerCase();
|
|
if (type === "number") {
|
|
isNumber = true;
|
|
const step = el.step;
|
|
if (
|
|
step &&
|
|
(step === "1" || (!step.includes(".") && step !== "any"))
|
|
) {
|
|
integerOnly = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if (
|
|
field &&
|
|
typeof RadioNodeList !== "undefined" &&
|
|
field instanceof RadioNodeList
|
|
) {
|
|
inspect(field[0]);
|
|
} else {
|
|
inspect(field);
|
|
}
|
|
|
|
if (isNumber) {
|
|
if (value === "" || value === null) return null;
|
|
const n = Number(value);
|
|
if (Number.isNaN(n)) return null;
|
|
return integerOnly ? Math.trunc(n) : n;
|
|
}
|
|
return value;
|
|
};
|
|
|
|
new FormData(form).forEach((v, k) => {
|
|
const val = coerceNumberIfNeeded(k, v);
|
|
if (data[k] !== undefined) {
|
|
if (!Array.isArray(data[k])) data[k] = [data[k]];
|
|
data[k].push(val);
|
|
} else data[k] = val;
|
|
});
|
|
return data;
|
|
}
|
|
|
|
export function saveSession(session) {
|
|
localStorage.setItem("srab.session", JSON.stringify(session));
|
|
}
|
|
export function loadSession() {
|
|
try {
|
|
return JSON.parse(localStorage.getItem("srab.session")) || null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
export function clearSession() {
|
|
localStorage.removeItem("srab.session");
|
|
}
|
|
|
|
export function setTopUser(text) {
|
|
$("#top-user").textContent = text || "";
|
|
}
|
|
export function setLogoutVisible(vis) {
|
|
$("#btn-logout").hidden = !vis;
|
|
}
|
|
|
|
export function setAvg(text) {
|
|
const n = $("#top-avg");
|
|
n.textContent = text || "";
|
|
n.className = "avg badge ok";
|
|
}
|
|
|
|
export function fmtDateInput(d = new Date()) {
|
|
const yyyy = d.getFullYear();
|
|
const mm = String(d.getMonth() + 1).padStart(2, "0");
|
|
const dd = String(d.getDate()).padStart(2, "0");
|
|
return `${yyyy}-${mm}-${dd}`;
|
|
}
|