Files
srab/frontend/utils.js
2025-11-26 21:32:41 +03:00

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}`;
}