init here
This commit is contained in:
112
frontend/utils.js
Normal file
112
frontend/utils.js
Normal file
@@ -0,0 +1,112 @@
|
||||
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}`;
|
||||
}
|
||||
Reference in New Issue
Block a user