2023-01-26 05:57:31 +00:00
|
|
|
let adminToken = null;
|
2023-01-28 07:28:15 +00:00
|
|
|
const adminWrapper = document.getElementById("adminWrapper");
|
|
|
|
const adminZone = document.getElementById("adminZone");
|
2023-07-06 05:19:14 +00:00
|
|
|
const spriteZone = document.getElementById("spriteZone");
|
2023-01-28 07:28:15 +00:00
|
|
|
const createTableForm = document.getElementById("createTableForm");
|
2023-07-06 05:19:14 +00:00
|
|
|
const createTokenForm = document.getElementById("createTokenForm");
|
|
|
|
const tokenWrapper = document.getElementById("adminWrapper_tokens");
|
2023-01-28 07:28:15 +00:00
|
|
|
const newTableName = document.getElementById("newTableName");
|
|
|
|
const newTablePass = document.getElementById("newTablePass");
|
2023-07-06 08:20:30 +00:00
|
|
|
const tokenSpriteDropdown = document.getElementById("token_combobox");
|
|
|
|
const tokenName = document.getElementById("token_name");
|
|
|
|
const tokenWidth = document.getElementById("token_width");
|
|
|
|
const tokenHeight = document.getElementById("token_height");
|
|
|
|
const tokenCX = document.getElementById("token_cx");
|
|
|
|
const tokenCY = document.getElementById("token_cy");
|
|
|
|
const previewZone = document.getElementById("tokenPreview_zone");
|
|
|
|
const tokenAspect = document.getElementById("tokenKeepAspect");
|
|
|
|
const aspectLockLabel = document.getElementById("aspectLockLabel");
|
2023-07-08 05:56:41 +00:00
|
|
|
const tokenZone = document.getElementById("tokenZone");
|
2023-01-26 05:57:31 +00:00
|
|
|
|
2023-07-08 07:42:31 +00:00
|
|
|
async function rebindUi(name, pass) {
|
2023-02-10 05:45:09 +00:00
|
|
|
try {
|
|
|
|
const headers = new Headers();
|
|
|
|
headers.set('Authorization', 'Bearer ' + adminToken.access_token);
|
|
|
|
const res = await fetch(`/admin/api/table/${name}?passcode=${pass}`, {
|
|
|
|
method: 'GET',
|
|
|
|
headers: headers,
|
|
|
|
});
|
2023-04-06 04:33:38 +00:00
|
|
|
|
2023-07-04 07:08:01 +00:00
|
|
|
const mapImgs = await fetch (`/admin/api/upload/${name}/map/?passcode=${pass}`, {
|
2023-04-06 04:33:38 +00:00
|
|
|
method: 'GET',
|
|
|
|
headers: headers,
|
|
|
|
});
|
2023-07-06 05:19:14 +00:00
|
|
|
|
|
|
|
const tokenImgs = await fetch(`/admin/api/upload/${name}/token/?passcode=${pass}`, {
|
|
|
|
method: 'GET',
|
|
|
|
headers: headers,
|
|
|
|
});
|
|
|
|
|
|
|
|
let infoHtml = ""
|
2023-02-10 05:45:09 +00:00
|
|
|
if (res.ok) {
|
2023-02-22 05:27:54 +00:00
|
|
|
document.getElementById("input_table_name").value = name;
|
|
|
|
document.getElementById("input_table_pass").value = pass;
|
|
|
|
dial();
|
2023-07-08 05:56:41 +00:00
|
|
|
const table = await res.json()
|
2023-07-09 06:48:19 +00:00
|
|
|
infoHtml = "<a href='#' onclick='getTables();return false;'>← table list</a><br>";
|
2023-07-08 05:56:41 +00:00
|
|
|
infoHtml += `<textarea id='auxMsgZone'>${table.auxMsg}</textarea><br><button onclick='publishAuxMsg()'>Set Status</button>`
|
2023-07-03 05:10:58 +00:00
|
|
|
infoHtml += "<button onclick='destroyTable()'>Destroy Table</button><br/>";
|
|
|
|
infoHtml += "<input id='map_img_upload' type='file'/><button onclick='uploadMapImg()'>Upload Map</button><br/>"
|
2023-04-06 04:33:38 +00:00
|
|
|
if (mapImgs.ok) {
|
2023-07-03 05:10:58 +00:00
|
|
|
infoHtml += "<label>Available Maps</label>";
|
2023-07-14 02:27:19 +00:00
|
|
|
const imgs = (await mapImgs.json()).sort();
|
2023-07-09 06:48:19 +00:00
|
|
|
infoHtml += "<ul class='two_btn_list'>";
|
2023-04-06 04:33:38 +00:00
|
|
|
for (const i of imgs) {
|
|
|
|
const parts = i.split("/");
|
2023-07-09 06:48:19 +00:00
|
|
|
infoHtml += `<li><a href="${i}" target="_blank">${parts[parts.length - 1]}</a> <button onclick="sendMapImg('${i}');">Set</button> <button onclick="deleteImg('${i}')">Delete</button></li>\n`;
|
2023-04-06 04:33:38 +00:00
|
|
|
}
|
2023-07-03 05:10:58 +00:00
|
|
|
infoHtml += "</ul>";
|
|
|
|
} else {
|
|
|
|
infoHtml += "<label>Maps couldn't be retrieved</label>";
|
2023-04-06 04:33:38 +00:00
|
|
|
}
|
2023-02-10 05:45:09 +00:00
|
|
|
adminZone.innerHTML = infoHtml;
|
2023-07-05 07:18:46 +00:00
|
|
|
|
2023-07-06 08:20:30 +00:00
|
|
|
let tokenListHTML = "<input id='token_img_upload' type='file'/><button onclick='uploadTokenImg()'>Upload Sprite</button><br/>";
|
2023-07-06 05:19:14 +00:00
|
|
|
if (tokenImgs.ok) {
|
2023-07-14 02:27:19 +00:00
|
|
|
const tokens = (await tokenImgs.json()).sort();
|
2023-07-09 06:48:19 +00:00
|
|
|
tokenListHTML += "<ul class='single_btn_list'>";
|
2023-07-06 05:19:14 +00:00
|
|
|
for (const t of tokens) {
|
|
|
|
const parts = t.split("/");
|
2023-07-09 06:48:19 +00:00
|
|
|
tokenListHTML += `<li><a href="${t}" target="_blank">${parts[parts.length - 1]}</a> <button onclick="deleteImg('${t}')">Delete</button></li>\n`
|
2023-07-06 05:19:14 +00:00
|
|
|
}
|
|
|
|
tokenListHTML += "</ul>";
|
2023-07-06 08:20:30 +00:00
|
|
|
fillSpriteDropdown(tokens);
|
2023-07-08 07:42:31 +00:00
|
|
|
|
2023-07-06 05:19:14 +00:00
|
|
|
} else {
|
|
|
|
tokenListHTML += "<label>Sprites couldn't be retrieved</label>"
|
|
|
|
}
|
|
|
|
|
|
|
|
spriteZone.innerHTML = tokenListHTML;
|
|
|
|
tokenWrapper.style.display = "inline";
|
|
|
|
|
2023-07-05 07:18:46 +00:00
|
|
|
} else {
|
2023-02-10 05:45:09 +00:00
|
|
|
console.log(res.status);
|
|
|
|
}
|
|
|
|
} catch (err) {
|
2023-02-26 05:43:38 +00:00
|
|
|
setErr(`${err.name}: ${err.message}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-06 08:20:30 +00:00
|
|
|
function fillSpriteDropdown(tokens) {
|
2023-07-14 02:27:19 +00:00
|
|
|
tokens = tokens.sort();
|
2023-07-06 08:20:30 +00:00
|
|
|
let options = "<option value=''>select</option>";
|
|
|
|
for (const t of tokens) {
|
|
|
|
const parts = t.split("/");
|
|
|
|
const o = `<option value="${t}">${parts[parts.length - 1]}</option>\n`;
|
|
|
|
options += o;
|
|
|
|
}
|
|
|
|
tokenSpriteDropdown.innerHTML = options;
|
|
|
|
}
|
|
|
|
|
|
|
|
function previewSprite(source) {
|
|
|
|
if (source) {
|
|
|
|
switch (source.id) {
|
|
|
|
case "token_combobox":
|
|
|
|
reinitializeSpritePreview();
|
|
|
|
break;
|
|
|
|
case "token_cx":
|
|
|
|
case "token_cy":
|
|
|
|
drawTokenOrigin();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
scaleSpritePreview(source);
|
|
|
|
console.log("default case");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function toggleAspectLock() {
|
|
|
|
if (tokenKeepAspect.checked) {
|
|
|
|
aspectLockLabel.innerHTML = "🔒"
|
|
|
|
} else {
|
|
|
|
aspectLockLabel.innerHTML = "🔓"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function scaleSpritePreview(source) {
|
|
|
|
if (mapImg && mapImg._image) {
|
2023-07-08 05:56:41 +00:00
|
|
|
const scaleFactor = mapImg._image.clientWidth / mapImg._image.naturalWidth;
|
|
|
|
const keepAspect = tokenAspect.checked;
|
|
|
|
const img = previewZone.children[0];
|
2023-07-17 03:29:53 +00:00
|
|
|
|
|
|
|
tokenHeight.value = Math.floor(Number(tokenHeight.value))
|
|
|
|
tokenWidth.value = Math.floor(Number(tokenWidth.value))
|
|
|
|
|
|
|
|
|
2023-07-08 05:56:41 +00:00
|
|
|
if (img) {
|
|
|
|
if (!keepAspect || !source) {
|
|
|
|
img.width = Number(tokenWidth.value) * scaleFactor;
|
|
|
|
img.height = Number(tokenHeight.value) * scaleFactor;
|
|
|
|
} else {
|
2023-07-06 08:20:30 +00:00
|
|
|
|
2023-07-08 05:56:41 +00:00
|
|
|
const currentAspect = img.width/img.height;
|
|
|
|
switch (source.id) {
|
|
|
|
case "token_width":
|
|
|
|
img.width = Number(tokenWidth.value) * scaleFactor;
|
|
|
|
img.height = (img.clientWidth / img.naturalWidth) * img.naturalHeight;
|
2023-07-17 03:29:53 +00:00
|
|
|
tokenHeight.value = Math.floor(Number(tokenWidth.value)/currentAspect);
|
2023-07-08 05:56:41 +00:00
|
|
|
break;
|
|
|
|
case "token_height":
|
|
|
|
img.height = Number(tokenHeight.value) * scaleFactor;
|
|
|
|
img.width = (img.clientHeight / img.naturalHeight) * img.naturalWidth;
|
2023-07-17 03:29:53 +00:00
|
|
|
tokenWidth.value = Math.floor(currentAspect * Number(tokenHeight.value));
|
2023-07-08 05:56:41 +00:00
|
|
|
break;
|
|
|
|
}
|
2023-07-06 08:20:30 +00:00
|
|
|
}
|
2023-07-18 04:26:31 +00:00
|
|
|
if (!tokenCX.value || source) {
|
|
|
|
tokenCX.value = Number(tokenWidth.value)/2;
|
|
|
|
} if (!tokenCY.value || source) {
|
|
|
|
tokenCY.value = Number(tokenHeight.value)/2;
|
|
|
|
}
|
2023-07-08 05:56:41 +00:00
|
|
|
drawTokenOrigin();
|
2023-07-06 08:20:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-12 05:57:06 +00:00
|
|
|
|
2023-07-06 08:20:30 +00:00
|
|
|
function drawTokenOrigin() {
|
2023-07-09 06:48:19 +00:00
|
|
|
if (tokenSpriteDropdown.selectedIndex >= 0) {
|
2023-07-17 03:29:53 +00:00
|
|
|
|
|
|
|
tokenCX.value = Math.floor(Number(tokenCX.value))
|
|
|
|
tokenCY.value = Math.floor(Number(tokenCY.value))
|
|
|
|
|
2023-07-06 08:20:30 +00:00
|
|
|
const img = previewZone.children[0];
|
|
|
|
const x = Number(tokenWidth.value) / Number(tokenCX.value);
|
|
|
|
const y = Number(tokenHeight.value) / Number(tokenCY.value);
|
2023-07-08 05:56:41 +00:00
|
|
|
|
2023-07-06 08:20:30 +00:00
|
|
|
const origin = {x: img.width/x, y: img.height/y};
|
|
|
|
const originImg = document.createElement("img");
|
2023-07-08 05:56:41 +00:00
|
|
|
|
2023-07-06 08:20:30 +00:00
|
|
|
originImg.src="/table/origin.png";
|
|
|
|
originImg.style.position = "absolute";
|
|
|
|
originImg.style.left = (origin.x - 2) + "px";
|
|
|
|
originImg.style.top = (origin.y - 2) + "px";
|
2023-07-08 05:56:41 +00:00
|
|
|
|
2023-07-06 08:20:30 +00:00
|
|
|
if (previewZone.children.length > 1) {
|
|
|
|
previewZone.replaceChild(originImg, previewZone.children[1]);
|
|
|
|
} else {
|
|
|
|
previewZone.appendChild(originImg);
|
|
|
|
}
|
2023-07-09 06:48:19 +00:00
|
|
|
}
|
2023-07-06 08:20:30 +00:00
|
|
|
}
|
|
|
|
|
2023-07-18 04:26:31 +00:00
|
|
|
function reinitializeSpritePreview(existing = false) {
|
2023-07-06 08:20:30 +00:00
|
|
|
const img = document.createElement("img");
|
|
|
|
img.src = tokenSpriteDropdown[tokenSpriteDropdown.selectedIndex].value;
|
2023-07-10 05:41:30 +00:00
|
|
|
|
2023-07-18 04:26:31 +00:00
|
|
|
if (!existing) {
|
|
|
|
const tokenNameParts = tokenSpriteDropdown[tokenSpriteDropdown.selectedIndex].text.split(".");
|
|
|
|
tokenNameParts.pop();
|
|
|
|
tokenName.value = tokenNameParts.join(".");
|
|
|
|
}
|
2023-07-10 05:41:30 +00:00
|
|
|
|
2023-07-06 08:20:30 +00:00
|
|
|
img.onload = () => {
|
|
|
|
const w = img.naturalWidth;
|
|
|
|
const h = img.naturalHeight;
|
|
|
|
|
2023-07-18 04:26:31 +00:00
|
|
|
if (!existing) {
|
2023-07-06 08:20:30 +00:00
|
|
|
tokenWidth.value = w;
|
|
|
|
tokenHeight.value = h;
|
2023-07-18 04:26:31 +00:00
|
|
|
tokenCX.value = ""
|
|
|
|
tokenCY.value = ""
|
|
|
|
}
|
2023-07-06 08:20:30 +00:00
|
|
|
scaleSpritePreview();
|
|
|
|
}
|
2023-07-10 05:41:30 +00:00
|
|
|
|
2023-07-09 06:48:19 +00:00
|
|
|
previewZone.innerHTML = "";
|
|
|
|
previewZone.appendChild(img);
|
2023-07-06 08:20:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function createToken() {
|
|
|
|
const w = Number(tokenWidth.value);
|
|
|
|
const h = Number(tokenHeight.value);
|
|
|
|
const oX = Number(tokenCX.value);
|
|
|
|
const oY = Number(tokenCY.value);
|
|
|
|
const img = tokenSpriteDropdown[tokenSpriteDropdown.selectedIndex].value;
|
|
|
|
const name = tokenName.value;
|
|
|
|
|
|
|
|
if (!isNaN(w) && !isNaN(h) && !isNaN(oX) && !isNaN(oY) && img && name) {
|
2023-07-14 23:04:02 +00:00
|
|
|
// send it on the websocket and wait for it to come back
|
|
|
|
const [x, y] = [0, 0];
|
2023-07-08 07:42:31 +00:00
|
|
|
sendToken({
|
|
|
|
w: w,
|
|
|
|
h: h,
|
|
|
|
ox:oX,
|
|
|
|
oy:oY,
|
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
sprite: img,
|
|
|
|
name: name,
|
|
|
|
active: false}
|
|
|
|
);
|
2023-07-14 23:04:02 +00:00
|
|
|
setTokenCreateFormVisible(false);
|
2023-07-08 07:42:31 +00:00
|
|
|
return;
|
2023-07-06 08:20:30 +00:00
|
|
|
}
|
2023-07-08 07:42:31 +00:00
|
|
|
setErr("All token fields are required");
|
2023-07-06 08:20:30 +00:00
|
|
|
}
|
|
|
|
|
2023-07-09 06:48:19 +00:00
|
|
|
function destroyToken(id) {
|
|
|
|
const existing = tokens.find(t=>t.t.id == id);
|
|
|
|
if (existing) {
|
|
|
|
const self = Object.assign({}, existing.t);
|
|
|
|
self.active = false;
|
|
|
|
self.x = null;
|
|
|
|
self.y = null;
|
|
|
|
sendToken(self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function previewExistingToken(id) {
|
|
|
|
const existing = tokens.find(t=>t.t.id == id);
|
|
|
|
if (existing) {
|
|
|
|
tokenWidth.value = existing.t.w;
|
|
|
|
tokenHeight.value = existing.t.h;
|
|
|
|
tokenCX.value = existing.t.oX;
|
|
|
|
tokenCY.value = existing.t.oY;
|
|
|
|
tokenName.value = existing.t.name;
|
|
|
|
for (let i = 0; i < tokenSpriteDropdown.options.length; i++) {
|
|
|
|
if (tokenSpriteDropdown.options[i].value == existing.t.sprite) {
|
|
|
|
tokenSpriteDropdown.selectedIndex = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-07-18 04:26:31 +00:00
|
|
|
reinitializeSpritePreview(true);
|
2023-07-09 06:48:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-17 03:29:53 +00:00
|
|
|
function copyToken(id) {
|
|
|
|
setTokenCreateFormVisible(true);
|
|
|
|
previewExistingToken(id);
|
|
|
|
}
|
|
|
|
|
2023-07-09 06:48:19 +00:00
|
|
|
function renderTokenMasterList() {
|
|
|
|
if (tokenZone) {
|
2023-07-17 03:29:53 +00:00
|
|
|
let tokenMasterListHTML = "";
|
|
|
|
const scroll = tokenZone.scrollTop;
|
2023-07-09 06:48:19 +00:00
|
|
|
for (const t of tokens) {
|
2023-07-17 03:29:53 +00:00
|
|
|
tokenMasterListHTML += `<li><a href="#" onclick="previewExistingToken('${t.t.id}');return false">${t.t.name}</a><button onclick="copyToken('${t.t.id}')">Copy</button><button onclick="destroyToken('${t.t.id}')">Destroy</button></li>\n`;
|
2023-07-09 06:48:19 +00:00
|
|
|
}
|
|
|
|
tokenZone.innerHTML = tokenMasterListHTML;
|
2023-07-17 03:29:53 +00:00
|
|
|
tokenZone.scrollTop = scroll;
|
2023-07-09 06:48:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 04:24:40 +00:00
|
|
|
function publishAuxMsg() {
|
|
|
|
const txtArea = document.getElementById("auxMsgZone");
|
|
|
|
if (txtArea != null) {
|
|
|
|
publish({auxMsg: txtArea.value, auth: adminToken.access_token});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-06 04:33:38 +00:00
|
|
|
function sendMapImg(url) {
|
|
|
|
publish({mapImg: url, auth: adminToken.access_token});
|
|
|
|
}
|
|
|
|
|
2023-07-08 05:56:41 +00:00
|
|
|
function sendToken(t) {
|
|
|
|
publish({token: t, auth: adminToken.access_token});
|
|
|
|
}
|
|
|
|
|
2023-04-04 05:15:17 +00:00
|
|
|
async function uploadMapImg() {
|
|
|
|
try {
|
|
|
|
var input = document.getElementById("map_img_upload");
|
|
|
|
var data = new FormData();
|
|
|
|
data.append('file', input.files[0]);
|
|
|
|
data.append('name', tableKey.name);
|
|
|
|
data.append('passcode', tableKey.passcode);
|
|
|
|
const headers = new Headers();
|
|
|
|
headers.set('Authorization', 'Bearer ' + adminToken.access_token);
|
|
|
|
res = await fetch(`/admin/api/upload/${tableKey.name}/map/`, {
|
|
|
|
headers: headers,
|
|
|
|
method: "POST",
|
|
|
|
body: data,
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
2023-07-04 07:08:01 +00:00
|
|
|
// refresh so we can see the new entry in the list
|
2023-07-08 07:42:31 +00:00
|
|
|
rebindUi(tableKey.name, tableKey.passcode);
|
2023-04-04 05:15:17 +00:00
|
|
|
} else {
|
|
|
|
throw new Error("Something went wrong uploading the map BG...");
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
setErr(`${err.name}: ${err.message}`);
|
|
|
|
}
|
|
|
|
}
|
2023-07-06 05:19:14 +00:00
|
|
|
async function uploadTokenImg() {
|
|
|
|
try {
|
|
|
|
var input = document.getElementById("token_img_upload");
|
|
|
|
var data = new FormData();
|
|
|
|
data.append('file', input.files[0]);
|
|
|
|
data.append('name', tableKey.name);
|
|
|
|
data.append('passcode', tableKey.passcode);
|
|
|
|
const headers = new Headers();
|
|
|
|
headers.set('Authorization', 'Bearer ' + adminToken.access_token);
|
|
|
|
res = await fetch(`/admin/api/upload/${tableKey.name}/token/`, {
|
|
|
|
headers: headers,
|
|
|
|
method: "POST",
|
|
|
|
body: data,
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
|
|
|
// refresh so we can see the new entry in the list
|
2023-07-08 07:42:31 +00:00
|
|
|
rebindUi(tableKey.name, tableKey.passcode);
|
2023-07-06 05:19:14 +00:00
|
|
|
} else {
|
|
|
|
throw new Error("Something went wrong uploading the token sprite...");
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
setErr(`${err.name}: ${err.message}`);
|
|
|
|
}
|
|
|
|
}
|
2023-07-05 05:54:43 +00:00
|
|
|
async function deleteImg(url) {
|
2023-07-04 07:08:01 +00:00
|
|
|
try {
|
2023-07-05 05:54:43 +00:00
|
|
|
if (url.startsWith("/uploads/")) {
|
|
|
|
const parts = url.split("/");
|
|
|
|
parts.shift();
|
|
|
|
const table = parts[1];
|
|
|
|
const imgType = parts[2]
|
|
|
|
const file = parts[3];
|
|
|
|
|
|
|
|
const headers = new Headers();
|
|
|
|
headers.set('Authorization', 'Bearer ' + adminToken.access_token);
|
|
|
|
const res = await fetch(`/admin/api/upload/${table}/${imgType}/${file}?passcode=${tableKey.passcode}`, {
|
|
|
|
headers: headers,
|
|
|
|
method: "DELETE",
|
|
|
|
});
|
|
|
|
|
|
|
|
if (res.ok) {
|
|
|
|
// refresh UI
|
2023-07-08 07:42:31 +00:00
|
|
|
rebindUi(tableKey.name, tableKey.passcode);
|
2023-07-05 05:54:43 +00:00
|
|
|
} else {
|
|
|
|
throw new Error ("Something went wrong deleting the image...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
setErr(`${err.name}: ${err.message}`);
|
2023-07-04 07:08:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-26 05:43:38 +00:00
|
|
|
async function destroyTable() {
|
|
|
|
try {
|
2023-07-03 05:10:58 +00:00
|
|
|
if (confirm("You really want to destroy this table?")) {
|
2023-02-26 05:43:38 +00:00
|
|
|
const headers = new Headers();
|
|
|
|
headers.set('Authorization', 'Bearer ' + adminToken.access_token);
|
|
|
|
const res = await fetch(`/admin/api/table/${tableKey.name}`, {
|
|
|
|
method: 'DELETE',
|
|
|
|
headers: headers,
|
|
|
|
body: JSON.stringify(tableKey)
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
|
|
|
conn.close(1000);
|
2023-07-06 04:27:38 +00:00
|
|
|
initializeMap("");
|
2023-02-26 05:43:38 +00:00
|
|
|
getTables();
|
2023-07-06 04:27:38 +00:00
|
|
|
|
2023-02-26 05:43:38 +00:00
|
|
|
} else {
|
|
|
|
setErr(await res.json());
|
|
|
|
}
|
2023-07-03 05:10:58 +00:00
|
|
|
}
|
2023-02-26 05:43:38 +00:00
|
|
|
} catch (err) {
|
|
|
|
setErr(`${err.name}: ${err.message}`);
|
2023-02-10 05:45:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-27 04:44:03 +00:00
|
|
|
async function getTables() {
|
|
|
|
try {
|
|
|
|
const headers = new Headers();
|
2023-01-28 07:28:15 +00:00
|
|
|
headers.set('Authorization', 'Bearer ' + adminToken.access_token);
|
2023-01-27 04:44:03 +00:00
|
|
|
const res = await fetch('/admin/api/table/', {
|
|
|
|
method: 'GET',
|
|
|
|
headers: headers
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
2023-01-28 07:28:15 +00:00
|
|
|
const tableList = await res.json();
|
2023-07-14 02:27:19 +00:00
|
|
|
tableList.sort((a,b)=>{
|
|
|
|
if (a.name < b.name) {
|
|
|
|
return -1;
|
|
|
|
} else if (a.name > b.name) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
});
|
2023-01-28 07:28:15 +00:00
|
|
|
let tableListHTML = "<ul>\n";
|
|
|
|
for (const t of tableList) {
|
2023-07-08 07:42:31 +00:00
|
|
|
tableListHTML += `<li><a href="#" onclick="rebindUi('${t.name}','${t.passcode}');return false;">${t.name}</a></li>\n`
|
2023-01-28 07:28:15 +00:00
|
|
|
}
|
|
|
|
tableListHTML += "</ul>"
|
|
|
|
adminZone.innerHTML = tableListHTML;
|
2023-07-06 05:19:14 +00:00
|
|
|
tokenWrapper.style.display = "none";
|
2023-01-27 04:44:03 +00:00
|
|
|
} else {
|
2023-07-17 03:29:53 +00:00
|
|
|
// fail silently
|
2023-01-27 04:44:03 +00:00
|
|
|
}
|
|
|
|
} catch {
|
2023-07-17 03:29:53 +00:00
|
|
|
// fail silently
|
2023-01-27 04:44:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-26 05:57:31 +00:00
|
|
|
async function doLogin() {
|
2023-02-19 03:37:50 +00:00
|
|
|
const adminUsrInput = document.getElementById("name_entry");
|
2023-01-26 05:57:31 +00:00
|
|
|
const adminPassInput = document.getElementById("input_admin_pass");
|
|
|
|
|
|
|
|
if (adminUsrInput && adminPassInput) {
|
|
|
|
adminToken = await getAdminToken(adminUsrInput.value, adminPassInput.value);
|
|
|
|
if (adminToken) {
|
2023-01-27 04:44:03 +00:00
|
|
|
getTables();
|
2023-07-06 08:20:30 +00:00
|
|
|
adminWrapper.style.display="inline";
|
2023-02-22 05:27:54 +00:00
|
|
|
adminZone.style.display = "block";
|
2023-07-09 06:48:19 +00:00
|
|
|
closeErr();
|
2023-07-10 05:41:30 +00:00
|
|
|
replaceAdminModal();
|
2023-01-26 05:57:31 +00:00
|
|
|
} else {
|
2023-01-28 07:28:15 +00:00
|
|
|
setErr("Incorrect credentials");
|
2023-01-26 05:57:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-10 05:41:30 +00:00
|
|
|
function replaceAdminModal() {
|
|
|
|
const adminModal = document.getElementById("admin_modal");
|
|
|
|
if (adminModal) {
|
|
|
|
adminModal.innerHTML = "<a href='./'>Logout</a>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-26 05:57:31 +00:00
|
|
|
async function getAdminToken(user, pass) {
|
|
|
|
const headers = new Headers();
|
|
|
|
headers.set('Authorization', 'Basic ' + btoa(user + ":" + pass));
|
|
|
|
try {
|
|
|
|
const res = await fetch('/admin/api/auth/', {
|
|
|
|
method: 'POST',
|
|
|
|
headers: headers
|
|
|
|
});
|
|
|
|
|
|
|
|
if (res.ok) {
|
|
|
|
return await res.json();
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
} catch (err) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2023-01-28 07:28:15 +00:00
|
|
|
|
|
|
|
function setTableCreateFormVisible(v) {
|
|
|
|
if (createTableForm) {
|
|
|
|
createTableForm.style.display = v ? "block" : "none";
|
|
|
|
}
|
|
|
|
if (!v) {
|
|
|
|
if (newTableName) {
|
|
|
|
newTableName.value = "";
|
|
|
|
}
|
|
|
|
if (newTablePass) {
|
|
|
|
newTablePass.value = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-06 05:19:14 +00:00
|
|
|
function setTokenCreateFormVisible(v) {
|
2023-07-09 06:48:19 +00:00
|
|
|
if (createTokenForm && tokenZone) {
|
|
|
|
if (v) {
|
|
|
|
// clear the form when displaying because we may have values from a preview of an existing token
|
|
|
|
tokenWidth.value = "";
|
|
|
|
tokenHeight.value = "";
|
|
|
|
tokenCX.value = "";
|
|
|
|
tokenCY.value = "";
|
|
|
|
tokenName.value = "";
|
|
|
|
tokenSpriteDropdown.selectedIndex = 0;
|
|
|
|
}
|
2023-07-06 05:19:14 +00:00
|
|
|
createTokenForm.style.display = v ? "block" : "none";
|
2023-07-17 03:29:53 +00:00
|
|
|
tokenZone.style.display = v ? "none" : "block";
|
2023-07-18 04:26:31 +00:00
|
|
|
previewZone.innerHTML = "";
|
2023-07-06 05:19:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-28 07:28:15 +00:00
|
|
|
async function createTable() {
|
|
|
|
const headers = new Headers();
|
|
|
|
headers.set('Authorization', 'Bearer ' + adminToken.access_token);
|
|
|
|
|
|
|
|
const formData = new FormData();
|
|
|
|
formData.set("name", newTableName.value);
|
|
|
|
formData.set("passcode", newTablePass.value);
|
|
|
|
|
|
|
|
let bodyStr = "{";
|
|
|
|
for (const pair of formData.entries()) {
|
|
|
|
bodyStr += `"${pair[0]}": "${pair[1]}",`;
|
|
|
|
}
|
|
|
|
bodyStr = bodyStr.slice(0, -1);
|
|
|
|
bodyStr += "}";
|
|
|
|
const res = await fetch('/admin/api/table/', {
|
|
|
|
method: 'POST',
|
|
|
|
headers: headers,
|
|
|
|
body: bodyStr,
|
|
|
|
});
|
|
|
|
if (res.ok) {
|
|
|
|
getTables();
|
|
|
|
setTableCreateFormVisible(false);
|
2023-07-08 05:56:41 +00:00
|
|
|
} else if (res.status === 422) {
|
|
|
|
setErr('Table name and passcode must be only alphanumeric and underscores');
|
|
|
|
} else {
|
|
|
|
setErr('Error creating table');
|
2023-01-28 07:28:15 +00:00
|
|
|
}
|
|
|
|
}
|