aredn/files/app/main/app.ut

214 lines
8.7 KiB
Plaintext
Executable File

{%
/*
* Part of AREDN® -- Used for creating Amateur Radio Emergency Data Networks
* Copyright (C) 2024 Tim Wilkinson
* See Contributors file for additional contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms:
*
* Additional use restrictions exist on the AREDN® trademark and logo.
* See AREDNLicense.txt for more info.
*
* Attributions to the AREDN® Project must be retained in the source code.
* If importing this code into a new or existing project attribution
* to the AREDN® project must be added to the source code.
*
* You must not misrepresent the origin of the material contained within.
*
* Modified versions must be modified to attribute to the original source
* and be marked in reasonable ways as differentiate it from the original
* version
*/
%}
{% if (!request.headers["hx-boosted"]) { %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
{% if (!config.resourcehash) { %}
<link href="/a/css/theme.css" rel="stylesheet">
<link href="/a/css/user.css" rel="stylesheet">
{% if (request.mobile) { %}
<link href="/a/css/mobile.css" rel="stylesheet">
{% } %}
{% if (auth.isAdmin) { %}
<link href="/a/css/admin.css" rel="stylesheet">
<script src="/a/js/htmx.min.js"></script>
{% } %}
{% } else {
versions.themecss = fs.readlink(`${config.application}/resource/css/theme.version`);
%}
<link href="http://localnode.local.mesh/a/css/theme.{{versions.themecss}}.css" rel="stylesheet" onerror="s=document.createElement('link');s.rel='stylesheet';s.href='/a/css/theme.{{versions.themecss}}.css';document.head.appendChild(s)">
<link href="http://localnode.local.mesh/a/css/user.{{versions.usercss}}.css" rel="stylesheet" onerror="s=document.createElement('link');s.rel='stylesheet';s.href='/a/css/user.{{versions.usercss}}.css';document.head.appendChild(s)">
{% if (request.mobile) { %}
<link href="http://localnode.local.mesh/a/css/mobile.{{versions.mobilecss}}.css" rel="stylesheet" onerror="s=document.createElement('link');s.rel='stylesheet';s.href='/a/css/mobile.{{versions.mobilecss}}.css';document.head.appendChild(s)">
{% } %}
{% if (auth.isAdmin) { %}
<link href="http://localnode.local.mesh/a/css/admin.{{versions.admincss}}.css" rel="stylesheet" onerror="s=document.createElement('link');s.rel='stylesheet';s.href='/a/css/admin.{{versions.admincss}}.css';document.head.appendChild(s)">
<script src="http://localnode.local.mesh/a/js/htmx.min.{{versions.htmx}}.js" onerror="s=document.createElement('script');s.type='text/javascript';s.onload=()=>htmx.process(document.body);s.src='/a/js/htmx.min.{{versions.htmx}}.js';document.head.appendChild(s)"></script>
{% } %}
{% } %}
<link rel="icon" type="image/svg+xml" href="http://localnode.local.mesh/a/img/favicon.svg">
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>{{configuration.getName()}} {{auth.isAdmin && request.page === "status" ? "admin" : request.page}}</title>
</head>
<body class="{{auth.isAdmin ? "authenticated" : ""}} {{request.mobile ? "mobile" : ""}}" hx-indicator="body">
<dialog id="ctrl-modal" onclose="event.target.innerHTML = ''"></dialog>
{% if (!request.mobile) { %}
<div id="all">
<div id="nav">
{{_R("nav")}}
</div>
<div id="panel">
<div id="select">
{{_R("selection")}}
</div>
<div id="main">
<div id="main-container" hx-get="u-{{request.page}}" hx-trigger="visibilitychange[document.visibilityState === 'visible'] from:document">
{{_R(request.page)}}
</div>
</div>
</div>
</div>
{% if (auth.isAdmin) { %}
<script>
(function(){
const m = document.getElementById("ctrl-modal");
document.body.addEventListener("click", e => {
const a = htmx.findAll(".popup-menu input[type=checkbox]:checked");
for (let i = 0; i < a.length; i++) {
if (a[i] !== e.target) {
a[i].checked = false;
}
}
});
document.body.addEventListener("click", e => {
if (!(m.open || document.getSelection().isCollapsed)) {
e.stopPropagation();
}
}, true);
function dialogDone()
{
const d = htmx.find("#dialog-done");
if (d) {
setTimeout(function() {
let invalid = false;
const f = htmx.findAll(m, "form");
for (let i = 0; i < f.length; i++) {
if (!f[i].checkValidity()) {
invalid = true;
break;
}
}
d.disabled = invalid;
}, 10);
}
}
m.addEventListener("input", dialogDone);
m.addEventListener("click", dialogDone);
})();
</script>
{% } %}
{% } else { %}
<div id="m-all">
<div id="m-title">
<a href="http://localnode.local.mesh"><div id="icon-logo"></div></a><div></div>
{{_R("changes")}}
<div class="nav-node-name">{{configuration.getName()}}</div>
</div>
<div id="m-main">
<div id="main-container">
{{_R(request.page)}}
</div>
</div>
<div id="m-nav">
<div>
<a href="status">
<div class="icon status {{request.page === "status"}}"></div>
</a>
</div>
<div>
<a href="mesh">
<div class="icon mesh {{request.page === "mesh"}}"></div>
</a>
</div>
<div>
<div style="margin: 0 calc(50% - 21px);">
{{_R("tools")}}
</div>
</div>
<div>
{{_R("login")}}
</div>
</div>
</div>
<script>
(function(){
const m = document.getElementById("ctrl-modal");
document.body.addEventListener("click", e => {
const a = htmx.findAll(".popup-menu input[type=checkbox]:checked");
for (let i = 0; i < a.length; i++) {
if (a[i] !== e.target) {
a[i].checked = false;
}
}
});
document.body.addEventListener("click", e => {
if (!(m.open || document.getSelection().isCollapsed)) {
e.stopPropagation();
}
}, true);
function dialogDone()
{
const d = htmx.find("#dialog-done");
if (d) {
setTimeout(function() {
let invalid = false;
const f = htmx.findAll(m, "form");
for (let i = 0; i < f.length; i++) {
if (!f[i].checkValidity()) {
invalid = true;
break;
}
}
d.disabled = invalid;
}, 10);
}
}
m.addEventListener("input", dialogDone);
m.addEventListener("click", dialogDone);
document.querySelector("#m-all").addEventListener("click", _ => document.body.focus());
document.querySelector("#ctrl-modal").addEventListener("click", _ => document.body.focus());
})();
</script>
{% } %}
</body>
</html>
{% } else { %}
<title>{{configuration.getName()}} {{auth.isAdmin && request.page === "status" ? "admin" : request.page}}</title>
{{_R("nav-status")}}
<div id="panel" hx-swap-oob="true">
<div id="select">
{{_R("selection")}}
</div>
<div id="main">
<div id="main-container" hx-get="u-{{request.page}}" hx-trigger="visibilitychange[document.visibilityState === 'visible'] from:document">
{{_R(request.page)}}
</div>
</div>
</div>
{% } %}