ai-adventure-labs/server/frontend/public/js/main.js

389 lines
13 KiB
JavaScript

// cookie parser function
function getCookies() {
return Object.fromEntries(
document.cookie
.split(/\s{0,};\s{0,}/gimu)
.map((i) => i.split(/\s{0,}=\s{0,}/gimu)),
);
}
// translate function
function translate(page) {
[...document.getElementsByClassName("translate")].forEach((translateEl) => {
// console.log(translateEl.id);
const result = tr(page, translateEl.id);
// console.log(result);
if (result) translateEl.innerHTML = result;
});
[...document.getElementsByClassName("linked-btn")].forEach((el) => {
el.style.cursor = "pointer";
});
}
// Get random integer number function
function randint(min, max) {
return Math.ceil(Math.random() * (max - min) + min);
}
// Get traceId for requests to server
function getTraceId() {
const dict = "1234567890abcdefABCDEF";
return [...new Array(16)]
.map(() => dict[randint(0, dict.length - 1)])
.join("");
}
// load styles
document.head.innerHTML +=
'\\n <link href="/bootstrap/bootstrap.min.css" rel="stylesheet">';
document.head.innerHTML += '\\n <link href="/css/main.css" rel="stylesheet">';
document.head.innerHTML +=
'\\n <link href="/font-awesome/css/all.css" rel="stylesheet">';
document.head.innerHTML += '\\n <link rel="icon" href="/favicon.png">';
// load main page
document.body.innerHTML = `<nav id="navbar-main" class="navbar navbar-expand-lg navbar-dark bg-dark"><div class="container-fluid">
<a class="navbar-brand linked-btn" onclick="fl.go('/');">
Adventure AI Labs
</a>
<div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav">
<div class="vr"></div>
<li class="nav-item">
<a class="nav-link translate linked-btn" aria-current="page" onclick="fl.go('/');" id="nav-home-btn"><i class="fas fa-home"></i> Home</a>
</li>
<li class="nav-item">
<a class="nav-link translate linked-btn" aria-current="page" onclick="fl.go('/connect');" id="nav-connect-btn"><i class="fas fa-network-wired"></i> Connect</a>
</li>
<li class="nav-item">
<a class="nav-link translate linked-btn" aria-current="page" onclick="fl.go('/documentation');" id="nav-docs-btn"><i class="fas fa-book"></i> Documentation</a>
</li>
</ul></div>
</div></nav>
<div id="fl.area">
</div>`;
function checkContentWarning(successfulHandler) {
const warnModal = new bootstrap.Modal(
document.getElementById("warningModal"),
{},
);
document.getElementById("accept-denial-btn").onclick = () => {
document.cookie = "cw=1";
successfulHandler?.();
};
const cookies = getCookies();
if (!cookies.cw) {
warnModal.show();
} else {
successfulHandler?.();
}
}
// Fl Handlers
fl.bindLoad("/connect", () => {
translate("/connect");
function initNewConnectionOpen() {
if (initNewConnectionOpen.interval)
clearInterval(initNewConnectionOpen.interval);
document.getElementById("custom-conn-address").value = "";
document.getElementById("custom-conn-port").value = 80;
document.getElementById("custom-conn-encryption").checked = false;
document.getElementById("custom-connect-btn").disabled = true;
const connButton = document.getElementById("custom-connect-btn");
initNewConnectionOpen.interval = setInterval(() => {
const address = document.getElementById("custom-conn-address");
// address.value
const port = document.getElementById("custom-conn-port");
// port.value
const isWSS = document.getElementById("custom-conn-encryption");
// isWSS.checked
// connButton.disabled
if (address.value.match(/^wss:\/\//)) {
address.value = address.value.slice(6);
isWSS.checked = true;
}
if (address.value.match(/^ws:\/\//)) {
address.value = address.value.slice(5);
isWSS.checked = false;
}
if (address.value.match(/:[0-9]{1,5}$/)) {
const portSelected = +address.value
.match(/:[0-9]{1,5}$/)
.at(0)
.slice(1);
address.value = address.value.slice(
0,
-1 * (":" + portSelected).length,
);
port.value = portSelected;
document.getElementById("custom-conn-port").focus();
}
if (!port.value) {
port.value = 80;
}
if (+port.value < 0) port.value = 0;
if (+port.value > 65535) port.value = 65535;
connButton.disabled = !address.value;
}, 50);
connButton.onclick = () => {
const serverlist =
JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? [];
serverlist.push({
address: document.getElementById("custom-conn-address").value,
port: +document.getElementById("custom-conn-port").value,
tls: document.getElementById("custom-conn-encryption").checked,
});
localStorage.setItem("savedServers", JSON.stringify(serverlist));
connectServers();
};
}
function connectServers() {
document.getElementById("loading-servers").innerHTML =
`<center><p>${tr("/connect", "loading") ?? "Loading..."}</p></center>`;
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/active-servers.json", true);
xhr.onerror = () => {
document.getElementById("loading-servers").innerHTML = `<center>
<h3>${tr("/connect", "connection-failed") ?? "Connection failed"}</h3><hr>
<button type="button" class="btn btn-primary translate" id="retry-connecting">${tr("/connect", "retry-connecting") ?? "Retry"}</button>
</center>`;
document.getElementById("retry-connecting").onclick = () =>
connectServers();
};
xhr.onload = async () => {
if (xhr.status === 200) {
const localServers = (
JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? []
).map((x) => {
x.fromLocal = true;
return x;
});
const servers = localServers.concat(
JSON.parse(xhr.response).result.map((x) => {
x.fromLocal = false;
return x;
}),
);
const serversByItemID = new Object();
const serversByAddress = new Object();
const items = [];
const itemIDs = [];
const mp = servers.map(async (serverItem) => {
const promise = new Promise((resolve, reject) => {
console.log("serverItem:", serverItem);
const trace_id = getTraceId();
const socket = new WebSocket(
`${!serverItem.tls ? "ws" : "wss"}://${serverItem.address}:${serverItem.port}`,
);
let ping = new Date();
socket.onopen = () => {
ping = new Date() - ping;
socket.onmessage = (ev) => {
const data = JSON.parse(ev.data).result;
console.debug("data:", data);
data.tls = serverItem.tls;
itemIDs.push({
...data,
itemID: `con-btn-to:${data.tag}:${serverItem.address}:${serverItem.port}`,
deleteID: `remove-con:${serverItem.address}:${serverItem.port}`,
address: `${serverItem.address}:${serverItem.port}`,
});
serversByItemID[
`con-btn-to:${data.tag}:${serverItem.address}:${serverItem.port}`
] = { data, serverItem };
serversByAddress[`${serverItem.address}:${serverItem.port}`] = {
data,
serverItem,
};
resolve(
items.push(`<tr${!data.tls ? ' style="background-color: #7F6003"' : ""}>
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}>${data.name}</td>
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}>${serverItem.address}:${serverItem.port}</td>
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}>${!data.tls ? '<font color="red"><i class="fas fa-exclamation-triangle"></i></font>' : '<font color="green"><i class="fas fa-lock"></i></font>'}</td>
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}>${ping}</td>
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}><button class="btn btn-secondary" id="con-btn-to:${data.tag}:${serverItem.address}:${serverItem.port}">${tr("/connect", "connect-to-server-btn") ?? "Connect"}</button></td>
<td${!data.tls ? ' style="background-color: #7F6003"' : ""}><button class="btn btn-outline-danger" id="remove-con:${serverItem.address}:${serverItem.port}"${!serverItem.fromLocal ? " disabled" : ""}><i class="fas fa-trash"></i></button></td>
</tr>`),
);
};
socket.send(
JSON.stringify({
method: "info",
fields: "name,tag",
trace_id,
}),
);
};
socket.onerror = (err) => {
console.error(err);
itemIDs.push({
deleteID: `remove-con:${serverItem.address}:${serverItem.port}`,
address: `${serverItem.address}:${serverItem.port}`,
});
serversByAddress[`${serverItem.address}:${serverItem.port}`] = {
serverItem,
};
resolve(
items.push(`<tr>
<td style="background-color: #7F0000"><font color="red">${tr("/connect", "offline-server") ?? "Offline"}</font></td>
<td style="background-color: #7F0000">${serverItem.address}:${serverItem.port}</td>
<td style="background-color: #7F0000"><font color="red"><i class="fas fa-exclamation-triangle"></i></font></td>
<td style="background-color: #7F0000"><font color="red">${tr("/connect", "offline-server") ?? "Offline"}</font></td>
<td style="background-color: #7F0000"><button class="btn btn-danger" disabled>${tr("/connect", "offline-server") ?? "Offline"}</button></td>
<td style="background-color: #7F0000"><button class="btn btn-outline-danger" id="remove-con:${serverItem.address}:${serverItem.port}"${!serverItem.fromLocal ? " disabled" : ""}><i class="fas fa-trash"></i></button></td>
</tr>`),
);
};
});
return await promise;
});
await Promise.all(mp);
items.push(
`<tr><td colspan="6"><center><button class="btn btn-primary" id="conn-to-custom">${tr("/connect", "add-custon-server") ?? "Connect to custom server"}</button></center></td></tr>`,
);
document.getElementById("loading-servers").innerHTML =
`<table class="table table-dark">
<thead>
<th scope="col">${tr("/connect", "server-name-tbl") ?? "Name"}</th>
<th scope="col">${tr("/connect", "server-address") ?? "Address"}</th>
<th scope="col">${tr("/connect", "server-encryption") ?? "Encrypted"}</th>
<th scope="col">${tr("/connect", "server-ping") ?? "Ping"}</th>
<th scope="col">${tr("/connect", "server-action") ?? "Action"}</th>
<th scope="col"></th>
</thead>
<tbody>
${items.join("\n")}
</tbody>
</table>`;
itemIDs.forEach((btn) => {
//console.log("btn:", btn);
if (btn.itemID)
document.getElementById(btn.itemID).onclick = () => {
checkContentWarning(() => {
const serverInfo = serversByItemID[btn.itemID].serverItem;
window.open(
`/connect-area?server=${serverInfo.address}:${serverInfo.port}&encrypted=${serverInfo.tls ? "true" : "false"}`,
);
});
};
document.getElementById(btn.deleteID).onclick = () => {
const serverInfo = serversByAddress[btn.address].serverItem;
console.log("serverInfo:", serverInfo);
const savedServers = (
JSON.parse(localStorage.getItem("savedServers") ?? "null") ?? []
).filter((server) => {
return !(
server.address === serverInfo.address &&
server.port === serverInfo.port
);
});
localStorage.setItem("savedServers", JSON.stringify(savedServers));
connectServers();
};
});
document.getElementById("conn-to-custom").onclick = function () {
const connectModal = new bootstrap.Modal(
document.getElementById("connectModal"),
{},
);
initNewConnectionOpen();
connectModal.show();
};
}
};
xhr.send();
}
const cookies = getCookies();
console.log(cookies);
const cookiesModal = new bootstrap.Modal(
document.getElementById("cookiesModal"),
{},
);
if (!cookies.accept_cookies) {
cookiesModal.show();
} else {
connectServers();
}
document.getElementById("accept-cookie-btn").onclick = () => {
document.cookie = "accept_cookies=1";
connectServers();
};
/*document.getElementById("enable-cookie-cnt").onclick = () => {
cookiesModal.show();
};*/
});
fl.bindLoad("", () => {
translate("/");
// carousel
function onMouse(condition) {
return;
[...document.getElementsByClassName("card-img")].forEach((img) => {
img.style.filter = `blur(${!condition ? 5 : 0}px)`;
});
}
onMouse(false);
[...document.getElementsByClassName("carousel-item")].forEach((item) => {
item.onmouseout = () => onMouse(false);
item.onmouseover = () => onMouse(true);
});
[...document.getElementsByClassName("btn-card")].forEach((item) => {
item.onmouseout = () => onMouse(true);
item.onmouseover = () => onMouse(false);
});
const interval = setInterval(() => {
const navbarHeight = +document.getElementById("navbar-main")?.offsetHeight;
/*if (document.getElementById('main_img1')?.src) {
document.getElementById('main_img1').src = window.screen.availWidth / window.screen.availHeight > 1.45 ? "/assets/hello/1.png" : "/assets/hello/m/1.png";
document.getElementById('main_img2').src = window.screen.availWidth / window.screen.availHeight > 1.45 ? "/assets/hello/2.png" : "/assets/hello/m/2.png";
document.getElementById('main_img3').src = window.screen.availWidth / window.screen.availHeight > 1.45 ? "/assets/hello/3.png" : "/assets/hello/m/3.png";
}*/
const selectedCSS = Object.entries(document.styleSheets).filter(
([key, cssFileObject]) =>
cssFileObject.href === `${location.origin}/css/main.css`,
)[0][1];
Object.entries(selectedCSS.rules).filter(
([key, rule]) =>
rule.selectorText ==
".carousel > .carousel-inner > .carousel-item > img",
)[0][1].style.height = `calc(100vh - ${navbarHeight}px)`;
// console.log('ok');
}, 1);
fl.bindUnload("/", () => {
clearInterval(interval);
});
});
// Go to current page
fl.goJust(window.location.pathname);