diff options
| author | Marin Ivanov <[email protected]> | 2024-08-20 16:50:32 +0300 |
|---|---|---|
| committer | Marin Ivanov <[email protected]> | 2024-08-20 16:50:32 +0300 |
| commit | 7661fbf35526696c6a563e8d6378e040930a0de9 (patch) | |
| tree | e51dc0a2b856df92a1c37f88dfc1fd607d77cd61 | |
| parent | da5fd96e5e9364a6ae26a9a2ffe5dad294d93ec7 (diff) | |
V2
| -rw-r--r-- | app.js | 226 | ||||
| -rw-r--r-- | index.html | 21 | ||||
| -rw-r--r-- | ka.js | 114 |
3 files changed, 187 insertions, 174 deletions
@@ -1,106 +1,132 @@ -let isLoading = 0; -const loading = (val) => { - isLoading = val; - loader.$cls(isLoading ? "" : "hidden"); -} -loader.$click(() => loading(0)); +(() => { + let isLoading = 0; + const loading = (val) => { + isLoading = val; + loader.$cls(isLoading ? "" : "hidden"); + } + loader.$click(() => loading(0)); -let error = null; -function errClose() { - error = null; - app.reload(); -} -let data = {}; -function onerror(err) { - error = err; - console.error(err); - app.reload(); -} -function parsedata(r) { - return Object.fromEntries(r.split("\n").map(x=>x.trim()).filter(x=>x).map(x=>x.split('='))); -} -function cmd(url, body) { - return fetch(url, {method:body?'POST':'GET', body}) - .then(r => { - if (!r.ok){ - throw new Error(r.statusText); - } - return r.text(); - }) - .then(r => parsedata(r)); -}; -function loadconfig() { - loading(1); - cmd("/cgi-bin/getconfig") - .then(x => { - data = x; - app.reload(); - }) - .catch(onerror) - .then(() => loading(0)) -} -function saveconfig(groups) { - cmd("/cgi-bin/setconfig", data) - .catch(onerror) - .then(loadconfig) -} - -function CErr(text) { - var el = div( - div("🗙").$cls("close").$click(errClose), - span("⚠ "), - text, - ).$cls("err"); + let error = null; function errClose() { error = null; - el.remove(); - }; - return el; -} + app.reload(); + } + let data = {}; + function onerror(err) { + error = err; + console.error(err); + app.reload(); + } + function parsedata(r) { + return Object.fromEntries(r.split("\n").map(x=>x.trim()).filter(x=>x).map(x=>x.split('='))); + } + function cmd(url, body) { + return fetch(url, {method:body?'POST':'GET', body}) + .then(r => { + if (!r.ok){ + throw new Error(r.statusText); + } + return r.text(); + }) + .then(r => parsedata(r)); + }; + function loadconfig() { + loading(1); + cmd("/cgi-bin/getconfig") + .then(x => { + data = x; + app.reload(); + }) + .catch(onerror) + .then(() => loading(0)) + } + function saveconfig(groups) { + cmd("/cgi-bin/setconfig", data) + .catch(onerror) + .then(loadconfig) + } -const routes = { - "/": () => div( - h2("Lorem Ipsum"), - p("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "), - p("Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."), - ), - "/network": () => div( - error && CErr(error.message), - h1("Network settings"), - table( - tr( - td("IP"), - td(input("text").$value(data["cfg.ip"])), - ), - tr( - td("MAC"), - td( - input("text").$value(data["cfg.mac"]) - .$change2state(data, "cfg.mac") + function CErr(text) { + var el = div( + div("🗙").$cls("close").$click(errClose), + span("⚠ "), + text, + ).$cls("err"); + function errClose() { + error = null; + el.remove(); + }; + return el; + } + function CNav(navs) { + return (h) => nav( + labelfor("showmenu", span("☰"), " Menu"), + input("checkbox").$attr("id", "showmenu"), + ...navs.map(([href,txt]) => ahref(href,txt).$cls(href===h?"active":"")) + ); + } + function CRouter(routes) { + return (h) => { + const p = h.substr(1) || "/"; + const r = p in routes ? p : ""; + return routes[r](); + } + } + const navbar = CNav([ + ["#", "Home"], + ["#/network", "Network"], + ["#/config", "Configuration"], + ["#/tools", "Tools"], + ]); + const router = CRouter({ + "/": () => div( + h2("Lorem Ipsum"), + p("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "), + p("Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."), + ), + "/network": () => div( + h1("Network settings"), + table( + tr( + td("IP"), + td(input("text").$value(data["cfg.ip"])), ), - ) - ).$cls("network"), - input("button").$value("Save").$click(saveconfig) - ), - "/config": () => { - return div(); - }, - "/waiting": () => { - loading(1); - setTimeout(() => { - loading(0); - }, 3000); - return div(""); - }, - "": () => div( - h1("Not Found"), - p("The requested page is not available.") - ), -}; -const onchange = (h) => { - doc.querySelectorAll('nav a').forEach(x => x.$cls(x.attr("href")===h?"active":"")); - loading(isLoading); -}; + tr( + td("MAC"), + td( + input("text").$value(data["cfg.mac"]) + .$change2state(data, "cfg.mac") + ), + ) + ).$cls("network"), + input("button").$value("Save").$click(saveconfig) + ), + "/config": () => { + return div(); + }, + "/waiting": () => { + loading(1); + setTimeout(() => { + loading(0); + }, 3000); + return div(""); + }, + "": () => div( + h1("Not Found"), + p("The requested page is not available.") + ), + }); + function app(h) { + loading(isLoading); + return [ + div(error && CErr(error.message)).$cls("noflex"), + main( + navbar(h), + section(router(h)) + ), + ]; + } -router(app, routes, onchange); -loadconfig(); + mount(root, app); + loadconfig(); +})() @@ -8,26 +8,17 @@ <body> <div class="container"> <header><big>🛠️ WebIF 2.0</big></header> - <main> - <nav> - <label for="showmenu"><span>☰</span> Меню</label> - <input type="checkbox" id="showmenu" /> - - <a class="active" href="#">Home</a> - <a href="#/network">Network</a> - <a href="#/config">Configuration</a> - <a href="#/tools">Tools</a> - </nav> - <section id="app"></section> - </main> + <div id="root"></div> </div> <div id="loader" title="цъкни да скриеш"> <div> <div class="loadspin"></div> <p> - <noscript>Не</noscript> - Зарежда... - <noscript>JavaScript не е включен.</noscript> + Loading... + <noscript> + FAILED. JavaScript is disabled. + <p><a href="command.html">Use Command Interface</a></p> + </noscript> </p> </div> </div> @@ -1,64 +1,60 @@ -var doc = document; -var elproto = Element.prototype; -elproto.attr = function(name){ - return this.getAttribute(name); -}; -elproto.$attr = function(name, value) { - this.setAttribute(name, value); - return this; -}; -elproto.$attrs = function(attrs) { - for (const [attr, value] of Object.entries(attrs)) { - this.$attr(attr, value); - } - return this; -} -elproto.$cls = function(cls) { - return this.$attr("class", cls); -} -elproto.$value = function(value) { - this.value = value; - return this; -} -elproto.$click = function(callback) { - this.onclick = callback; - return this; -} -const getvalue = x => x.value; -elproto.$change2state = function(state, field, valgetter=getvalue) { - this.onchange = () => { - state[field] = valgetter(this); +(()=>{ + doc = document; + + var ep = Element.prototype; + ep.attr = function(name){ + return this.getAttribute(name); + }; + ep.$attr = function(name, value) { + this.setAttribute(name, value); + return this; }; - return this; -} -function tag(name, attrs, ...children) { - const el = doc.createElement(name); - el.$attrs(attrs||{}); - for (const child of children.filter(x=>x)) { - el.appendChild((typeof(child) === 'string') ? doc.createTextNode(child) : child); + ep.$attrs = function(attrs) { + Object.entries(attrs).forEach(([attr, value]) => this.$attr(attr, value)); + return this; } - return el; -} - -const TRIVIAL = "h1,h2,h3,p,,div,span,select,table,tr,td"; -for (let name of TRIVIAL.split(",")) { + ep.$cls = function(cls) { + return this.$attr("class", cls); + } + ep.$value = function(value) { + this.value = value; + return this; + } + ep.$click = function(callback) { + this.onclick = callback; + return this; + } + const getvalue = x => x.value; + ep.$change2state = function(state, field, valgetter=getvalue) { + this.onchange = () => { + state[field] = valgetter(this); + }; + return this; + } + tag = (name, attrs, ...children) => { + const el = doc.createElement(name); + el.$attrs(attrs||{}); + for (const child of children.filter(x=>x)) { + el.appendChild((typeof(child) === 'string') ? doc.createTextNode(child) : child); + } + return el; + } + ahref = (href, ...children) => tag("a", {href}, ...children); + labelfor = (for_, ...children) => tag("label", {"for":for_}, ...children); + img = (src) => tag("img", {src}); + input = (type) => tag("input", {type}); + const TRIVIAL = "main,section,nav,h1,h2,h3,p,,div,span,select,table,tr,td"; + for (let name of TRIVIAL.split(",")) { window[name] = (...children) => tag(name, null, ...children); -} - -var ahref = (href, ...children) => tag("a", {href}, ...children); -var img = (src) => tag("img", {src}); -var input = (type) => tag("input", {type}); + } -function router(root, routes, onreload) { - function reload() { - const h = doc.location.hash || "#"; - const p = h.substr(1) || "/"; - const r = p in routes ? p : ""; - root.replaceChildren(routes[r]()); - onreload && onreload(h); + mount = (root, app) => { + function reload() { + const h = doc.location.hash || "#"; + root.replaceChildren(...app(h)); + }; + reload(); + window.addEventListener("hashchange", reload); + app.reload = reload; }; - reload(); - window.addEventListener("hashchange", reload); - root.reload = reload; -} - +})() |
