// 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) { return fetch(url, {redirect: "follow"}) .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]+/)) { var m = c.match(/^\s*([\;\/]?)((?:"[^"]*"|[^"])*?)\s*=(.*)$/); if (m && m[1] == "") { var k = m[2].replaceAll(/(^"|"$|(")")/g, "$2"); map.set(k, m[3]); } } return map; }); } function boolcfg(str) { return str && !str.match(/^(0*|[fnd].*|of.*)$/i); } // 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 instanceof HTMLSelectElement) && !field.classList.contains("noload")) { const val = map.get(field.name) || ''; if (field.type == 'checkbox') { field.checked = !boolcfg(val); } else if (field.type == 'radio') { field.checked = (val == field.name); field.remove(); } else { field.value = val; } } else if (field instanceof HTMLButtonElement && field.type == 'submit') { button = field; } } 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(() => {}); } // Replace the contents of selected HTML elements based on a map with selectors function fillin(map,html) { for (const [key,val] of map) { try { for (var e of document.querySelectorAll(key)) if (html) e.innerHTML = val; else e.innerText = val; } catch (error) { } } } // Load status or HTML data function load(url,html = false) { fetchconfig(url) .then(map => { fillin(map,html) }) .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 * 1.05; 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); } // POST upload of a form as key=value pairs, *including* transmitting // unchecked checkboxes as name=0. // 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 now_visible = me.classList.toggle('hide'); me.classList.toggle('show',!now_visible); const new_type = now_visible ? 'text' : 'password'; pwd.setAttribute('type', new_type); } // Hack to include an HTML files. Sadly, does not support // including files with