summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarin Ivanov <[email protected]>2024-08-20 16:50:32 +0300
committerMarin Ivanov <[email protected]>2024-08-20 16:50:32 +0300
commit7661fbf35526696c6a563e8d6378e040930a0de9 (patch)
treee51dc0a2b856df92a1c37f88dfc1fd607d77cd61
parentda5fd96e5e9364a6ae26a9a2ffe5dad294d93ec7 (diff)
V2
-rw-r--r--app.js226
-rw-r--r--index.html21
-rw-r--r--ka.js114
3 files changed, 187 insertions, 174 deletions
diff --git a/app.js b/app.js
index aa1fcdc..e9dfc60 100644
--- a/app.js
+++ b/app.js
@@ -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();
+})()
diff --git a/index.html b/index.html
index 7a19004..363f319 100644
--- a/index.html
+++ b/index.html
@@ -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>
diff --git a/ka.js b/ka.js
index 09257c7..a14ae7f 100644
--- a/ka.js
+++ b/ka.js
@@ -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;
-}
-
+})()