mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
js cleanup
This commit is contained in:
parent
beb5d541b0
commit
94fe2226f1
@ -39,23 +39,39 @@ export function main() {
|
||||
}
|
||||
|
||||
function __setAppText() {
|
||||
let e_href = tools.escape(window.location.href);
|
||||
$("app-text").innerHTML = `
|
||||
<span class="code-comment"># On Linux using Chromium/Chrome via any terminal:<br>
|
||||
$</span> \`which chromium 2>/dev/null || which chrome 2>/dev/null || which google-chrome\` --app="${window.location.href}"<br>
|
||||
$</span> \`which chromium 2>/dev/null || which chrome 2>/dev/null || which google-chrome\` --app="${e_href}"<br>
|
||||
<br>
|
||||
<span class="code-comment"># On MacOS using Terminal application:<br>
|
||||
$</span> /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --app="${window.location.href}"<br>
|
||||
$</span> /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --app="${e_href}"<br>
|
||||
<br>
|
||||
<span class="code-comment"># On Windows via cmd.exe:<br>
|
||||
C:\></span> start chrome --app="${window.location.href}"
|
||||
C:\></span> start chrome --app="${e_href}"
|
||||
`;
|
||||
}
|
||||
|
||||
function __loadKvmdInfo() {
|
||||
tools.httpGet("api/info", {"fields": "auth,meta,extras"}, function(http) {
|
||||
if (http.status === 200) {
|
||||
let info = JSON.parse(http.responseText).result;
|
||||
switch (http.status) {
|
||||
case 200:
|
||||
__showKvmdInfo(JSON.parse(http.responseText).result);
|
||||
break;
|
||||
|
||||
case 401:
|
||||
case 403:
|
||||
tools.currentOpen("login");
|
||||
break;
|
||||
|
||||
default:
|
||||
setTimeout(__loadKvmdInfo, 1000);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function __showKvmdInfo(info) {
|
||||
let apps = [];
|
||||
if (info.extras === null) {
|
||||
wm.error("Not all applications in the menu can be displayed due an error.<br>See KVMD logs for details.");
|
||||
@ -71,7 +87,7 @@ function __loadKvmdInfo() {
|
||||
});
|
||||
}
|
||||
|
||||
$("apps-box").innerHTML = "<ul id=\"apps\"></ul>";
|
||||
let html = "";
|
||||
|
||||
// Don't use this option, it may be removed in any time
|
||||
let hide_kvm_button = (
|
||||
@ -79,17 +95,22 @@ function __loadKvmdInfo() {
|
||||
|| tools.config.getBool("index--hide-kvm-button", false)
|
||||
);
|
||||
if (!hide_kvm_button) {
|
||||
$("apps").innerHTML += __makeApp(null, "kvm", "share/svg/kvm.svg", "KVM");
|
||||
html += __makeApp(null, "kvm", "share/svg/kvm.svg", "KVM");
|
||||
}
|
||||
|
||||
for (let app of apps) {
|
||||
if (app.place >= 0 && (app.enabled || app.started)) {
|
||||
$("apps").innerHTML += __makeApp(null, app.path, app.icon, app.name);
|
||||
html += __makeApp(null, app.path, app.icon, app.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (info.auth.enabled) {
|
||||
$("apps").innerHTML += __makeApp("logout-button", "#", "share/svg/logout.svg", "Logout");
|
||||
html += __makeApp("logout-button", "#", "share/svg/logout.svg", "Logout");
|
||||
}
|
||||
|
||||
$("apps-box").innerHTML = `<ul id="apps">${html}</ul>`;
|
||||
|
||||
if (info.auth.enabled) {
|
||||
tools.el.setOnClick($("logout-button"), __logout);
|
||||
}
|
||||
|
||||
@ -100,23 +121,18 @@ function __loadKvmdInfo() {
|
||||
$("kvmd-meta-server-host").innerHTML = "";
|
||||
document.title = "PiKVM Index";
|
||||
}
|
||||
} else if (http.status === 401 || http.status === 403) {
|
||||
tools.currentOpen("login");
|
||||
} else {
|
||||
setTimeout(__loadKvmdInfo, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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.
|
||||
let e_add_id = (id ? `id="${tools.escape(id)}"` : "");
|
||||
return `<li>
|
||||
<div ${id ? "id=\"" + id + "\"" : ""} class="app">
|
||||
<a href="${ROOT_PREFIX}${path}/">
|
||||
<div ${e_add_id} class="app">
|
||||
<a href="${tools.escape(ROOT_PREFIX + path)}/">
|
||||
<div>
|
||||
<img class="svg-gray" src="${ROOT_PREFIX}${icon}">
|
||||
<img class="svg-gray" src="${tools.escape(ROOT_PREFIX + icon)}">
|
||||
${tools.escape(name)}
|
||||
</div>
|
||||
</a>
|
||||
@ -126,10 +142,16 @@ function __makeApp(id, path, icon, name) {
|
||||
|
||||
function __logout() {
|
||||
tools.httpPost("api/auth/logout", null, function(http) {
|
||||
if (http.status === 200 || http.status === 401 || http.status === 403) {
|
||||
switch (http.status) {
|
||||
case 200:
|
||||
case 401:
|
||||
case 403:
|
||||
tools.currentOpen("login");
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
wm.error("Logout error", http.responseText);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -32,29 +32,43 @@ export function main() {
|
||||
|
||||
function __loadKvmdInfo() {
|
||||
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) => `
|
||||
<span class="code-comment"># ${comment}:<br>$</span>
|
||||
ipmitool -I lanplus -U admin -P admin -H ${window.location.hostname} -p ${ipmi_port} ${ipmi}<br>
|
||||
<span class="code-comment">$</span> curl -XPOST -HX-KVMD-User:admin -HX-KVMD-Passwd:admin -k \\<br>
|
||||
${window.location.protocol}//${window.location.host}/api/atx${api}<br>
|
||||
`;
|
||||
$("ipmi-text").innerHTML = `
|
||||
${make_item("Power on the server if it's off", "power on", "/power?action=on")}
|
||||
<br>
|
||||
${make_item("Soft power off the server if it's on", "power soft", "/power?action=off")}
|
||||
<br>
|
||||
${make_item("Hard power off the server if it's on", "power off", "/power?action=off_hard")}
|
||||
<br>
|
||||
${make_item("Hard reset the server if it's on", "power reset", "/power?action=reset_hard")}
|
||||
<br>
|
||||
${make_item("Check the power status", "power status", "")}
|
||||
`;
|
||||
} else if (http.status === 401 || http.status === 403) {
|
||||
switch (http.status) {
|
||||
case 200:
|
||||
__showKvmdInfo(JSON.parse(http.responseText).result);
|
||||
break;
|
||||
|
||||
case 401:
|
||||
case 403:
|
||||
tools.currentOpen("login");
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
setTimeout(__loadKvmdInfo, 1000);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function __showKvmdInfo(info) {
|
||||
let make_item = function (comment, cmd, api) {
|
||||
return `
|
||||
<span class="code-comment">
|
||||
# ${tools.escape(comment)}:<br>$
|
||||
</span>
|
||||
ipmitool -I lanplus -U admin -P admin
|
||||
-H ${tools.escape(window.location.hostname)}
|
||||
-p ${tools.escape(info.extras.ipmi.port)} ${tools.escape(cmd)}
|
||||
<br>
|
||||
<span class="code-comment">$</span>
|
||||
curl -XPOST -HX-KVMD-User:admin -HX-KVMD-Passwd:admin -k \\<br>
|
||||
${tools.escape(window.location.protocol + "//" + window.location.host + "/api/atx" + api)}
|
||||
`;
|
||||
};
|
||||
$("ipmi-text").innerHTML = [
|
||||
make_item("Power on the server if it's off", "power on", "/power?action=on"),
|
||||
make_item("Soft power off the server if it's on", "power soft", "/power?action=off"),
|
||||
make_item("Hard power off the server if it's on", "power off", "/power?action=off_hard"),
|
||||
make_item("Hard reset the server if it's on", "power reset", "/power?action=reset_hard"),
|
||||
make_item("Check the power status", "power status", ""),
|
||||
].join("<br><br>");
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ export function Atx(__recorder) {
|
||||
|
||||
if ($("atx-ask-switch").checked) {
|
||||
wm.confirm(`
|
||||
Are you sure you want to press the <b>${button}</b> button?<br>
|
||||
Are you sure you want to press the <b>${tools.escape(button)}</b> button?<br>
|
||||
Warning! This could cause data loss on the server.
|
||||
`).then(function(ok) {
|
||||
if (ok) {
|
||||
|
||||
@ -135,30 +135,36 @@ export function Gpio(__recorder) {
|
||||
var __createItem = function(item) {
|
||||
if (item.type === "label") {
|
||||
return item.text;
|
||||
|
||||
} else if (item.type === "input") {
|
||||
let e_ch_class = tools.escape(`__gpio-led-${item.channel}`);
|
||||
let e_icon = tools.escape(`${ROOT_PREFIX}share/svg/led-circle.svg`);
|
||||
return `
|
||||
<img
|
||||
class="__gpio-led __gpio-led-${item.channel} inline-lamp-big led-gray"
|
||||
src="${ROOT_PREFIX}share/svg/led-circle.svg"
|
||||
data-color="${item.color}"
|
||||
class="__gpio-led ${e_ch_class} inline-lamp-big led-gray"
|
||||
src="${e_icon}"
|
||||
data-color="${tools.escape(item.color)}"
|
||||
/>
|
||||
`;
|
||||
|
||||
} else if (item.type === "output") {
|
||||
let controls = [];
|
||||
let confirm = (item.confirm ? "Are you sure you want to perform this action?" : "");
|
||||
let e_ch = tools.escape(item.channel);
|
||||
let e_confirm = (item.confirm ? tools.escape("Are you sure you want to perform this action?") : "");
|
||||
if (item.scheme["switch"]) {
|
||||
let id = tools.makeId();
|
||||
let e_id = tools.escape(`__gpio-switch-${tools.makeRandomId()}`);
|
||||
let e_ch_class = tools.escape(`__gpio-switch-${item.channel}`);
|
||||
controls.push(`
|
||||
<td><div class="switch-box">
|
||||
<input
|
||||
disabled
|
||||
type="checkbox"
|
||||
id="__gpio-switch-${id}"
|
||||
class="__gpio-switch __gpio-switch-${item.channel}"
|
||||
data-channel="${item.channel}"
|
||||
data-confirm="${confirm}"
|
||||
id="${e_id}"
|
||||
class="__gpio-switch ${e_ch_class}"
|
||||
data-channel="${e_ch}"
|
||||
data-confirm="${e_confirm}"
|
||||
/>
|
||||
<label for="__gpio-switch-${id}">
|
||||
<label for="${e_id}">
|
||||
<span class="switch-inner"></span>
|
||||
<span class="switch"></span>
|
||||
</label>
|
||||
@ -166,22 +172,23 @@ export function Gpio(__recorder) {
|
||||
`);
|
||||
}
|
||||
if (item.scheme.pulse.delay) {
|
||||
let e_ch_class = tools.escape(`__gpio-button-${item.channel}`);
|
||||
controls.push(`
|
||||
<td><button
|
||||
disabled
|
||||
class="__gpio-button __gpio-button-${item.channel}"
|
||||
class="__gpio-button ${e_ch_class}"
|
||||
${item.hide ? "data-force-hide-menu" : ""}
|
||||
data-channel="${item.channel}"
|
||||
data-confirm="${confirm}"
|
||||
data-channel="${e_ch}"
|
||||
data-confirm="${e_confirm}"
|
||||
>
|
||||
${(item.hide ? "• " : "") + item.text}
|
||||
${(item.hide ? "• " : "") + tools.escape(item.text)}
|
||||
</button></td>
|
||||
`);
|
||||
}
|
||||
return `<table><tr>${controls.join("<td> </td>")}</tr></table>`;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
var __setLedState = function(el, on) {
|
||||
|
||||
@ -112,7 +112,7 @@ export function Mouse(__getGeometry, __recordWsEvent) {
|
||||
};
|
||||
|
||||
var __updateRate = function(value) {
|
||||
$("hid-mouse-rate-value").innerHTML = value + " ms";
|
||||
$("hid-mouse-rate-value").innerText = value + " ms";
|
||||
tools.storage.set("hid.mouse.rate", value);
|
||||
if (__timer) {
|
||||
clearInterval(__timer);
|
||||
@ -121,13 +121,13 @@ export function Mouse(__getGeometry, __recordWsEvent) {
|
||||
};
|
||||
|
||||
var __updateScrollRate = function(value) {
|
||||
$("hid-mouse-scroll-value").innerHTML = value;
|
||||
$("hid-mouse-scroll-value").innerText = value;
|
||||
tools.storage.set("hid.mouse.scroll_rate", value);
|
||||
__scroll_rate = value;
|
||||
};
|
||||
|
||||
var __updateRelativeSens = function(value) {
|
||||
$("hid-mouse-sens-value").innerHTML = value.toFixed(1);
|
||||
$("hid-mouse-sens-value").innerText = value.toFixed(1);
|
||||
tools.storage.set("hid.mouse.sens", value);
|
||||
__relative_sens = value;
|
||||
};
|
||||
|
||||
@ -208,7 +208,7 @@ export function Msd() {
|
||||
if (el.__names_json !== names_json) {
|
||||
el.innerHTML = names.map(name => `
|
||||
<div class="text">
|
||||
<div id="__msd-storage-${tools.makeIdByText(name)}-progress" class="progress">
|
||||
<div id="__msd-storage-${tools.makeTextId(name)}-progress" class="progress">
|
||||
<span class="progress-value"></span>
|
||||
</div>
|
||||
</div>
|
||||
@ -223,7 +223,7 @@ export function Msd() {
|
||||
? `${names.length === 1 ? "Storage: %s" : "Internal storage: %s"}` // eslint-disable-line
|
||||
: `Storage [${name}${part.writable ? "]" : ", read-only]"}: %s` // eslint-disable-line
|
||||
);
|
||||
let id = `__msd-storage-${tools.makeIdByText(name)}-progress`;
|
||||
let id = `__msd-storage-${tools.makeTextId(name)}-progress`;
|
||||
tools.progress.setSizeOf($(id), title, part.size, part.free);
|
||||
}
|
||||
};
|
||||
@ -270,8 +270,8 @@ export function Msd() {
|
||||
};
|
||||
|
||||
var __clickDownloadButton = function() {
|
||||
let image = encodeURIComponent($("msd-image-selector").value);
|
||||
tools.windowOpen(`api/msd/read?image=${image}`);
|
||||
let e_image = encodeURIComponent($("msd-image-selector").value);
|
||||
tools.windowOpen(`api/msd/read?image=${e_image}`);
|
||||
};
|
||||
|
||||
var __clickRemoveButton = function() {
|
||||
@ -299,13 +299,13 @@ export function Msd() {
|
||||
var __clickUploadNewButton = function() {
|
||||
let file = tools.input.getFile($("msd-new-file"));
|
||||
__http = new XMLHttpRequest();
|
||||
let prefix = encodeURIComponent($("msd-new-part-selector").value);
|
||||
let e_prefix = encodeURIComponent($("msd-new-part-selector").value);
|
||||
if (file) {
|
||||
let image = encodeURIComponent(file.name);
|
||||
__http.open("POST", `${ROOT_PREFIX}api/msd/write?prefix=${prefix}&image=${image}&remove_incomplete=1`, true);
|
||||
let e_image = encodeURIComponent(file.name);
|
||||
__http.open("POST", `${ROOT_PREFIX}api/msd/write?prefix=${e_prefix}&image=${e_image}&remove_incomplete=1`, true);
|
||||
} else {
|
||||
let url = encodeURIComponent($("msd-new-url").value);
|
||||
__http.open("POST", `${ROOT_PREFIX}api/msd/write_remote?prefix=${prefix}&url=${url}&remove_incomplete=1`, true);
|
||||
let e_url = encodeURIComponent($("msd-new-url").value);
|
||||
__http.open("POST", `${ROOT_PREFIX}api/msd/write_remote?prefix=${e_prefix}&url=${e_url}&remove_incomplete=1`, true);
|
||||
}
|
||||
__http.upload.timeout = 7 * 24 * 3600;
|
||||
__http.onreadystatechange = __uploadStateChange;
|
||||
@ -402,7 +402,8 @@ export function Msd() {
|
||||
if (__state && __state.storage && __state.storage.parts) {
|
||||
let part = __state.storage.parts[$("msd-new-part-selector").value];
|
||||
if (part && (file.size > part.size)) {
|
||||
wm.error(`The new image is too big for the Mass Storage partition.<br>Maximum: ${tools.formatSize(part.size)}`);
|
||||
let e_size = tools.escape(tools.formatSize(part.size));
|
||||
wm.error(`The new image is too big for the Mass Storage partition.<br>Maximum: ${e_size}`);
|
||||
el.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,7 +220,8 @@ export function MediaStreamer(__setActive, __setInactive, __setInfo, __orient) {
|
||||
let width = frame.displayWidth;
|
||||
let height = frame.displayHeight;
|
||||
switch (__orient) {
|
||||
case 90: case 270:
|
||||
case 90:
|
||||
case 270:
|
||||
width = frame.displayHeight;
|
||||
height = frame.displayWidth;
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ export function MjpegStreamer(__setActive, __setInactive, __setInfo) {
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
var __key = tools.makeId();
|
||||
var __key = tools.makeRandomId();
|
||||
var __id = "";
|
||||
var __fps = -1;
|
||||
var __state = null;
|
||||
@ -91,7 +91,7 @@ export function MjpegStreamer(__setActive, __setInactive, __setInfo) {
|
||||
|
||||
var __setStreamInactive = function() {
|
||||
let old_fps = __fps;
|
||||
__key = tools.makeId();
|
||||
__key = tools.makeRandomId();
|
||||
__id = "";
|
||||
__fps = -1;
|
||||
__state = null;
|
||||
@ -139,7 +139,7 @@ export function MjpegStreamer(__setActive, __setInactive, __setInfo) {
|
||||
__setStreamInactive();
|
||||
__stopChecking();
|
||||
|
||||
let path = `${ROOT_PREFIX}streamer/stream?key=${__key}`;
|
||||
let path = `${ROOT_PREFIX}streamer/stream?key=${encodeURIComponent(__key)}`;
|
||||
if (tools.browser.is_safari || tools.browser.is_ios) {
|
||||
// uStreamer fix for WebKit
|
||||
__logInfo("Using dual_final_frames=1 to fix WebKit bugs");
|
||||
|
||||
@ -178,8 +178,8 @@ export function Switch() {
|
||||
};
|
||||
|
||||
var __clickAddEdidButton = function() {
|
||||
let create_content = function(el_parent, el_ok_button) {
|
||||
tools.el.setEnabled(el_ok_button, false);
|
||||
let create_content = function(el_parent, el_ok_bt) {
|
||||
tools.el.setEnabled(el_ok_bt, false);
|
||||
el_parent.innerHTML = `
|
||||
<table>
|
||||
<tr>
|
||||
@ -203,7 +203,7 @@ export function Switch() {
|
||||
el_name.oninput = el_data.oninput = function() {
|
||||
let name = el_name.value.replace(/\s+/g, "");
|
||||
let data = el_data.value.replace(/\s+/g, "");
|
||||
tools.el.setEnabled(el_ok_button, ((name.length > 0) && /[0-9a-fA-F]{512}/.test(data)));
|
||||
tools.el.setEnabled(el_ok_bt, ((name.length > 0) && /[0-9a-fA-F]{512}/.test(data)));
|
||||
};
|
||||
};
|
||||
|
||||
@ -584,7 +584,7 @@ export function Switch() {
|
||||
};
|
||||
if ($("switch-atx-ask-switch").checked) {
|
||||
wm.confirm(`
|
||||
Are you sure you want to press the <b>${button}</b> button?<br>
|
||||
Are you sure you want to press the <b>${tools.escape(button)}</b> button?<br>
|
||||
Warning! This could cause data loss on the server.
|
||||
`).then(function(ok) {
|
||||
if (ok) {
|
||||
|
||||
@ -52,20 +52,28 @@ function __login() {
|
||||
let passwd = $("passwd-input").value + $("code-input").value;
|
||||
let body = `user=${encodeURIComponent(user)}&passwd=${encodeURIComponent(passwd)}`;
|
||||
tools.httpPost("api/auth/login", null, function(http) {
|
||||
if (http.status === 200) {
|
||||
switch (http.status) {
|
||||
case 200:
|
||||
tools.currentOpen("");
|
||||
} else if (http.status === 403) {
|
||||
break;
|
||||
|
||||
case 403:
|
||||
wm.error("Invalid credentials").then(__tryAgain);
|
||||
} else {
|
||||
break;
|
||||
|
||||
default: {
|
||||
let error = "";
|
||||
if (http.status === 400) {
|
||||
try { error = JSON.parse(http.responseText)["result"]["error"]; } catch { /* Nah */ }
|
||||
try {
|
||||
error = JSON.parse(http.responseText)["result"]["error"];
|
||||
} catch { /* Nah */ }
|
||||
}
|
||||
if (error === "ValidatorError") {
|
||||
wm.error("Invalid characters in credentials").then(__tryAgain);
|
||||
} else {
|
||||
wm.error("Login error", http.responseText).then(__tryAgain);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}, body, "application/x-www-form-urlencoded");
|
||||
__setEnabled(false);
|
||||
|
||||
@ -86,8 +86,11 @@ export var tools = new function() {
|
||||
/************************************************************************/
|
||||
|
||||
self.escape = function(text) {
|
||||
if (typeof text !== "string") {
|
||||
text = "" + text;
|
||||
}
|
||||
return text.replace(
|
||||
/[^0-9A-Za-z ]/g,
|
||||
/[^-_0-9A-Za-z ]/g,
|
||||
ch => "&#" + ch.charCodeAt(0) + ";"
|
||||
);
|
||||
};
|
||||
@ -100,7 +103,7 @@ export var tools = new function() {
|
||||
return text[0].toUpperCase() + text.slice(1);
|
||||
};
|
||||
|
||||
self.makeId = function() {
|
||||
self.makeRandomId = function() {
|
||||
let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let id = "";
|
||||
for (let count = 0; count < 16; ++count) {
|
||||
@ -109,16 +112,10 @@ export var tools = new function() {
|
||||
return id;
|
||||
};
|
||||
|
||||
self.makeIdByText = function(text) {
|
||||
self.makeTextId = function(text) {
|
||||
return btoa(text).replace("=", "_");
|
||||
};
|
||||
|
||||
self.getRandomInt = function(min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
};
|
||||
|
||||
self.formatSize = function(size) {
|
||||
if (size > 0) {
|
||||
let index = Math.floor( Math.log(size) / Math.log(1024) );
|
||||
@ -149,6 +146,12 @@ export var tools = new function() {
|
||||
return remapped;
|
||||
};
|
||||
|
||||
self.getRandomInt = function(min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
self.el = new function() {
|
||||
@ -270,26 +273,34 @@ export var tools = new function() {
|
||||
self.radio = new function() {
|
||||
return {
|
||||
"makeItem": function(name, title, value) {
|
||||
let e_id = self.escape(name) + self.makeTextId(value);
|
||||
return `
|
||||
<input type="radio" id="${name}-${value}" name="${name}" value="${value}" />
|
||||
<label for="${name}-${value}">${title}</label>
|
||||
<input
|
||||
type="radio"
|
||||
id="${e_id}"
|
||||
name="${tools.escape(name)}"
|
||||
value="${tools.escape(value)}"
|
||||
/>
|
||||
<label for="${e_id}">
|
||||
${tools.escape(title)}
|
||||
</label>
|
||||
`;
|
||||
},
|
||||
"setOnClick": function(name, callback, prevent_default=true) {
|
||||
for (let el of $$$(`input[type="radio"][name="${name}"]`)) {
|
||||
for (let el of $$$(`input[type="radio"][name="${CSS.escape(name)}"]`)) {
|
||||
self.el.setOnClick(el, callback, prevent_default);
|
||||
}
|
||||
},
|
||||
"getValue": function(name) {
|
||||
return document.querySelector(`input[type="radio"][name="${name}"]:checked`).value;
|
||||
return document.querySelector(`input[type="radio"][name="${CSS.escape(name)}"]:checked`).value;
|
||||
},
|
||||
"setValue": function(name, value) {
|
||||
for (let el of $$$(`input[type="radio"][name="${name}"]`)) {
|
||||
for (let el of $$$(`input[type="radio"][name="${CSS.escape(name)}"]`)) {
|
||||
el.checked = (el.value === value);
|
||||
}
|
||||
},
|
||||
"clickValue": function(name, value) {
|
||||
for (let el of $$$(`input[type="radio"][name="${name}"]`)) {
|
||||
for (let el of $$$(`input[type="radio"][name="${CSS.escape(name)}"]`)) {
|
||||
if (el.value === value) {
|
||||
el.click();
|
||||
return;
|
||||
@ -297,7 +308,7 @@ export var tools = new function() {
|
||||
}
|
||||
},
|
||||
"setEnabled": function(name, enabled) {
|
||||
for (let el of $$$(`input[type="radio"][name="${name}"]`)) {
|
||||
for (let el of $$$(`input[type="radio"][name="${CSS.escape(name)}"]`)) {
|
||||
self.el.setEnabled(el, enabled);
|
||||
}
|
||||
},
|
||||
|
||||
@ -32,16 +32,26 @@ export function main() {
|
||||
|
||||
function __loadKvmdInfo() {
|
||||
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 = `
|
||||
<span class="code-comment"># How to connect using the Linux terminal:<br>
|
||||
$</span> vncviewer ${window.location.hostname}::${vnc_port}
|
||||
`;
|
||||
} else if (http.status === 401 || http.status === 403) {
|
||||
switch (http.status) {
|
||||
case 200:
|
||||
__showKvmdInfo(JSON.parse(http.responseText).result);
|
||||
break;
|
||||
|
||||
case 401:
|
||||
case 403:
|
||||
tools.currentOpen("login");
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
setTimeout(__loadKvmdInfo, 1000);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function __showKvmdInfo(info) {
|
||||
$("vnc-text").innerHTML = `
|
||||
<span class="code-comment"># How to connect using the Linux terminal:<br>
|
||||
$</span> vncviewer ${tools.escape(window.location.hostname + "::" + info.extras.vnc.port)}
|
||||
`;
|
||||
}
|
||||
|
||||
@ -42,96 +42,105 @@ function __WindowManager() {
|
||||
var __menu_buttons = [];
|
||||
|
||||
var __init__ = function() {
|
||||
for (let el_button of $$$("button")) {
|
||||
for (let el of $$$("button")) {
|
||||
// XXX: Workaround for iOS Safari:
|
||||
// https://stackoverflow.com/questions/3885018/active-pseudo-class-doesnt-work-in-mobile-safari
|
||||
el_button.ontouchstart = function() {};
|
||||
el.ontouchstart = function() {};
|
||||
}
|
||||
|
||||
for (let el_button of $$("menu-button")) {
|
||||
el_button.parentElement.querySelector(".menu").setAttribute("tabindex", "-1");
|
||||
tools.el.setOnDown(el_button, () => __toggleMenu(el_button));
|
||||
__menu_buttons.push(el_button);
|
||||
for (let el of $$("menu-button")) {
|
||||
el.parentElement.querySelector(".menu").setAttribute("tabindex", "-1");
|
||||
tools.el.setOnDown(el, () => __toggleMenu(el));
|
||||
__menu_buttons.push(el);
|
||||
}
|
||||
|
||||
if (!window.ResizeObserver) {
|
||||
tools.error("ResizeObserver not supported");
|
||||
}
|
||||
|
||||
for (let el_window of $$("window")) {
|
||||
el_window.setAttribute("tabindex", "-1");
|
||||
__makeWindowMovable(el_window);
|
||||
__windows.push(el_window);
|
||||
for (let el_win of $$("window")) {
|
||||
el_win.setAttribute("tabindex", "-1");
|
||||
__makeWindowMovable(el_win);
|
||||
__windows.push(el_win);
|
||||
|
||||
if (el_window.classList.contains("window-resizable") && window.ResizeObserver) {
|
||||
if (el_win.classList.contains("window-resizable") && window.ResizeObserver) {
|
||||
new ResizeObserver(function() {
|
||||
// При переполнении рабочей области сократить размер окна по высоте.
|
||||
// По ширине оно настраивается само в CSS.
|
||||
let view = self.getViewGeometry();
|
||||
let rect = el_window.getBoundingClientRect();
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
if ((rect.bottom - rect.top) > (view.bottom - view.top)) {
|
||||
let ratio = (rect.bottom - rect.top) / (view.bottom - view.top);
|
||||
el_window.style.height = view.bottom - view.top + "px";
|
||||
el_window.style.width = Math.round((rect.right - rect.left) / ratio) + "px";
|
||||
el_win.style.height = view.bottom - view.top + "px";
|
||||
el_win.style.width = Math.round((rect.right - rect.left) / ratio) + "px";
|
||||
}
|
||||
|
||||
if (el_window.hasAttribute("data-centered")) {
|
||||
__centerWindow(el_window);
|
||||
if (el_win.hasAttribute("data-centered")) {
|
||||
__centerWindow(el_win);
|
||||
}
|
||||
}).observe(el_window);
|
||||
}).observe(el_win);
|
||||
}
|
||||
|
||||
let el_close_button = el_window.querySelector(".window-header .window-button-close");
|
||||
if (el_close_button) {
|
||||
el_close_button.title = "Close window";
|
||||
tools.el.setOnClick(el_close_button, () => self.closeWindow(el_window));
|
||||
{
|
||||
let el = el_win.querySelector(".window-header .window-button-close");
|
||||
if (el) {
|
||||
el.title = "Close window";
|
||||
tools.el.setOnClick(el, () => self.closeWindow(el_win));
|
||||
}
|
||||
}
|
||||
|
||||
let el_maximize_button = el_window.querySelector(".window-header .window-button-maximize");
|
||||
if (el_maximize_button) {
|
||||
el_maximize_button.title = "Maximize window";
|
||||
tools.el.setOnClick(el_maximize_button, function() {
|
||||
__maximizeWindow(el_window);
|
||||
__activateLastWindow(el_window);
|
||||
});
|
||||
}
|
||||
|
||||
let el_orig_button = el_window.querySelector(".window-header .window-button-original");
|
||||
if (el_orig_button) {
|
||||
el_orig_button.title = "Reduce window to its original size and center it";
|
||||
tools.el.setOnClick(el_orig_button, function() {
|
||||
el_window.style.width = "";
|
||||
el_window.style.height = "";
|
||||
__centerWindow(el_window);
|
||||
__activateLastWindow(el_window);
|
||||
});
|
||||
}
|
||||
|
||||
let el_enter_full_tab_button = el_window.querySelector(".window-header .window-button-enter-full-tab");
|
||||
let el_exit_full_tab_button = el_window.querySelector(".window-button-exit-full-tab");
|
||||
if (el_enter_full_tab_button && el_exit_full_tab_button) {
|
||||
el_enter_full_tab_button.title = "Stretch to the entire tab";
|
||||
tools.el.setOnClick(el_enter_full_tab_button, () => self.setFullTabWindow(el_window, true));
|
||||
tools.el.setOnClick(el_exit_full_tab_button, () => self.setFullTabWindow(el_window, false));
|
||||
}
|
||||
|
||||
let el_full_screen_button = el_window.querySelector(".window-header .window-button-full-screen");
|
||||
if (el_full_screen_button && __getFullScreenFunction(el_window)) {
|
||||
el_full_screen_button.title = "Go to full-screen mode";
|
||||
tools.el.setOnClick(el_full_screen_button, function() {
|
||||
__fullScreenWindow(el_window);
|
||||
el_window.focus(el_window); // Почему-то теряется фокус
|
||||
__activateLastWindow(el_window);
|
||||
{
|
||||
let el = el_win.querySelector(".window-header .window-button-maximize");
|
||||
if (el) {
|
||||
el.title = "Maximize window";
|
||||
tools.el.setOnClick(el, function() {
|
||||
__maximizeWindow(el_win);
|
||||
__activateLastWindow(el_win);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (let el_button of $$$("button[data-show-window]")) {
|
||||
tools.el.setOnClick(el_button, () => self.showWindow($(el_button.getAttribute("data-show-window"))));
|
||||
{
|
||||
let el = el_win.querySelector(".window-header .window-button-original");
|
||||
if (el) {
|
||||
el.title = "Reduce window to its original size and center it";
|
||||
tools.el.setOnClick(el, function() {
|
||||
el_win.style.width = "";
|
||||
el_win.style.height = "";
|
||||
__centerWindow(el_win);
|
||||
__activateLastWindow(el_win);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.onmouseup = __globalMouseButtonHandler;
|
||||
window.ontouchend = __globalMouseButtonHandler;
|
||||
{
|
||||
let el_enter = el_win.querySelector(".window-header .window-button-enter-full-tab");
|
||||
let el_exit = el_win.querySelector(".window-button-exit-full-tab");
|
||||
if (el_enter && el_exit) {
|
||||
el_enter.title = "Stretch to the entire tab";
|
||||
tools.el.setOnClick(el_enter, () => self.setFullTabWindow(el_win, true));
|
||||
tools.el.setOnClick(el_exit, () => self.setFullTabWindow(el_win, false));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let el = el_win.querySelector(".window-header .window-button-full-screen");
|
||||
if (el && __getFullScreenFunction(el_win)) {
|
||||
el.title = "Go to full-screen mode";
|
||||
tools.el.setOnClick(el, function() {
|
||||
__fullScreenWindow(el_win);
|
||||
el_win.focus(el_win); // Почему-то теряется фокус
|
||||
__activateLastWindow(el_win);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let el of $$$("button[data-show-window]")) {
|
||||
tools.el.setOnClick(el, () => self.showWindow($(el.getAttribute("data-show-window"))));
|
||||
}
|
||||
|
||||
window.onmouseup = window.ontouchend = __globalMouseButtonHandler;
|
||||
|
||||
window.addEventListener("focusin", (event) => __focusInOut(event, true));
|
||||
window.addEventListener("focusout", (event) => __focusInOut(event, false));
|
||||
@ -196,7 +205,12 @@ function __WindowManager() {
|
||||
var __modalCodeDialog = function(header, html, code, ok, cancel) {
|
||||
let create_content = function(el_content) {
|
||||
if (code) {
|
||||
html += `<br><br><div class="code"><pre style="margin:0px">${tools.escape(code)}</pre></div>`;
|
||||
html += `
|
||||
<br><br>
|
||||
<div class="code">
|
||||
<pre style="margin:0px">${tools.escape(code)}</pre>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
el_content.innerHTML = html;
|
||||
};
|
||||
@ -210,49 +224,49 @@ function __WindowManager() {
|
||||
el_modal.className = "modal";
|
||||
el_modal.style.visibility = "visible";
|
||||
|
||||
let el_window = document.createElement("div");
|
||||
el_window.className = "modal-window";
|
||||
el_window.setAttribute("tabindex", "-1");
|
||||
el_modal.appendChild(el_window);
|
||||
let el_win = document.createElement("div");
|
||||
el_win.className = "modal-window";
|
||||
el_win.setAttribute("tabindex", "-1");
|
||||
el_modal.appendChild(el_win);
|
||||
|
||||
let el_header = document.createElement("div");
|
||||
el_header.className = "modal-header";
|
||||
el_header.innerText = header;
|
||||
el_window.appendChild(el_header);
|
||||
el_win.appendChild(el_header);
|
||||
|
||||
let el_content = document.createElement("div");
|
||||
el_content.className = "modal-content";
|
||||
el_window.appendChild(el_content);
|
||||
el_win.appendChild(el_content);
|
||||
|
||||
let el_buttons = document.createElement("div");
|
||||
el_buttons.classList.add("modal-buttons", "buttons-row");
|
||||
el_window.appendChild(el_buttons);
|
||||
el_win.appendChild(el_buttons);
|
||||
|
||||
let el_cancel_button = null;
|
||||
let el_ok_button = null;
|
||||
let el_cancel_bt = null;
|
||||
let el_ok_bt = null;
|
||||
if (cancel) {
|
||||
el_cancel_button = document.createElement("button");
|
||||
el_cancel_button.className = "row100";
|
||||
el_cancel_button.innerText = "Cancel";
|
||||
el_buttons.appendChild(el_cancel_button);
|
||||
el_cancel_bt = document.createElement("button");
|
||||
el_cancel_bt.className = "row100";
|
||||
el_cancel_bt.innerText = "Cancel";
|
||||
el_buttons.appendChild(el_cancel_bt);
|
||||
}
|
||||
if (ok) {
|
||||
el_ok_button = document.createElement("button");
|
||||
el_ok_button.className = "row100";
|
||||
el_ok_button.innerText = "OK";
|
||||
el_buttons.appendChild(el_ok_button);
|
||||
el_ok_bt = document.createElement("button");
|
||||
el_ok_bt.className = "row100";
|
||||
el_ok_bt.innerText = "OK";
|
||||
el_buttons.appendChild(el_ok_bt);
|
||||
}
|
||||
if (ok && cancel) {
|
||||
el_ok_button.className = "row50";
|
||||
el_cancel_button.className = "row50";
|
||||
el_ok_bt.className = "row50";
|
||||
el_cancel_bt.className = "row50";
|
||||
}
|
||||
|
||||
el_window.onkeyup = function(event) {
|
||||
el_win.onkeyup = function(event) {
|
||||
event.preventDefault();
|
||||
if (ok && event.code === "Enter") {
|
||||
el_ok_button.click();
|
||||
el_ok_bt.click();
|
||||
} else if (cancel && event.code === "Escape") {
|
||||
el_cancel_button.click();
|
||||
el_cancel_bt.click();
|
||||
}
|
||||
};
|
||||
|
||||
@ -260,7 +274,7 @@ function __WindowManager() {
|
||||
if (ok || cancel) {
|
||||
promise = new Promise(function(resolve) {
|
||||
function close(retval) {
|
||||
__closeWindow(el_window);
|
||||
__closeWindow(el_win);
|
||||
let index = __windows.indexOf(el_modal);
|
||||
if (index !== -1) {
|
||||
__windows.splice(index, 1);
|
||||
@ -276,10 +290,10 @@ function __WindowManager() {
|
||||
}
|
||||
|
||||
if (cancel) {
|
||||
tools.el.setOnClick(el_cancel_button, () => close(false));
|
||||
tools.el.setOnClick(el_cancel_bt, () => close(false));
|
||||
}
|
||||
if (ok) {
|
||||
tools.el.setOnClick(el_ok_button, () => close(true));
|
||||
tools.el.setOnClick(el_ok_bt, () => close(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -288,7 +302,7 @@ function __WindowManager() {
|
||||
(parent || document.fullscreenElement || document.body).appendChild(el_modal);
|
||||
if (typeof html === "function") {
|
||||
// Это должно быть здесь, потому что элемент должен иметь родителя чтобы существовать
|
||||
html(el_content, el_ok_button);
|
||||
html(el_content, el_ok_bt);
|
||||
} else {
|
||||
el_content.innerHTML = html;
|
||||
}
|
||||
@ -297,26 +311,26 @@ function __WindowManager() {
|
||||
return promise;
|
||||
};
|
||||
|
||||
self.showWindow = function(el_window, activate=true, center=false) {
|
||||
self.showWindow = function(el_win, activate=true, center=false) {
|
||||
let showed = false;
|
||||
if (!self.isWindowVisible(el_window)) {
|
||||
if (!self.isWindowVisible(el_win)) {
|
||||
center = true;
|
||||
showed = true;
|
||||
}
|
||||
__organizeWindow(el_window, center);
|
||||
el_window.style.visibility = "visible";
|
||||
__organizeWindow(el_win, center);
|
||||
el_win.style.visibility = "visible";
|
||||
if (activate) {
|
||||
__activateWindow(el_window);
|
||||
__activateWindow(el_win);
|
||||
}
|
||||
if (el_window.show_hook) {
|
||||
if (el_win.show_hook) {
|
||||
if (showed) {
|
||||
el_window.show_hook();
|
||||
el_win.show_hook();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.isWindowVisible = function(el_window) {
|
||||
return (window.getComputedStyle(el_window, null).visibility !== "hidden");
|
||||
self.isWindowVisible = function(el_win) {
|
||||
return (window.getComputedStyle(el_win, null).visibility !== "hidden");
|
||||
};
|
||||
|
||||
self.getViewGeometry = function() {
|
||||
@ -329,35 +343,35 @@ function __WindowManager() {
|
||||
};
|
||||
};
|
||||
|
||||
self.closeWindow = function(el_window) {
|
||||
__closeWindow(el_window);
|
||||
__activateLastWindow(el_window);
|
||||
self.closeWindow = function(el_win) {
|
||||
__closeWindow(el_win);
|
||||
__activateLastWindow(el_win);
|
||||
};
|
||||
|
||||
self.setFullTabWindow = function(el_window, enabled) {
|
||||
el_window.classList.toggle("window-full-tab", enabled);
|
||||
__activateLastWindow(el_window);
|
||||
self.setFullTabWindow = function(el_win, enabled) {
|
||||
el_win.classList.toggle("window-full-tab", enabled);
|
||||
__activateLastWindow(el_win);
|
||||
let el_navbar = $("navbar");
|
||||
if (el_navbar) {
|
||||
tools.hidden.setVisible(el_navbar, !enabled);
|
||||
}
|
||||
};
|
||||
|
||||
var __closeWindow = function(el_window) {
|
||||
el_window.focus();
|
||||
el_window.blur();
|
||||
el_window.style.visibility = "hidden";
|
||||
if (el_window.close_hook) {
|
||||
el_window.close_hook();
|
||||
var __closeWindow = function(el_win) {
|
||||
el_win.focus();
|
||||
el_win.blur();
|
||||
el_win.style.visibility = "hidden";
|
||||
if (el_win.close_hook) {
|
||||
el_win.close_hook();
|
||||
}
|
||||
};
|
||||
|
||||
var __toggleMenu = function(el_a) {
|
||||
let all_hidden = true;
|
||||
|
||||
for (let el_button of __menu_buttons) {
|
||||
let el_menu = el_button.parentElement.querySelector(".menu");
|
||||
if (el_button === el_a && window.getComputedStyle(el_menu, null).visibility === "hidden") {
|
||||
for (let el_bt of __menu_buttons) {
|
||||
let el_menu = el_bt.parentElement.querySelector(".menu");
|
||||
if (el_bt === el_a && window.getComputedStyle(el_menu, null).visibility === "hidden") {
|
||||
let rect = el_menu.getBoundingClientRect();
|
||||
let offset = self.getViewGeometry().right - (rect.left + el_menu.clientWidth + 2); // + 2 is ugly hack
|
||||
if (offset < 0) {
|
||||
@ -366,13 +380,13 @@ function __WindowManager() {
|
||||
el_menu.style.removeProperty("right");
|
||||
}
|
||||
|
||||
el_button.classList.add("menu-button-pressed");
|
||||
el_bt.classList.add("menu-button-pressed");
|
||||
el_menu.style.visibility = "visible";
|
||||
let el_focus = el_menu.querySelector("[data-focus]");
|
||||
(el_focus !== null ? el_focus : el_menu).focus();
|
||||
all_hidden &= false;
|
||||
} else {
|
||||
el_button.classList.remove("menu-button-pressed");
|
||||
el_bt.classList.remove("menu-button-pressed");
|
||||
el_menu.style.visibility = "hidden";
|
||||
el_menu.style.removeProperty("right");
|
||||
}
|
||||
@ -394,9 +408,9 @@ function __WindowManager() {
|
||||
|
||||
var __closeAllMenues = function() {
|
||||
document.onkeyup = null;
|
||||
for (let el_button of __menu_buttons) {
|
||||
let el_menu = el_button.parentElement.querySelector(".menu");
|
||||
el_button.classList.remove("menu-button-pressed");
|
||||
for (let el_bt of __menu_buttons) {
|
||||
let el_menu = el_bt.parentElement.querySelector(".menu");
|
||||
el_bt.classList.remove("menu-button-pressed");
|
||||
el_menu.style.visibility = "hidden";
|
||||
el_menu.style.removeProperty("right");
|
||||
}
|
||||
@ -420,10 +434,10 @@ function __WindowManager() {
|
||||
&& !event.target.closest(".menu-button")
|
||||
&& !event.target.closest(".modal")
|
||||
) {
|
||||
for (let el_item = event.target; el_item && el_item !== document; el_item = el_item.parentNode) {
|
||||
if (el_item.classList.contains("menu")) {
|
||||
for (let el = event.target; el && el !== document; el = el.parentNode) {
|
||||
if (el.classList.contains("menu")) {
|
||||
return;
|
||||
} else if (el_item.hasAttribute("data-force-hide-menu")) {
|
||||
} else if (el.hasAttribute("data-force-hide-menu")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -433,122 +447,122 @@ function __WindowManager() {
|
||||
};
|
||||
|
||||
var __organizeWindowsOnBrowserResize = function() {
|
||||
for (let el_window of $$("window")) {
|
||||
if (el_window.style.visibility === "visible") {
|
||||
if (tools.browser.is_mobile && el_window.classList.contains("window-resizable")) {
|
||||
for (let el_win of $$("window")) {
|
||||
if (el_win.style.visibility === "visible") {
|
||||
if (tools.browser.is_mobile && el_win.classList.contains("window-resizable")) {
|
||||
// FIXME: При смене ориентации на мобильном браузере надо сбрасывать
|
||||
// настройки окна стрима, поэтому тут стоит вот этот костыль
|
||||
el_window.style.width = "";
|
||||
el_window.style.height = "";
|
||||
el_win.style.width = "";
|
||||
el_win.style.height = "";
|
||||
}
|
||||
__organizeWindow(el_window);
|
||||
__organizeWindow(el_win);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var __organizeWindow = function(el_window, center=false) {
|
||||
var __organizeWindow = function(el_win, center=false) {
|
||||
let view = self.getViewGeometry();
|
||||
let rect = el_window.getBoundingClientRect();
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
|
||||
if (el_window.classList.contains("window-resizable")) {
|
||||
if (el_win.classList.contains("window-resizable")) {
|
||||
// При переполнении рабочей области сократить размер окна
|
||||
if ((rect.bottom - rect.top) > (view.bottom - view.top)) {
|
||||
let ratio = (rect.bottom - rect.top) / (view.bottom - view.top);
|
||||
el_window.style.height = view.bottom - view.top + "px";
|
||||
el_window.style.width = Math.round((rect.right - rect.left) / ratio) + "px";
|
||||
el_win.style.height = view.bottom - view.top + "px";
|
||||
el_win.style.width = Math.round((rect.right - rect.left) / ratio) + "px";
|
||||
}
|
||||
if ((rect.right - rect.left) > (view.right - view.left)) {
|
||||
el_window.style.width = view.right - view.left + "px";
|
||||
el_win.style.width = view.right - view.left + "px";
|
||||
}
|
||||
rect = el_window.getBoundingClientRect();
|
||||
rect = el_win.getBoundingClientRect();
|
||||
}
|
||||
|
||||
if (el_window.hasAttribute("data-centered") || center) {
|
||||
__centerWindow(el_window);
|
||||
if (el_win.hasAttribute("data-centered") || center) {
|
||||
__centerWindow(el_win);
|
||||
} else {
|
||||
if (rect.top <= view.top) {
|
||||
el_window.style.top = view.top + "px";
|
||||
el_win.style.top = view.top + "px";
|
||||
} else if (rect.bottom > view.bottom) {
|
||||
el_window.style.top = view.bottom - rect.height + "px";
|
||||
el_win.style.top = view.bottom - rect.height + "px";
|
||||
}
|
||||
|
||||
if (rect.left <= view.left) {
|
||||
el_window.style.left = view.left + "px";
|
||||
el_win.style.left = view.left + "px";
|
||||
} else if (rect.right > view.right) {
|
||||
el_window.style.left = view.right - rect.width + "px";
|
||||
el_win.style.left = view.right - rect.width + "px";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var __centerWindow = function(el_window) {
|
||||
var __centerWindow = function(el_win) {
|
||||
let view = self.getViewGeometry();
|
||||
let rect = el_window.getBoundingClientRect();
|
||||
el_window.style.top = Math.max(view.top, Math.round((view.bottom - rect.height) / 2)) + "px";
|
||||
el_window.style.left = Math.round((view.right - rect.width) / 2) + "px";
|
||||
el_window.setAttribute("data-centered", "");
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
el_win.style.top = Math.max(view.top, Math.round((view.bottom - rect.height) / 2)) + "px";
|
||||
el_win.style.left = Math.round((view.right - rect.width) / 2) + "px";
|
||||
el_win.setAttribute("data-centered", "");
|
||||
};
|
||||
|
||||
var __activateLastWindow = function(el_except_window=null) {
|
||||
let el_last_window = null;
|
||||
var __activateLastWindow = function(el_except_win=null) {
|
||||
let el_last_win = null;
|
||||
|
||||
if (document.activeElement) {
|
||||
el_last_window = (document.activeElement.closest(".modal-window") || document.activeElement.closest(".window"));
|
||||
if (el_last_window && window.getComputedStyle(el_last_window, null).visibility === "hidden") {
|
||||
el_last_window = null;
|
||||
el_last_win = (document.activeElement.closest(".modal-window") || document.activeElement.closest(".window"));
|
||||
if (el_last_win && window.getComputedStyle(el_last_win, null).visibility === "hidden") {
|
||||
el_last_win = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!el_last_window || el_last_window === el_except_window) {
|
||||
if (!el_last_win || el_last_win === el_except_win) {
|
||||
let max_z_index = 0;
|
||||
|
||||
for (let el_window of __windows) {
|
||||
let z_index = parseInt(window.getComputedStyle(el_window, null).zIndex) || 0;
|
||||
let visibility = window.getComputedStyle(el_window, null).visibility;
|
||||
for (let el_win of __windows) {
|
||||
let z_index = parseInt(window.getComputedStyle(el_win, null).zIndex) || 0;
|
||||
let visibility = window.getComputedStyle(el_win, null).visibility;
|
||||
|
||||
if (max_z_index < z_index && visibility !== "hidden" && el_window !== el_except_window) {
|
||||
el_last_window = el_window;
|
||||
if (max_z_index < z_index && visibility !== "hidden" && el_win !== el_except_win) {
|
||||
el_last_win = el_win;
|
||||
max_z_index = z_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (el_last_window) {
|
||||
tools.debug("UI: Activating last window:", el_last_window);
|
||||
__activateWindow(el_last_window);
|
||||
if (el_last_win) {
|
||||
tools.debug("UI: Activating last window:", el_last_win);
|
||||
__activateWindow(el_last_win);
|
||||
} else {
|
||||
tools.debug("UI: No last window to activation");
|
||||
}
|
||||
};
|
||||
|
||||
var __activateWindow = function(el_window) {
|
||||
if (window.getComputedStyle(el_window, null).visibility !== "hidden") {
|
||||
var __activateWindow = function(el_win) {
|
||||
if (window.getComputedStyle(el_win, null).visibility !== "hidden") {
|
||||
let el_to_focus;
|
||||
let el_window_contains_focus;
|
||||
let el_focused; // A window which contains a focus
|
||||
|
||||
if (el_window.className === "modal") {
|
||||
el_to_focus = el_window.querySelector(".modal-window");
|
||||
el_window_contains_focus = (document.activeElement && document.activeElement.closest(".modal-window"));
|
||||
if (el_win.className === "modal") {
|
||||
el_to_focus = el_win.querySelector(".modal-window");
|
||||
el_focused = (document.activeElement && document.activeElement.closest(".modal-window"));
|
||||
} else { // .window
|
||||
el_to_focus = el_window;
|
||||
el_window_contains_focus = (document.activeElement && document.activeElement.closest(".window"));
|
||||
el_to_focus = el_win;
|
||||
el_focused = (document.activeElement && document.activeElement.closest(".window"));
|
||||
}
|
||||
|
||||
if (el_window.className !== "modal" && parseInt(el_window.style.zIndex) !== __top_z_index) {
|
||||
if (el_win.className !== "modal" && parseInt(el_win.style.zIndex) !== __top_z_index) {
|
||||
__top_z_index += 1;
|
||||
el_window.style.zIndex = __top_z_index;
|
||||
tools.debug("UI: Activated window:", el_window);
|
||||
el_win.style.zIndex = __top_z_index;
|
||||
tools.debug("UI: Activated window:", el_win);
|
||||
}
|
||||
|
||||
if (el_window !== el_window_contains_focus) {
|
||||
if (el_win !== el_focused) {
|
||||
el_to_focus.focus();
|
||||
tools.debug("UI: Focused window:", el_window);
|
||||
tools.debug("UI: Focused window:", el_win);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var __makeWindowMovable = function(el_window) {
|
||||
let el_header = el_window.querySelector(".window-header");
|
||||
let el_grab = el_window.querySelector(".window-header .window-grab");
|
||||
var __makeWindowMovable = function(el_win) {
|
||||
let el_header = el_win.querySelector(".window-header");
|
||||
let el_grab = el_win.querySelector(".window-header .window-grab");
|
||||
if (el_header === null || el_grab === null) {
|
||||
// Для псевдоокна OCR
|
||||
return;
|
||||
@ -559,10 +573,10 @@ function __WindowManager() {
|
||||
function startMoving(event) {
|
||||
// При перетаскивании resizable-окна за правый кран экрана оно ужимается.
|
||||
// Этот костыль фиксит это.
|
||||
el_window.style.width = el_window.offsetWidth + "px";
|
||||
el_win.style.width = el_win.offsetWidth + "px";
|
||||
|
||||
__closeAllMenues();
|
||||
__activateWindow(el_window);
|
||||
__activateWindow(el_win);
|
||||
event = (event || window.event);
|
||||
event.preventDefault();
|
||||
|
||||
@ -580,7 +594,7 @@ function __WindowManager() {
|
||||
}
|
||||
|
||||
function doMoving(event) {
|
||||
el_window.removeAttribute("data-centered");
|
||||
el_win.removeAttribute("data-centered");
|
||||
|
||||
event = (event || window.event);
|
||||
event.preventDefault();
|
||||
@ -589,8 +603,8 @@ function __WindowManager() {
|
||||
let x = prev_pos.x - event_pos.x;
|
||||
let y = prev_pos.y - event_pos.y;
|
||||
|
||||
el_window.style.top = (el_window.offsetTop - y) + "px";
|
||||
el_window.style.left = (el_window.offsetLeft - x) + "px";
|
||||
el_win.style.top = (el_win.offsetTop - y) + "px";
|
||||
el_win.style.left = (el_win.offsetLeft - x) + "px";
|
||||
|
||||
prev_pos = event_pos;
|
||||
}
|
||||
@ -613,29 +627,29 @@ function __WindowManager() {
|
||||
}
|
||||
}
|
||||
|
||||
el_window.setAttribute("data-centered", "");
|
||||
el_window.onmousedown = el_window.ontouchstart = () => __activateWindow(el_window);
|
||||
el_win.setAttribute("data-centered", "");
|
||||
el_win.onmousedown = el_win.ontouchstart = () => __activateWindow(el_win);
|
||||
|
||||
el_grab.onmousedown = startMoving;
|
||||
el_grab.ontouchstart = startMoving;
|
||||
};
|
||||
|
||||
var __onFullScreenChange = function(event) {
|
||||
let el_window = event.target;
|
||||
let el_win = event.target;
|
||||
if (!document.fullscreenElement) {
|
||||
let rect = el_window.before_full_screen;
|
||||
let rect = el_win.before_full_screen;
|
||||
if (rect) {
|
||||
el_window.style.width = rect.width + "px";
|
||||
el_window.style.height = rect.height + "px";
|
||||
el_window.style.top = rect.top + "px";
|
||||
el_window.style.left = rect.left + "px";
|
||||
el_win.style.width = rect.width + "px";
|
||||
el_win.style.height = rect.height + "px";
|
||||
el_win.style.top = rect.top + "px";
|
||||
el_win.style.left = rect.left + "px";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var __fullScreenWindow = function(el_window) {
|
||||
el_window.before_full_screen = el_window.getBoundingClientRect();
|
||||
__getFullScreenFunction(el_window).call(el_window);
|
||||
var __fullScreenWindow = function(el_win) {
|
||||
el_win.before_full_screen = el_win.getBoundingClientRect();
|
||||
__getFullScreenFunction(el_win).call(el_win);
|
||||
if (navigator.keyboard && navigator.keyboard.lock) {
|
||||
navigator.keyboard.lock();
|
||||
} else {
|
||||
@ -647,26 +661,26 @@ function __WindowManager() {
|
||||
+ "In Chrome use HTTPS and enable <i>system-keyboard-lock</i><br>"
|
||||
+ "by putting at URL <i>chrome://flags/#system-keyboard-lock</i>"
|
||||
);
|
||||
__modalDialog("Keyboard lock is unsupported", msg, true, false, el_window);
|
||||
__modalDialog("Keyboard lock is unsupported", msg, true, false, el_win);
|
||||
}
|
||||
};
|
||||
|
||||
var __maximizeWindow = function(el_window) {
|
||||
var __maximizeWindow = function(el_win) {
|
||||
let el_navbar = $("navbar");
|
||||
let vertical_offset = (el_navbar ? el_navbar.offsetHeight : 0);
|
||||
el_window.style.left = "0px";
|
||||
el_window.style.top = vertical_offset + "px";
|
||||
el_window.style.width = window.innerWidth + "px";
|
||||
el_window.style.height = window.innerHeight - vertical_offset + "px";
|
||||
el_win.style.left = "0px";
|
||||
el_win.style.top = vertical_offset + "px";
|
||||
el_win.style.width = window.innerWidth + "px";
|
||||
el_win.style.height = window.innerHeight - vertical_offset + "px";
|
||||
};
|
||||
|
||||
var __getFullScreenFunction = function(el_window) {
|
||||
if (el_window.requestFullscreen) {
|
||||
return el_window.requestFullscreen;
|
||||
} else if (el_window.webkitRequestFullscreen) {
|
||||
return el_window.webkitRequestFullscreen;
|
||||
} else if (el_window.mozRequestFullscreen) {
|
||||
return el_window.mozRequestFullscreen;
|
||||
var __getFullScreenFunction = function(el_win) {
|
||||
if (el_win.requestFullscreen) {
|
||||
return el_win.requestFullscreen;
|
||||
} else if (el_win.webkitRequestFullscreen) {
|
||||
return el_win.webkitRequestFullscreen;
|
||||
} else if (el_win.mozRequestFullscreen) {
|
||||
return el_win.mozRequestFullscreen;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user