// Get an element by id or an Element object function getelem(id) { return (id instanceof Element) ? id : document.getElementById(id); } // Read a key=value text file and return it as a Promise of a Map function fetchconfig(url) { var xdr = new XMLHttpRequest(); return fetch(url, {cache: "no-store"}) .then(res => { if (!res.ok) { throw new Error("HTTP error "+response.status); } else { return res.text(); } }) .then(text => { var map = new Map(); for (const c of text.split(/[\r\n]+/)) { const eqs = c.indexOf("="); if (eqs > 0) { map.set(c.slice(0, eqs), c.slice(eqs+1)); } } return map; }); } // Initialize a form from a map function initform(form,map) { var button = null; var clearers = new Map; form = getelem(form); for (var field of form.elements) { if (field instanceof HTMLInputElement && !field.classList.contains("noload")) { var val = map.get(field.name); if (val == undefined) val = ''; if (field.type == 'checkbox') { const checked = !val.match(/^(0*|[fn].*|of.*)$/i); field.checked = checked; if (checked) { const clearer_name = '-' + field.name; if (!clearers.has(clearer_name)) { clearers.set(clearer_name, 1); } } } else if (field.type == 'radio') { field.checked = (val == field.name); } else if (field.type == 'hidden') { clearers.set(field.name, 0); } else { field.value = val; } } else if (field instanceof HTMLButtonElement && field.type == 'submit') { button = field; } } for (const [what, need] of clearers) { if (need) { var clearer = document.createElement('INPUT'); clearer.type = 'hidden'; clearer.name = what; form.prepend(clearer); } } if (button) { button.disabled = false; // All loaded, enable the submit button } } // Load form initialization data function loadform(form, url) { fetchconfig(url) .then(map => { initform(form, map) }) .catch(() => {}); } // Insert status data from a map function initstatus(map) { for (const [key,val] of map) { var e = document.getElementById(key); if (e) { e.innerText = val; } } } // Load status data function loaddata(url) { fetchconfig(url) .then(map => { initdata(map) }) .catch(() => {}); } // POST file upload with progress and response text function uploadfile(event) { event.preventDefault(); var form = event.currentTarget; var elem = form.elements; var files = elem["file"].files; if (files.length != 1) { /* Show error */ return; } var file = files[0]; var xhr = new XMLHttpRequest(); var progress = form.querySelector("progress"); if (progress != undefined) { progress.value = 0; xhr.upload.addEventListener("progress", (event) => { if (event.lengthComputable) { progress.max = event.total; progress.value = event.loaded; } }); } var result = form.querySelector("pre.result"); if (result != undefined) { result.className = "result hide"; } xhr.addEventListener("loadend", (event) => { const ok = xhr.status >= 200 && xhr.status <= 299; if (progress != undefined) { progress.value = ok ? progress.max : 0; } if (result != undefined) { result.className = "result " + (ok ? "ok" : "err"); result.innerText = xhr.responseText; } }); xhr.open("POST", form.action); xhr.responseType = 'text'; xhr.send(file); } // Enable a button (this ensures that the necessary scripts have been // run before one can submit) function enablebutton(id,on) { getelem(id).disabled = !on; } // Flip the status of an INPUT element between text and password function showpwd(id,me) { var pwd = getelem(id); const was_visible = pwd.getAttribute('type') == 'text'; const new_type = was_visible ? 'password' : 'text'; const new_icon = was_visible ? 'show' : 'hide'; pwd.setAttribute('type', new_type); me.innerHTML = new_icon; } // Hack to include an HTML files. Sadly, does not support // including files with