diff --git a/static/admin.js b/static/admin.js index 86f675a..dd32617 100644 --- a/static/admin.js +++ b/static/admin.js @@ -1,28 +1,10 @@ let adminToken = null; -const adminWrapper = document.getElementById("adminWrapper"); -const adminZone = document.getElementById("adminZone"); -const spriteZone = document.getElementById("spriteZone"); -const createTableForm = document.getElementById("createTableForm"); -const createTokenForm = document.getElementById("createTokenForm"); -const tokenWrapper = document.getElementById("adminWrapper_tokens"); -const newTableName = document.getElementById("newTableName"); -const newTablePass = document.getElementById("newTablePass"); -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"); -const tokenZone = document.getElementById("tokenZone"); -async function rebindUi(name, pass) { +async function loadAdmin(name, pass) { try { const headers = new Headers(); headers.set('Authorization', 'Bearer ' + adminToken.access_token); - const res = await fetch(`/admin/api/table/${name}?passcode=${pass}`, { + const tableData = await fetch(`/admin/api/table/${name}?passcode=${pass}`, { method: 'GET', headers: headers, }); @@ -37,71 +19,70 @@ async function rebindUi(name, pass) { headers: headers, }); - let infoHtml = "" - if (res.ok) { - document.getElementById("input_table_name").value = name; - document.getElementById("input_table_pass").value = pass; + let mgmtHTML = "" + if (tableData.ok) { + $("input_table_name").value = name; + $("input_table_pass").value = pass; dial(); - const table = await res.json() - infoHtml = "← table list
"; - infoHtml += `
` - infoHtml += "
"; - infoHtml += "
" - if (mapImgs.ok) { - infoHtml += ""; - const imgs = (await mapImgs.json()).sort(); - infoHtml += ""; - } else { - infoHtml += ""; - } - adminZone.innerHTML = infoHtml; - let tokenListHTML = "
"; - if (tokenImgs.ok) { - const tokens = (await tokenImgs.json()).sort(); - tokenListHTML += ""; - fillSpriteDropdown(tokens); + const table = await tableData.json() + + mgmtHTML = `← table list
\n` + + `
\n` + + `
\n` + + `
\n` + + if (mapImgs.ok) { + const imgs = (await mapImgs.json()).sort(); + mgmtHTML = imgs.reduce((s, i) => { + const parts = i.split("/"); + return s + `
  • ${parts[parts.length - 1]}
  • \n`; + }, mgmtHTML + ""; } else { - tokenListHTML += "" + mgmtHTML += ""; + } + $("table_management").innerHTML = mgmtHTML; + + let spriteListHTML = `
    `; + + if (tokenImgs.ok) { + const sprites = (await tokenImgs.json()).sort(); + spriteListHTML = sprites.reduce((s, t) => { + const parts = t.split("/"); + return s + `
  • ${parts[parts.length - 1]}
  • \n`; + }, spriteListHTML + ""; + fillSpriteDropdown(sprites); + + } else { + spriteListHTML += "" } - spriteZone.innerHTML = tokenListHTML; - tokenWrapper.style.display = "inline"; + $("sprite_zone").innerHTML = spriteListHTML; + $("token_management").style.display = "inline"; } else { console.log(res.status); } } catch (err) { + console.dir(err) setErr(`${err.name}: ${err.message}`); } } -function fillSpriteDropdown(tokens) { - tokens = tokens.sort(); +function fillSpriteDropdown(sprites) { + const dropdown = $("sprite_dropdown"); let options = ""; - for (const t of tokens) { + dropdown.innerHTML = sprites.reduce((s, t) => { const parts = t.split("/"); - const o = `\n`; - options += o; - } - tokenSpriteDropdown.innerHTML = options; + return s + `\n`; + }, ""); } function previewSprite(source) { if (source) { switch (source.id) { - case "token_combobox": + case "sprite_dropdown": reinitializeSpritePreview(); break; case "token_cx": @@ -116,18 +97,24 @@ function previewSprite(source) { } function toggleAspectLock() { - if (tokenKeepAspect.checked) { - aspectLockLabel.innerHTML = "🔒" - } else { - aspectLockLabel.innerHTML = "🔓" - } + try { + const locked = $("token_aspect_lock").checked; + $("aspect_lock_label").innerHTML = locked ? "🔒" : "🔓" + } catch {} } function scaleSpritePreview(source) { - if (mapImg && mapImg._image) { + const tokenHeight = $("token_height"); + const tokenWidth = $("token_width"); + const tokenCX = $("token_cx"); + const tokenCY = $("token_cy"); + const tokenAspect = $("token_aspect_lock"); + const preview = $("token_admin_preview"); + + if (mapImg && mapImg._image && tokenHeight && tokenWidth && tokenCX && tokenCY && tokenAspect && preview) { const scaleFactor = mapImg._image.clientWidth / mapImg._image.naturalWidth; const keepAspect = tokenAspect.checked; - const img = previewZone.children[0]; + const img = preview.children[0]; tokenHeight.value = Math.floor(Number(tokenHeight.value)) tokenWidth.value = Math.floor(Number(tokenWidth.value)) @@ -165,12 +152,20 @@ function scaleSpritePreview(source) { function drawTokenOrigin() { - if (tokenSpriteDropdown.selectedIndex >= 0) { + const dropdown = $("sprite_dropdown"); + const tokenWidth = $("token_width"); + const tokenHeight = $("token_height"); + const tokenCX = $("token_cx"); + const tokenCY = $("token_cy"); + const preview = $("token_admin_preview"); + + if (dropdown && tokenWidth && tokenHeight && tokenCX && tokenCY && preview + && dropdown.selectedIndex >= 0) { tokenCX.value = Math.floor(Number(tokenCX.value)) tokenCY.value = Math.floor(Number(tokenCY.value)) - const img = previewZone.children[0]; + const img = preview.children[0]; const x = Number(tokenWidth.value) / Number(tokenCX.value); const y = Number(tokenHeight.value) / Number(tokenCY.value); @@ -182,67 +177,82 @@ function drawTokenOrigin() { originImg.style.left = (origin.x - 2) + "px"; originImg.style.top = (origin.y - 2) + "px"; - if (previewZone.children.length > 1) { - previewZone.replaceChild(originImg, previewZone.children[1]); + if (preview.children.length > 1) { + preview.replaceChild(originImg, preview.children[1]); } else { - previewZone.appendChild(originImg); + preview.appendChild(originImg); } } } function reinitializeSpritePreview(existing = false) { - const img = document.createElement("img"); - img.src = tokenSpriteDropdown[tokenSpriteDropdown.selectedIndex].value; + + const dropdown = $("sprite_dropdown"); + const tokenName = $("token_name"); + const tokenWidth = $("token_width"); + const tokenHeight = $("token_height"); + const tokenCX = $("token_cx"); + const tokenCY = $("token_cy"); + const preview = $("token_admin_preview"); - if (!existing) { - const tokenNameParts = tokenSpriteDropdown[tokenSpriteDropdown.selectedIndex].text.split("."); - tokenNameParts.pop(); - tokenName.value = tokenNameParts.join("."); - } + if (dropdown && tokenName && tokenWidth && tokenHeight && tokenCX && tokenCY && preview) { + + const img = document.createElement("img"); + img.src = dropdown[dropdown.selectedIndex].value; - img.onload = () => { - const w = img.naturalWidth; - const h = img.naturalHeight; - if (!existing) { - tokenWidth.value = w; - tokenHeight.value = h; - tokenCX.value = "" - tokenCY.value = "" + const tokenNameParts = dropdown[dropdown.selectedIndex].text.split("."); + tokenNameParts.pop(); + tokenName.value = tokenNameParts.join("."); } - scaleSpritePreview(); - } - previewZone.innerHTML = ""; - previewZone.appendChild(img); + img.onload = () => { + const w = img.naturalWidth; + const h = img.naturalHeight; + + if (!existing) { + tokenWidth.value = w; + tokenHeight.value = h; + tokenCX.value = ""; + tokenCY.value = ""; + } + scaleSpritePreview(); + } + + preview.innerHTML = ""; + preview.appendChild(img); + } } 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; + const dropdown = $("sprite_dropdown"); + try { + const w = Number($("token_width").value); + const h = Number($("token_height").value); + const oX = Number($("token_cx").value); + const oY = Number($("token_cy").value); + const img = dropdown[dropdown.selectedIndex].value; + const name = $("token_name").value; - if (!isNaN(w) && !isNaN(h) && !isNaN(oX) && !isNaN(oY) && img && name) { - // send it on the websocket and wait for it to come back - const [x, y] = [0, 0]; - sendToken({ - w: w, - h: h, - ox:oX, - oy:oY, - x: x, - y: y, - sprite: img, - name: name, - active: false} - ); - setTokenCreateFormVisible(false); - return; - } - setErr("All token fields are required"); + if (!isNaN(w) && !isNaN(h) && !isNaN(oX) && !isNaN(oY) && img && name) { + // send it on the websocket and wait for it to come back + const [x, y] = [0, 0]; + sendToken({ + w: w, + h: h, + ox:oX, + oy:oY, + x: x, + y: y, + sprite: img, + name: name, + active: false + }); + setTokenCreateFormVisible(false); + return; + } + setErr("All token fields are required"); + } catch {} } function destroyToken(id) { @@ -257,21 +267,27 @@ function destroyToken(id) { } 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; + try { + const existing = tokens.find(t=>t.t.id == id); + const dropdown = $("sprite_dropdown"); + if (existing) { + $("token_width").value = existing.t.w; + $("token_height").value = existing.t.h; + $("token_cx").value = existing.t.oX; + $("token_cy").value = existing.t.oY; + $("token_name").value = existing.t.name; + for (let i = 0; i < dropdown.options.length; i++ ) { + if (dropdown.options[i].value === existing.t.sprite) { + dropdown.selectedIndex = i; + break; + } } + reinitializeSpritePreview(true); } - reinitializeSpritePreview(true); + } catch (err) { + console.log(err); } + } function copyToken(id) { @@ -280,20 +296,19 @@ function copyToken(id) { } function renderTokenMasterList() { - if (tokenZone) { - let tokenMasterListHTML = ""; - const scroll = tokenZone.scrollTop; - for (const t of tokens) { - tokenMasterListHTML += `
  • ${t.t.name}
  • \n`; - } - tokenZone.innerHTML = tokenMasterListHTML; - tokenZone.scrollTop = scroll; + const tokenList = $("token_list"); + if (tokenList) { + const scroll = tokenList.scrollTop; + tokenList.innerHTML = tokens.reduce((s, t) => { + return s + `
  • ${t.t.name}
  • \n`; + }, ""); + tokenList.scrollTop = scroll; } } function publishAuxMsg() { - const txtArea = document.getElementById("auxMsgZone"); - if (txtArea != null) { + const txtArea = $("aux_msg_input"); + if (txtArea) { publish({auxMsg: txtArea.value, auth: adminToken.access_token}); } } @@ -306,54 +321,30 @@ function sendToken(t) { publish({token: t, auth: adminToken.access_token}); } -async function uploadMapImg() { +async function uploadImg(imgType) { try { - var input = document.getElementById("map_img_upload"); + var input = $(`${imgType}_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/`, { + res = await fetch(`/admin/api/upload/${tableKey.name}/${imgType}/`, { headers: headers, method: "POST", body: data, }); if (res.ok) { - // refresh so we can see the new entry in the list - rebindUi(tableKey.name, tableKey.passcode); + loadAdmin(tableKey.name, tableKey.passcode); } else { - throw new Error("Something went wrong uploading the map BG..."); - } - } catch (err) { - setErr(`${err.name}: ${err.message}`); - } -} -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 - rebindUi(tableKey.name, tableKey.passcode); - } else { - throw new Error("Something went wrong uploading the token sprite..."); + throw new Error("Something went wrong uploading the ${imgType} image..."); } } catch (err) { setErr(`${err.name}: ${err.message}`); } } + async function deleteImg(url) { try { if (url.startsWith("/uploads/")) { @@ -371,8 +362,7 @@ async function deleteImg(url) { }); if (res.ok) { - // refresh UI - rebindUi(tableKey.name, tableKey.passcode); + loadAdmin(tableKey.name, tableKey.passcode); } else { throw new Error ("Something went wrong deleting the image..."); } @@ -393,12 +383,10 @@ async function destroyTable() { body: JSON.stringify(tableKey) }); if (res.ok) { - conn.close(1000); - initializeMap(""); + leave(); getTables(); - } else { - setErr(await res.json()); + setErr("Error destroying table"); } } } catch (err) { @@ -406,49 +394,58 @@ async function destroyTable() { } } +function sortByName(a, b) { + return (a.name < b.name) + ? -1 + : ((a.name > b.name) + ? 1 + : 0) +} + async function getTables() { try { + const headers = new Headers(); headers.set('Authorization', 'Bearer ' + adminToken.access_token); const res = await fetch('/admin/api/table/', { method: 'GET', headers: headers }); + if (res.ok) { - const tableList = await res.json(); - tableList.sort((a,b)=>{ - if (a.name < b.name) { - return -1; - } else if (a.name > b.name) { - return 1; - } - return 0; - }); - let tableListHTML = "" - adminZone.innerHTML = tableListHTML; - tokenWrapper.style.display = "none"; + tblMgmt.style.display = "none"; + } else { // fail silently } + } catch { // fail silently } } async function doLogin() { - const adminUsrInput = document.getElementById("name_entry"); - const adminPassInput = document.getElementById("input_admin_pass"); + const adminUsrInput = $("name_entry"); + const adminPassInput = $("input_admin_pass"); + const adminUI = $("admin_ui"); + const tblMgmt = $("table_management"); + const tokenMgmt = $("token_management"); - if (adminUsrInput && adminPassInput) { + if (adminUsrInput && adminPassInput && adminUI && tblMgmt && tokenMgmt) { adminToken = await getAdminToken(adminUsrInput.value, adminPassInput.value); if (adminToken) { getTables(); - adminWrapper.style.display="inline"; - adminZone.style.display = "block"; + + tblMgmt.style.display = "block"; + tokenMgmt.style.display = "none"; + adminUI.style.display="inline"; closeErr(); replaceAdminModal(); } else { @@ -458,7 +455,7 @@ async function doLogin() { } function replaceAdminModal() { - const adminModal = document.getElementById("admin_modal"); + const adminModal = $("admin_modal"); if (adminModal) { adminModal.innerHTML = "Logout"; } @@ -483,61 +480,66 @@ async function getAdminToken(user, pass) { } function setTableCreateFormVisible(v) { - if (createTableForm) { - createTableForm.style.display = v ? "block" : "none"; - } - if (!v) { - if (newTableName) { - newTableName.value = ""; + try { + $("table_creation_form").style.display = v ? "block" : "none"; + if (!v) { + $("new_table_name").value = ""; + $("new_table_pass").value = ""; } - if (newTablePass) { - newTablePass.value = ""; - } - } + } catch {} } function setTokenCreateFormVisible(v) { - if (createTokenForm && tokenZone) { + try { 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; + $("token_width").value = ""; + $("token_height").value = ""; + $("token_cx").value = ""; + $("token_cy").value = ""; + $("token_name").value = ""; + $("sprite_dropdown").selectedIndex = 0; } - createTokenForm.style.display = v ? "block" : "none"; - tokenZone.style.display = v ? "none" : "block"; - previewZone.innerHTML = ""; - } + $("token_creation_form").style.display = v ? "block" : "none"; + $("token_list").style.display = v ? "none" : "block"; + $("token_admin_preview").innerHTML = ""; + } catch {} } async function createTable() { - const headers = new Headers(); - headers.set('Authorization', 'Bearer ' + adminToken.access_token); + const newTableName = $("new_table_name"); + const newTablePass = $("new_table_pass"); + + if (newTableName && newTablePass) { + 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); - } else if (res.status === 422) { - setErr('Table name and passcode must be only alphanumeric and underscores'); - } else { - setErr('Error creating table'); + 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 += "}"; + + try { + const res = await fetch('/admin/api/table/', { + method: 'POST', + headers: headers, + body: bodyStr, + }); + if (res.ok) { + getTables(); + setTableCreateFormVisible(false); + } else if (res.status === 422) { + setErr("Table name and passcode must be only alphanumeric and underscores"); + } else { + setErr("Error creating table"); + } + } catch { + setErr("Error creating table"); + } } } \ No newline at end of file diff --git a/static/dice.js b/static/dice.js index 56be65e..fc8cca5 100644 --- a/static/dice.js +++ b/static/dice.js @@ -1,10 +1,10 @@ function rollDice() { - const name = document.getElementById("name_entry"); - const numDice = document.getElementById("num_dice"); - const faces = document.getElementById("dice_faces"); - const note = document.getElementById("dice_note"); + const name = $("name_entry"); + const numDice = $("num_dice"); + const faces = $("dice_faces"); + const note = $("dice_note"); - if (conn == null || table == null) { + if (!conn || !tableKey.name) { setErr("Looks like you haven't joined a table yet."); return; } diff --git a/static/index.html b/static/index.html index f4cef00..d662dc2 100644 --- a/static/index.html +++ b/static/index.html @@ -16,7 +16,7 @@
    - +