mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
pikvm/pikvm#1462: relative root location
This commit is contained in:
parent
b51ea5e374
commit
73238e18e9
@ -23,7 +23,7 @@ doctype html
|
||||
==============================================================================
|
||||
|
||||
-
|
||||
var prefix = "./"
|
||||
var root_prefix = "./"
|
||||
|
||||
title = ""
|
||||
main_js = ""
|
||||
@ -36,7 +36,7 @@ block vars
|
||||
|
||||
block _vars_dynamic
|
||||
-
|
||||
share_dir = `${prefix}share`
|
||||
share_dir = `${root_prefix}share`
|
||||
css_dir = `${share_dir}/css`
|
||||
js_dir = `${share_dir}/js`
|
||||
svg_dir = `${share_dir}/svg`
|
||||
@ -61,6 +61,8 @@ html(lang="en")
|
||||
|
||||
if main_js
|
||||
script(type="module")
|
||||
| import {setRootPrefix} from "#{js_dir}/vars.js";
|
||||
| setRootPrefix("#{root_prefix}");
|
||||
| import {main} from "#{js_dir}/#{main_js}.js";
|
||||
| main();
|
||||
|
||||
|
||||
@ -40,7 +40,9 @@
|
||||
<link rel="stylesheet" href="./share/css/modal.css">
|
||||
<link rel="stylesheet" href="./share/css/index/index.css">
|
||||
<link rel="stylesheet" href="./share/css/user.css">
|
||||
<script type="module">import {main} from "./share/js/index/main.js";
|
||||
<script type="module">import {setRootPrefix} from "./share/js/vars.js";
|
||||
setRootPrefix("./");
|
||||
import {main} from "./share/js/index/main.js";
|
||||
main();
|
||||
</script>
|
||||
</head>
|
||||
@ -66,7 +68,7 @@
|
||||
<table>
|
||||
<td class="server">
|
||||
<td>Server:</td>
|
||||
<td><a id="kvmd-meta-server-host" target="_blank" href="/api/info"></a></td>
|
||||
<td><a id="kvmd-meta-server-host" target="_blank" href="./api/info"></a></td>
|
||||
</td>
|
||||
</table>
|
||||
<hr>
|
||||
|
||||
@ -25,7 +25,7 @@ block start
|
||||
table
|
||||
td(class="server")
|
||||
td Server:
|
||||
td #[a#kvmd-meta-server-host(target="_blank" href="/api/info")]
|
||||
td #[a#kvmd-meta-server-host(target="_blank" href=`${root_prefix}api/info`)]
|
||||
|
||||
hr
|
||||
#apps-box
|
||||
|
||||
@ -37,13 +37,15 @@
|
||||
<link rel="stylesheet" href="../share/css/main.css">
|
||||
<link rel="stylesheet" href="../share/css/start.css">
|
||||
<link rel="stylesheet" href="../share/css/user.css">
|
||||
<script type="module">import {main} from "../share/js/ipmi/main.js";
|
||||
<script type="module">import {setRootPrefix} from "../share/js/vars.js";
|
||||
setRootPrefix("../");
|
||||
import {main} from "../share/js/ipmi/main.js";
|
||||
main();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="start-box">
|
||||
<div class="start"><a style="display:inline-block; margin-top:4px; color:#5c90bc; text-decoration:none" href="/"> ← [ PiKVM Index ]</a>
|
||||
<div class="start"><a style="display:inline-block; margin-top:4px; color:#5c90bc; text-decoration:none" href="../"> ← [ PiKVM Index ]</a>
|
||||
<hr>
|
||||
<p class="text">This PiKVM device has running <b>kvmd-ipmi</b> daemon and provides IPMI 2.0 interface for some basic
|
||||
BMC operations like on/off/reset the server.
|
||||
|
||||
@ -3,7 +3,7 @@ extends ../start.pug
|
||||
|
||||
append vars
|
||||
-
|
||||
prefix = "../"
|
||||
root_prefix = "../"
|
||||
title = "PiKVM IPMI Info"
|
||||
main_js = "ipmi/main"
|
||||
index_link = true
|
||||
|
||||
@ -52,13 +52,15 @@
|
||||
<link rel="stylesheet" href="../share/css/kvm/keyboard.css">
|
||||
<link rel="stylesheet" href="../share/css/kvm/about.css">
|
||||
<link rel="stylesheet" href="../share/css/user.css">
|
||||
<script type="module">import {main} from "../share/js/kvm/main.js";
|
||||
<script type="module">import {setRootPrefix} from "../share/js/vars.js";
|
||||
setRootPrefix("../");
|
||||
import {main} from "../share/js/kvm/main.js";
|
||||
main();
|
||||
</script>
|
||||
</head>
|
||||
<body class="body-no-select">
|
||||
<ul id="navbar">
|
||||
<li class="left"><a id="logo" href="/">← <img class="svg-gray" src="../share/svg/logo.svg" alt="&pi;-kvm"></a></li>
|
||||
<li class="left"><a id="logo" href="../">← <img class="svg-gray" src="../share/svg/logo.svg" alt="&pi;-kvm"></a></li>
|
||||
<div class="hidden" id="hw-health-dropdown">
|
||||
<li class="left"><a class="menu-button" href="#"><img class="hidden" id="hw-health-undervoltage-led" src="../share/svg/led-undervoltage.svg"><img class="hidden" id="hw-health-overheating-led" src="../share/svg/led-overheating.svg"></a>
|
||||
<div class="menu">
|
||||
@ -131,7 +133,7 @@
|
||||
<td style="line-height:1.5"><b>Fan failed</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><sup style="line-height:1">A fan error occured, please <a href="/api/log?seek=3600&follow=1" target="_blank">check the log</a></sup></td>
|
||||
<td><sup style="line-height:1">A fan error occured, please <a href="../api/log?seek=3600&follow=1" target="_blank">check the log</a></sup></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@ -2283,7 +2285,9 @@
|
||||
<label for="about-tab-meta-button">Meta</label>
|
||||
<div class="tab">
|
||||
<div class="code" id="about-meta">
|
||||
<div><span class="code-comment">// You can get this JSON using handle <a target="_blank" href="/api/info?fields=meta">/api/info?fields=meta</a><br>
|
||||
<div><span class="code-comment">
|
||||
// You can get this JSON using handle
|
||||
<a target="_blank" href="../api/info?fields=meta">/api/info?fields=meta</a><br>
|
||||
// In the standard configuration this data<br>
|
||||
// is specified in the file /etc/kvmd/meta.yaml</span><br>
|
||||
<pre id="kvmd-meta-json">No data</pre>
|
||||
|
||||
@ -3,7 +3,7 @@ extends ../base.pug
|
||||
|
||||
append vars
|
||||
-
|
||||
prefix = "../"
|
||||
root_prefix = "../"
|
||||
title = "PiKVM Session"
|
||||
main_js = "kvm/main"
|
||||
body_class = "body-no-select"
|
||||
|
||||
@ -31,4 +31,4 @@
|
||||
#fan-health-message-fail
|
||||
hr
|
||||
+menu_message("led-fan", "Fan failed", "led-gray")
|
||||
| A fan error occured, please #[a(href="/api/log?seek=3600&follow=1" target="_blank") check the log]
|
||||
| A fan error occured, please #[a(href=`${root_prefix}api/log?seek=3600&follow=1` target="_blank") check the log]
|
||||
|
||||
@ -83,7 +83,7 @@ mixin menu_spoiler(title)
|
||||
|
||||
ul#navbar
|
||||
li.left
|
||||
a(id="logo" href="/") ←
|
||||
a(id="logo" href=root_prefix) ←
|
||||
img.svg-gray(src=`${svg_dir}/logo.svg` alt="π-kvm")
|
||||
|
||||
include navbar-health.pug
|
||||
|
||||
@ -34,7 +34,8 @@ mixin about_tab(name, title, checked=false)
|
||||
+about_tab("meta", "Meta", true)
|
||||
div
|
||||
span.code-comment
|
||||
| // You can get this JSON using handle #[a(target="_blank" href="/api/info?fields=meta") /api/info?fields=meta]#[br]
|
||||
| // You can get this JSON using handle
|
||||
| #[a(target="_blank" href=`${root_prefix}api/info?fields=meta`) /api/info?fields=meta]#[br]
|
||||
| // In the standard configuration this data#[br]
|
||||
| // is specified in the file /etc/kvmd/meta.yaml
|
||||
br
|
||||
|
||||
@ -39,7 +39,9 @@
|
||||
<link rel="stylesheet" href="../share/css/modal.css">
|
||||
<link rel="stylesheet" href="../share/css/login/login.css">
|
||||
<link rel="stylesheet" href="../share/css/user.css">
|
||||
<script type="module">import {main} from "../share/js/login/main.js";
|
||||
<script type="module">import {setRootPrefix} from "../share/js/vars.js";
|
||||
setRootPrefix("../");
|
||||
import {main} from "../share/js/login/main.js";
|
||||
main();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
@ -3,7 +3,7 @@ extends ../base.pug
|
||||
|
||||
append vars
|
||||
-
|
||||
prefix = "../"
|
||||
root_prefix = "../"
|
||||
title = "PiKVM Login"
|
||||
main_js = "login/main"
|
||||
css_list.push("window", "modal", "login/login")
|
||||
|
||||
@ -23,6 +23,9 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import {ROOT_PREFIX} from "./vars.js";
|
||||
|
||||
|
||||
export var browser = new function() {
|
||||
// https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser/9851769
|
||||
// https://github.com/fingerprintjs/fingerprintjs/discussions/641
|
||||
@ -133,12 +136,12 @@ export function checkBrowser(desktop_css, mobile_css) {
|
||||
let force_desktop = (new URL(window.location.href)).searchParams.get("force_desktop");
|
||||
let force_mobile = (new URL(window.location.href)).searchParams.get("force_mobile");
|
||||
if ((force_desktop || !browser.is_mobile) && !force_mobile) {
|
||||
__addCssLink("/share/css/x-desktop.css");
|
||||
__addCssLink("x-desktop.css");
|
||||
if (desktop_css) {
|
||||
__addCssLink(desktop_css);
|
||||
}
|
||||
} else {
|
||||
__addCssLink("/share/css/x-mobile.css");
|
||||
__addCssLink("x-mobile.css");
|
||||
if (mobile_css) {
|
||||
__addCssLink(mobile_css);
|
||||
}
|
||||
@ -148,6 +151,7 @@ export function checkBrowser(desktop_css, mobile_css) {
|
||||
}
|
||||
|
||||
function __addCssLink(path) {
|
||||
path = `${ROOT_PREFIX}share/css/${path}`;
|
||||
console.log("===== Adding CSS:", path);
|
||||
let el_head = document.getElementsByTagName("head")[0];
|
||||
let el_link = document.createElement("link");
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import {ROOT_PREFIX} from "../vars.js";
|
||||
import {tools, $} from "../tools.js";
|
||||
import {checkBrowser} from "../bb.js";
|
||||
import {wm, initWindowManager} from "../wm.js";
|
||||
@ -51,7 +52,7 @@ function __setAppText() {
|
||||
}
|
||||
|
||||
function __loadKvmdInfo() {
|
||||
tools.httpGet("/api/info", {"fields": "auth,meta,extras"}, function(http) {
|
||||
tools.httpGet("api/info", {"fields": "auth,meta,extras"}, function(http) {
|
||||
if (http.status === 200) {
|
||||
let info = JSON.parse(http.responseText).result;
|
||||
|
||||
@ -100,7 +101,7 @@ function __loadKvmdInfo() {
|
||||
document.title = "PiKVM Index";
|
||||
}
|
||||
} else if (http.status === 401 || http.status === 403) {
|
||||
document.location.href = "/login";
|
||||
tools.currentOpen("login");
|
||||
} else {
|
||||
setTimeout(__loadKvmdInfo, 1000);
|
||||
}
|
||||
@ -108,11 +109,14 @@ function __loadKvmdInfo() {
|
||||
}
|
||||
|
||||
function __makeApp(id, path, icon, name) {
|
||||
// Tailing slash in href is added to avoid Nginx 301 redirect
|
||||
// when the location doesn't have tailing slash: "foo -> foo/".
|
||||
// Reverse proxy over PiKVM can be misconfigured to handle this.
|
||||
return `<li>
|
||||
<div ${id ? "id=\"" + id + "\"" : ""} class="app">
|
||||
<a href="${path}">
|
||||
<a href="${ROOT_PREFIX}${path}/">
|
||||
<div>
|
||||
<img class="svg-gray" src="${icon}">
|
||||
<img class="svg-gray" src="${ROOT_PREFIX}${icon}">
|
||||
${tools.escape(name)}
|
||||
</div>
|
||||
</a>
|
||||
@ -121,9 +125,9 @@ function __makeApp(id, path, icon, name) {
|
||||
}
|
||||
|
||||
function __logout() {
|
||||
tools.httpPost("/api/auth/logout", null, function(http) {
|
||||
tools.httpPost("api/auth/logout", null, function(http) {
|
||||
if (http.status === 200 || http.status === 401 || http.status === 403) {
|
||||
document.location.href = "/login";
|
||||
tools.currentOpen("login");
|
||||
} else {
|
||||
wm.error("Logout error", http.responseText);
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ export function main() {
|
||||
}
|
||||
|
||||
function __loadKvmdInfo() {
|
||||
tools.httpGet("/api/info", null, function(http) {
|
||||
tools.httpGet("api/info", null, function(http) {
|
||||
if (http.status === 200) {
|
||||
let ipmi_port = JSON.parse(http.responseText).result.extras.ipmi.port;
|
||||
let make_item = (comment, ipmi, api) => `
|
||||
@ -52,7 +52,7 @@ function __loadKvmdInfo() {
|
||||
${make_item("Check the power status", "power status", "")}
|
||||
`;
|
||||
} else if (http.status === 401 || http.status === 403) {
|
||||
document.location.href = "/login";
|
||||
tools.currentOpen("login");
|
||||
} else {
|
||||
setTimeout(__loadKvmdInfo, 1000);
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ export function Atx(__recorder) {
|
||||
|
||||
var __clickAtx = function(button) {
|
||||
let click_button = function() {
|
||||
tools.httpPost("/api/atx/click", {"button": button}, function(http) {
|
||||
tools.httpPost("api/atx/click", {"button": button}, function(http) {
|
||||
if (http.status === 409) {
|
||||
wm.error("Performing another ATX operation for other client.<br>Please try again later.");
|
||||
} else if (http.status !== 200) {
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import {ROOT_PREFIX} from "../vars.js";
|
||||
import {tools, $, $$} from "../tools.js";
|
||||
import {wm} from "../wm.js";
|
||||
|
||||
@ -138,7 +139,7 @@ export function Gpio(__recorder) {
|
||||
return `
|
||||
<img
|
||||
class="__gpio-led __gpio-led-${item.channel} inline-lamp-big led-gray"
|
||||
src="/share/svg/led-circle.svg"
|
||||
src="${ROOT_PREFIX}share/svg/led-circle.svg"
|
||||
data-color="${item.color}"
|
||||
/>
|
||||
`;
|
||||
@ -202,7 +203,7 @@ export function Gpio(__recorder) {
|
||||
confirm = el.getAttribute("data-confirm-off");
|
||||
}
|
||||
let act = () => {
|
||||
__sendPost("/api/gpio/switch", {"channel": ch, "state": to});
|
||||
__sendPost("api/gpio/switch", {"channel": ch, "state": to});
|
||||
__recorder.recordGpioSwitchEvent(ch, to);
|
||||
};
|
||||
if (confirm) {
|
||||
@ -220,7 +221,7 @@ export function Gpio(__recorder) {
|
||||
let ch = el.getAttribute("data-channel");
|
||||
let confirm = el.getAttribute("data-confirm");
|
||||
let act = () => {
|
||||
__sendPost("/api/gpio/pulse", {"channel": ch});
|
||||
__sendPost("api/gpio/pulse", {"channel": ch});
|
||||
__recorder.recordGpioPulseEvent(ch);
|
||||
};
|
||||
if (confirm) {
|
||||
|
||||
@ -275,7 +275,7 @@ export function Hid(__getGeometry, __recorder) {
|
||||
|
||||
var __clickOutputsRadio = function(hid) {
|
||||
let output = tools.radio.getValue(`hid-outputs-${hid}-radio`);
|
||||
tools.httpPost("/api/hid/set_params", {[`${hid}_output`]: output}, function(http) {
|
||||
tools.httpPost("api/hid/set_params", {[`${hid}_output`]: output}, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("Can't configure HID", http.responseText);
|
||||
}
|
||||
@ -284,7 +284,7 @@ export function Hid(__getGeometry, __recorder) {
|
||||
|
||||
var __clickJigglerSwitch = function() {
|
||||
let enabled = $("hid-jiggler-switch").checked;
|
||||
tools.httpPost("/api/hid/set_params", {"jiggler": enabled}, function(http) {
|
||||
tools.httpPost("api/hid/set_params", {"jiggler": enabled}, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error(`Can't ${enabled ? "enabled" : "disable"} mouse jiggler`, http.responseText);
|
||||
}
|
||||
@ -293,7 +293,7 @@ export function Hid(__getGeometry, __recorder) {
|
||||
|
||||
var __clickConnectSwitch = function() {
|
||||
let connected = $("hid-connect-switch").checked;
|
||||
tools.httpPost("/api/hid/set_connected", {"connected": connected}, function(http) {
|
||||
tools.httpPost("api/hid/set_connected", {"connected": connected}, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error(`Can't ${connected ? "connect" : "disconnect"} HID`, http.responseText);
|
||||
}
|
||||
@ -303,7 +303,7 @@ export function Hid(__getGeometry, __recorder) {
|
||||
var __clickResetButton = function() {
|
||||
wm.confirm("Are you sure you want to reset HID (keyboard & mouse)?").then(function(ok) {
|
||||
if (ok) {
|
||||
tools.httpPost("/api/hid/reset", null, function(http) {
|
||||
tools.httpPost("api/hid/reset", null, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("HID reset error", http.responseText);
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ import {Session} from "./session.js";
|
||||
|
||||
|
||||
export function main() {
|
||||
if (checkBrowser(null, "/share/css/kvm/x-mobile.css")) {
|
||||
if (checkBrowser(null, "kvm/x-mobile.css")) {
|
||||
tools.storage.bindSimpleSwitch($("page-close-ask-switch"), "page.close.ask", true, function(value) {
|
||||
if (value) {
|
||||
window.onbeforeunload = function(event) {
|
||||
@ -48,7 +48,7 @@ export function main() {
|
||||
|
||||
initWindowManager();
|
||||
|
||||
tools.el.setOnClick($("open-log-button"), () => window.open("/api/log?seek=3600&follow=1", "_blank"));
|
||||
tools.el.setOnClick($("open-log-button"), () => tools.windowOpen("api/log?seek=3600&follow=1"));
|
||||
|
||||
tools.storage.bindSimpleSwitch(
|
||||
$("page-full-tab-stream-switch"),
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import {ROOT_PREFIX} from "../vars.js";
|
||||
import {tools, $} from "../tools.js";
|
||||
import {wm} from "../wm.js";
|
||||
|
||||
@ -270,14 +271,14 @@ export function Msd() {
|
||||
|
||||
var __clickDownloadButton = function() {
|
||||
let image = encodeURIComponent($("msd-image-selector").value);
|
||||
window.open(`/api/msd/read?image=${image}`);
|
||||
tools.windowOpen(`api/msd/read?image=${image}`);
|
||||
};
|
||||
|
||||
var __clickRemoveButton = function() {
|
||||
let name = $("msd-image-selector").value;
|
||||
wm.confirm("Are you sure you want to remove this image?", name).then(function(ok) {
|
||||
if (ok) {
|
||||
tools.httpPost("/api/msd/remove", {"image": name}, function(http) {
|
||||
tools.httpPost("api/msd/remove", {"image": name}, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("Can't remove image", http.responseText);
|
||||
}
|
||||
@ -287,7 +288,7 @@ export function Msd() {
|
||||
};
|
||||
|
||||
var __sendParam = function(name, value) {
|
||||
tools.httpPost("/api/msd/set_params", {[name]: value}, function(http) {
|
||||
tools.httpPost("api/msd/set_params", {[name]: value}, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("Can't configure Mass Storage", http.responseText);
|
||||
}
|
||||
@ -301,10 +302,10 @@ export function Msd() {
|
||||
let prefix = encodeURIComponent($("msd-new-part-selector").value);
|
||||
if (file) {
|
||||
let image = encodeURIComponent(file.name);
|
||||
__http.open("POST", `/api/msd/write?prefix=${prefix}&image=${image}&remove_incomplete=1`, true);
|
||||
__http.open("POST", `${ROOT_PREFIX}api/msd/write?prefix=${prefix}&image=${image}&remove_incomplete=1`, true);
|
||||
} else {
|
||||
let url = encodeURIComponent($("msd-new-url").value);
|
||||
__http.open("POST", `/api/msd/write_remote?prefix=${prefix}&url=${url}&remove_incomplete=1`, true);
|
||||
__http.open("POST", `${ROOT_PREFIX}api/msd/write_remote?prefix=${prefix}&url=${url}&remove_incomplete=1`, true);
|
||||
}
|
||||
__http.upload.timeout = 7 * 24 * 3600;
|
||||
__http.onreadystatechange = __uploadStateChange;
|
||||
@ -360,7 +361,7 @@ export function Msd() {
|
||||
};
|
||||
|
||||
var __clickConnectButton = function(connected) {
|
||||
tools.httpPost("/api/msd/set_connected", {"connected": connected}, function(http) {
|
||||
tools.httpPost("api/msd/set_connected", {"connected": connected}, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("Can't switch Mass Storage", http.responseText);
|
||||
}
|
||||
@ -373,7 +374,7 @@ export function Msd() {
|
||||
var __clickResetButton = function() {
|
||||
wm.confirm("Are you sure you want to reset Mass Storage?").then(function(ok) {
|
||||
if (ok) {
|
||||
tools.httpPost("/api/msd/reset", null, function(http) {
|
||||
tools.httpPost("api/msd/reset", null, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("Mass Storage reset error", http.responseText);
|
||||
}
|
||||
|
||||
@ -186,7 +186,7 @@ export function Ocr(__getGeometry) {
|
||||
"ocr_right": __sel.right,
|
||||
"ocr_bottom": __sel.bottom,
|
||||
};
|
||||
tools.httpGet("/api/streamer/snapshot", params, function(http) {
|
||||
tools.httpGet("api/streamer/snapshot", params, function(http) {
|
||||
if (http.status === 200) {
|
||||
wm.copyTextToClipboard(http.responseText);
|
||||
} else {
|
||||
|
||||
@ -72,7 +72,7 @@ export function Paste(__recorder) {
|
||||
|
||||
tools.debug(`HID: paste-as-keys ${keymap}: ${text}`);
|
||||
|
||||
tools.httpPost("/api/hid/print", {"limit": 0, "keymap": keymap, "slow": slow}, function(http) {
|
||||
tools.httpPost("api/hid/print", {"limit": 0, "keymap": keymap, "slow": slow}, function(http) {
|
||||
tools.el.setEnabled($("hid-pak-text"), true);
|
||||
tools.el.setEnabled($("hid-pak-button"), true);
|
||||
tools.el.setEnabled($("hid-pak-keymap-selector"), true);
|
||||
|
||||
@ -293,7 +293,7 @@ export function Recorder() {
|
||||
if (event.event.slow !== undefined) {
|
||||
params["slow"] = event.event.slow;
|
||||
}
|
||||
tools.httpPost("/api/hid/print", params, function(http) {
|
||||
tools.httpPost("api/hid/print", params, function(http) {
|
||||
if (http.status === 413) {
|
||||
wm.error("Too many text for paste!");
|
||||
__stopProcess();
|
||||
@ -307,7 +307,7 @@ export function Recorder() {
|
||||
return;
|
||||
|
||||
} else if (event.event_type === "atx_button") {
|
||||
tools.httpPost("/api/atx/click", {"button": event.event.button}, function(http) {
|
||||
tools.httpPost("api/atx/click", {"button": event.event.button}, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("ATX error", http.responseText);
|
||||
__stopProcess();
|
||||
@ -318,7 +318,7 @@ export function Recorder() {
|
||||
return;
|
||||
|
||||
} else if (["gpio_switch", "gpio_pulse"].includes(event.event_type)) {
|
||||
let path = "/api/gpio";
|
||||
let path = "api/gpio";
|
||||
let params = {"channel": event.event.channel};
|
||||
if (event.event_type === "gpio_switch") {
|
||||
path += "/switch";
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import {ROOT_PREFIX} from "../vars.js";
|
||||
import {tools, $} from "../tools.js";
|
||||
import {wm} from "../wm.js";
|
||||
|
||||
@ -272,10 +273,15 @@ export function Session() {
|
||||
let close_hook = null;
|
||||
let has_webterm = (state.webterm && (state.webterm.enabled || state.webterm.started));
|
||||
if (has_webterm) {
|
||||
let path = "/" + state.webterm.path + "?disableLeaveAlert=true";
|
||||
let loc = window.location;
|
||||
let base = `${loc.protocol}//${loc.host}${loc.pathname}${ROOT_PREFIX}`;
|
||||
// Tailing slash after state.webterm.path is added to avoid Nginx 301 redirect
|
||||
// when the location doesn't have tailing slash: "foo -> foo/".
|
||||
// Reverse proxy over PiKVM can be misconfigured to handle this.
|
||||
let url = base + state.webterm.path + "/?disableLeaveAlert=true";
|
||||
show_hook = function() {
|
||||
tools.info("Terminal opened: ", path);
|
||||
$("webterm-iframe").src = path;
|
||||
tools.info("Terminal opened: ", url);
|
||||
$("webterm-iframe").src = url;
|
||||
};
|
||||
close_hook = function() {
|
||||
tools.info("Terminal closed");
|
||||
@ -291,9 +297,9 @@ export function Session() {
|
||||
$("link-led").className = "led-yellow";
|
||||
$("link-led").title = "Connecting...";
|
||||
|
||||
tools.httpGet("/api/auth/check", null, function(http) {
|
||||
tools.httpGet("api/auth/check", null, function(http) {
|
||||
if (http.status === 200) {
|
||||
__ws = new WebSocket(`${tools.is_https ? "wss" : "ws"}://${location.host}/api/ws`);
|
||||
__ws = new WebSocket(tools.makeWsUrl("api/ws"));
|
||||
__ws.sendHidEvent = (event) => __sendHidEvent(__ws, event.event_type, event.event);
|
||||
__ws.onopen = __wsOpenHandler;
|
||||
__ws.onmessage = __wsMessageHandler;
|
||||
@ -302,7 +308,7 @@ export function Session() {
|
||||
} else if (http.status === 401 || http.status === 403) {
|
||||
window.onbeforeunload = () => null;
|
||||
wm.error("Unexpected logout occured, please login again").then(function() {
|
||||
document.location.href = "/login";
|
||||
tools.currentOpen("login");
|
||||
});
|
||||
} else {
|
||||
__wsCloseHandler(null);
|
||||
|
||||
@ -332,19 +332,14 @@ export function Streamer() {
|
||||
};
|
||||
|
||||
var __clickScreenshotButton = function() {
|
||||
let el = document.createElement("a");
|
||||
el.href = "/api/streamer/snapshot";
|
||||
el.target = "_blank";
|
||||
document.body.appendChild(el);
|
||||
el.click();
|
||||
setTimeout(() => document.body.removeChild(el), 0);
|
||||
tools.windowOpen("api/streamer/snapshot");
|
||||
};
|
||||
|
||||
var __clickResetButton = function() {
|
||||
wm.confirm("Are you sure you want to reset stream?").then(function(ok) {
|
||||
if (ok) {
|
||||
__resetStream();
|
||||
tools.httpPost("/api/streamer/reset", null, function(http) {
|
||||
tools.httpPost("api/streamer/reset", null, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("Can't reset stream", http.responseText);
|
||||
}
|
||||
@ -354,7 +349,7 @@ export function Streamer() {
|
||||
};
|
||||
|
||||
var __sendParam = function(name, value) {
|
||||
tools.httpPost("/api/streamer/set_params", {[name]: value}, function(http) {
|
||||
tools.httpPost("api/streamer/set_params", {[name]: value}, function(http) {
|
||||
if (http.status !== 200) {
|
||||
wm.error("Can't configure stream", http.responseText);
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ export function JanusStreamer(__setActive, __setInactive, __setInfo, __orient, _
|
||||
__setInfo(false, false, "");
|
||||
__logInfo("Starting Janus ...");
|
||||
__janus = new _Janus({
|
||||
"server": `${tools.is_https ? "wss" : "ws"}://${location.host}/janus/ws`,
|
||||
"server": tools.makeWsUrl("janus/ws"),
|
||||
"ipv6": true,
|
||||
"destroyOnUnload": false,
|
||||
"success": __attachJanus,
|
||||
|
||||
@ -79,7 +79,7 @@ export function MediaStreamer(__setActive, __setInactive, __setInfo) {
|
||||
__setInactive();
|
||||
__setInfo(false, false, "");
|
||||
__logInfo("Starting Media ...");
|
||||
__ws = new WebSocket(`${tools.is_https ? "wss" : "ws"}://${location.host}/api/media/ws`);
|
||||
__ws = new WebSocket(tools.makeWsUrl("api/media/ws"));
|
||||
__ws.binaryType = "arraybuffer";
|
||||
__ws.onopen = __wsOpenHandler;
|
||||
__ws.onerror = __wsErrorHandler;
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import {ROOT_PREFIX} from "../vars.js";
|
||||
import {tools, $} from "../tools.js";
|
||||
|
||||
|
||||
@ -72,7 +73,7 @@ export function MjpegStreamer(__setActive, __setInactive, __setInfo) {
|
||||
|
||||
self.stopStream = function() {
|
||||
self.ensureStream(null);
|
||||
let blank = "/share/png/blank-stream.png";
|
||||
let blank = `${ROOT_PREFIX}share/png/blank-stream.png`;
|
||||
if (!String.prototype.endsWith.call($("stream-image").src, blank)) {
|
||||
$("stream-image").src = blank;
|
||||
}
|
||||
@ -138,7 +139,7 @@ export function MjpegStreamer(__setActive, __setInactive, __setInfo) {
|
||||
__setStreamInactive();
|
||||
__stopChecking();
|
||||
|
||||
let path = `/streamer/stream?key=${__key}`;
|
||||
let path = `${ROOT_PREFIX}streamer/stream?key=${__key}`;
|
||||
if (tools.browser.is_safari || tools.browser.is_ios) {
|
||||
// uStreamer fix for WebKit
|
||||
__logInfo("Using dual_final_frames=1 to fix WebKit bugs");
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import {ROOT_PREFIX} from "../vars.js";
|
||||
import {tools, $} from "../tools.js";
|
||||
import {wm} from "../wm.js";
|
||||
|
||||
@ -125,7 +126,7 @@ export function Switch() {
|
||||
+ ":" + brightness.toString(16).padStart(2, "0")
|
||||
+ ":" + color.blink_ms.toString(16).padStart(4, "0")
|
||||
);
|
||||
__sendPost("/api/switch/set_colors", {[role]: rgbx}, function() {
|
||||
__sendPost("api/switch/set_colors", {[role]: rgbx}, function() {
|
||||
el_color.value = (
|
||||
"#"
|
||||
+ color.red.toString(16).padStart(2, "0")
|
||||
@ -137,7 +138,7 @@ export function Switch() {
|
||||
};
|
||||
|
||||
var __clickSetDefaultColorButton = function(role) {
|
||||
__sendPost("/api/switch/set_colors", {[role]: "default"});
|
||||
__sendPost("api/switch/set_colors", {[role]: "default"});
|
||||
};
|
||||
|
||||
var __applyEdids = function(edids) {
|
||||
@ -210,7 +211,7 @@ export function Switch() {
|
||||
if (ok) {
|
||||
let name = $("__switch-edid-new-name-input").value;
|
||||
let data = $("__switch-edid-new-data-text").value;
|
||||
__sendPost("/api/switch/edids/create", {"name": name, "data": data});
|
||||
__sendPost("api/switch/edids/create", {"name": name, "data": data});
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -222,7 +223,7 @@ export function Switch() {
|
||||
let html = "Are you sure to remove this EDID?<br>Ports that used it will change it to the default.";
|
||||
wm.confirm(html, name).then(function(ok) {
|
||||
if (ok) {
|
||||
__sendPost("/api/switch/edids/remove", {"id": edid_id});
|
||||
__sendPost("api/switch/edids/remove", {"id": edid_id});
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -344,11 +345,11 @@ export function Switch() {
|
||||
<td colspan=100>
|
||||
<div class="buttons-row">
|
||||
<button id="__switch-beacon-button-u${unit}" class="small" title="Toggle uplink Beacon Led">
|
||||
<img id="__switch-beacon-led-u${unit}" class="inline-lamp led-gray" src="/share/svg/led-beacon.svg"/>
|
||||
<img id="__switch-beacon-led-u${unit}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-beacon.svg"/>
|
||||
Uplink
|
||||
</button>
|
||||
<button id="__switch-beacon-button-d${unit}" class="small" title="Toggle downlink Beacon Led">
|
||||
<img id="__switch-beacon-led-d${unit}" class="inline-lamp led-gray" src="/share/svg/led-beacon.svg"/>
|
||||
<img id="__switch-beacon-led-d${unit}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-beacon.svg"/>
|
||||
Downlink
|
||||
</button>
|
||||
</div>
|
||||
@ -365,10 +366,10 @@ export function Switch() {
|
||||
<td>
|
||||
<div class="buttons-row">
|
||||
<button id="__switch-port-button-p${port}" title="Activate this port">
|
||||
<img id="__switch-port-led-p${port}" class="inline-lamp led-gray" src="/share/svg/led-circle.svg"/>
|
||||
<img id="__switch-port-led-p${port}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-circle.svg"/>
|
||||
</button>
|
||||
<button id="__switch-params-button-p${port}" title="Configure this port">
|
||||
<img id="__switch-params-led-p${port}" class="inline-lamp led-gray" src="/share/svg/led-gear.svg"/>
|
||||
<img id="__switch-params-led-p${port}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-gear.svg"/>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
@ -385,14 +386,14 @@ export function Switch() {
|
||||
</td>
|
||||
<td style="font-size:1em">
|
||||
<button id="__switch-beacon-button-p${port}" class="small" title="Toggle Beacon Led on this port">
|
||||
<img id="__switch-beacon-led-p${port}" class="inline-lamp led-gray" src="/share/svg/led-beacon.svg"/>
|
||||
<img id="__switch-beacon-led-p${port}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-beacon.svg"/>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<img id="__switch-video-led-p${port}" class="inline-lamp led-gray" src="/share/svg/led-video.svg" title="Video Link"/>
|
||||
<img id="__switch-usb-led-p${port}" class="inline-lamp led-gray" src="/share/svg/led-usb.svg" title="USB Link"/>
|
||||
<img id="__switch-atx-power-led-p${port}" class="inline-lamp led-gray" src="/share/svg/led-atx-power.svg" title="Power Led"/>
|
||||
<img id="__switch-atx-hdd-led-p${port}" class="inline-lamp led-gray" src="/share/svg/led-atx-hdd.svg" title="HDD Led"/>
|
||||
<img id="__switch-video-led-p${port}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-video.svg" title="Video Link"/>
|
||||
<img id="__switch-usb-led-p${port}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-usb.svg" title="USB Link"/>
|
||||
<img id="__switch-atx-power-led-p${port}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-atx-power.svg" title="Power Led"/>
|
||||
<img id="__switch-atx-hdd-led-p${port}" class="inline-lamp led-gray" src="${ROOT_PREFIX}share/svg/led-atx-hdd.svg" title="HDD Led"/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="buttons-row">
|
||||
@ -524,7 +525,7 @@ export function Switch() {
|
||||
for (let action of Object.keys(atx_actions)) {
|
||||
params[`atx_click_${action}_delay`] = tools.slider.getValue($(`__switch-port-atx-click-${action}-delay-slider`));
|
||||
};
|
||||
__sendPost("/api/switch/set_port_params", params);
|
||||
__sendPost("api/switch/set_port_params", params);
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -555,31 +556,31 @@ export function Switch() {
|
||||
Otherwise, it will break a current USB operation (OS installation, Live CD, or whatever).
|
||||
`);
|
||||
} else {
|
||||
__sendPost("/api/switch/set_active", {"port": port});
|
||||
__sendPost("api/switch/set_active", {"port": port});
|
||||
}
|
||||
};
|
||||
|
||||
var __switchUplinkBeacon = function(unit) {
|
||||
let state = false;
|
||||
try { state = !__state.beacons.uplinks[unit]; } catch {}; // eslint-disable-line no-empty
|
||||
__sendPost("/api/switch/set_beacon", {"uplink": unit, "state": state});
|
||||
__sendPost("api/switch/set_beacon", {"uplink": unit, "state": state});
|
||||
};
|
||||
|
||||
var __switchDownlinkBeacon = function(unit) {
|
||||
let state = false;
|
||||
try { state = !__state.beacons.downlinks[unit]; } catch {}; // eslint-disable-line no-empty
|
||||
__sendPost("/api/switch/set_beacon", {"downlink": unit, "state": state});
|
||||
__sendPost("api/switch/set_beacon", {"downlink": unit, "state": state});
|
||||
};
|
||||
|
||||
var __switchPortBeacon = function(port) {
|
||||
let state = false;
|
||||
try { state = !__state.beacons.ports[port]; } catch {}; // eslint-disable-line no-empty
|
||||
__sendPost("/api/switch/set_beacon", {"port": port, "state": state});
|
||||
__sendPost("api/switch/set_beacon", {"port": port, "state": state});
|
||||
};
|
||||
|
||||
var __atxClick = function(port, button) {
|
||||
let click_button = function() {
|
||||
__sendPost("/api/switch/atx/click", {"port": port, "button": button});
|
||||
__sendPost("api/switch/atx/click", {"port": port, "button": button});
|
||||
};
|
||||
if ($("switch-atx-ask-switch").checked) {
|
||||
wm.confirm(`
|
||||
|
||||
@ -51,9 +51,9 @@ function __login() {
|
||||
} else {
|
||||
let passwd = $("passwd-input").value + $("code-input").value;
|
||||
let body = `user=${encodeURIComponent(user)}&passwd=${encodeURIComponent(passwd)}`;
|
||||
tools.httpPost("/api/auth/login", null, function(http) {
|
||||
tools.httpPost("api/auth/login", null, function(http) {
|
||||
if (http.status === 200) {
|
||||
document.location.href = "/";
|
||||
tools.currentOpen("");
|
||||
} else if (http.status === 403) {
|
||||
wm.error("Invalid credentials").then(__tryAgain);
|
||||
} else {
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import {ROOT_PREFIX} from "./vars.js";
|
||||
import {browser} from "./bb.js";
|
||||
|
||||
|
||||
@ -39,7 +40,16 @@ export var tools = new function() {
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
self.currentOpen = function(url) {
|
||||
window.location.href = ROOT_PREFIX + url;
|
||||
};
|
||||
|
||||
self.windowOpen = function(url) {
|
||||
window.open(ROOT_PREFIX + url, "_blank");
|
||||
};
|
||||
|
||||
self.httpRequest = function(method, url, params, callback, body=null, content_type=null, timeout=15000) {
|
||||
url = ROOT_PREFIX + url;
|
||||
if (params) {
|
||||
params = new URLSearchParams(params);
|
||||
if (params) {
|
||||
@ -68,6 +78,11 @@ export var tools = new function() {
|
||||
self.httpRequest("POST", url, params, callback, body, content_type, timeout);
|
||||
};
|
||||
|
||||
self.makeWsUrl = function(url) {
|
||||
let proto = (self.is_https ? "wss://" : "ws://");
|
||||
return proto + window.location.host + window.location.pathname + ROOT_PREFIX + url;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
self.escape = function(text) {
|
||||
@ -383,7 +398,7 @@ export var tools = new function() {
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
self.is_https = (location.protocol === "https:");
|
||||
self.is_https = (window.location.protocol === "https:");
|
||||
|
||||
self.cookies = new function() {
|
||||
return {
|
||||
|
||||
31
web/share/js/vars.js
Normal file
31
web/share/js/vars.js
Normal file
@ -0,0 +1,31 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# 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 <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
export var ROOT_PREFIX = "./";
|
||||
|
||||
|
||||
export function setRootPrefix(prefix) {
|
||||
ROOT_PREFIX = prefix;
|
||||
}
|
||||
@ -31,7 +31,7 @@ export function main() {
|
||||
}
|
||||
|
||||
function __loadKvmdInfo() {
|
||||
tools.httpGet("/api/info", null, function(http) {
|
||||
tools.httpGet("api/info", null, function(http) {
|
||||
if (http.status === 200) {
|
||||
let vnc_port = JSON.parse(http.responseText).result.extras.vnc.port;
|
||||
$("vnc-text").innerHTML = `
|
||||
@ -39,7 +39,7 @@ function __loadKvmdInfo() {
|
||||
$</span> vncviewer ${window.location.hostname}::${vnc_port}
|
||||
`;
|
||||
} else if (http.status === 401 || http.status === 403) {
|
||||
document.location.href = "/login";
|
||||
tools.currentOpen("login");
|
||||
} else {
|
||||
setTimeout(__loadKvmdInfo, 1000);
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ block body
|
||||
div(class="start-box")
|
||||
div(class="start")
|
||||
if index_link
|
||||
a(style="display:inline-block; margin-top:4px; color:#5c90bc; text-decoration:none" href="/")
|
||||
a(style="display:inline-block; margin-top:4px; color:#5c90bc; text-decoration:none" href=root_prefix)
|
||||
| ← [ PiKVM Index ]
|
||||
hr
|
||||
block start
|
||||
|
||||
@ -37,13 +37,15 @@
|
||||
<link rel="stylesheet" href="../share/css/main.css">
|
||||
<link rel="stylesheet" href="../share/css/start.css">
|
||||
<link rel="stylesheet" href="../share/css/user.css">
|
||||
<script type="module">import {main} from "../share/js/vnc/main.js";
|
||||
<script type="module">import {setRootPrefix} from "../share/js/vars.js";
|
||||
setRootPrefix("../");
|
||||
import {main} from "../share/js/vnc/main.js";
|
||||
main();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="start-box">
|
||||
<div class="start"><a style="display:inline-block; margin-top:4px; color:#5c90bc; text-decoration:none" href="/"> ← [ PiKVM Index ]</a>
|
||||
<div class="start"><a style="display:inline-block; margin-top:4px; color:#5c90bc; text-decoration:none" href="../"> ← [ PiKVM Index ]</a>
|
||||
<hr>
|
||||
<p class="text">This PiKVM device has running <b>kvmd-vnc</b> daemon and provides VNC access to the server.</p>
|
||||
<p class="text"><b>WARNING!</b> We strongly don't recommend you to use VNC in untrusted networks without
|
||||
|
||||
@ -3,7 +3,7 @@ extends ../start.pug
|
||||
|
||||
append vars
|
||||
-
|
||||
prefix = "../"
|
||||
root_prefix = "../"
|
||||
title = "PiKVM VNC Info"
|
||||
main_js = "vnc/main"
|
||||
index_link = true
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user