diff options
author | Tor Andersson <tor@ccxvii.net> | 2023-11-28 13:42:36 +0100 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2023-12-10 18:06:33 +0100 |
commit | adee63783dca7a8fae75cb4f8ac3889cef07469a (patch) | |
tree | f70eace2e7374a91a2085dabf16e00a57c121ced /public | |
parent | 1e2964b488e102efa05b03b0d43e086ca7bb7930 (diff) | |
download | server-adee63783dca7a8fae75cb4f8ac3889cef07469a.tar.gz |
Automated role panel display.
Create and populate aside #roles list if missing.
Initialize roles and pointers into global "roles" object.
Diffstat (limited to 'public')
-rw-r--r-- | public/common/client.css | 68 | ||||
-rw-r--r-- | public/common/client.js | 83 | ||||
-rw-r--r-- | public/common/replay.js | 16 |
3 files changed, 115 insertions, 52 deletions
diff --git a/public/common/client.css b/public/common/client.css index 86f968b..c039afe 100644 --- a/public/common/client.css +++ b/public/common/client.css @@ -125,7 +125,7 @@ aside { grid-row: 2; display: grid; overflow: clip; - grid-template-rows: auto minmax(0, 1fr); + grid-template-rows: auto auto minmax(0, 1fr); width: 212px; background-color: white; border-left: 1px solid black; @@ -137,6 +137,8 @@ aside { } #turn_info { + grid-column: 1; + grid-row: 2; border-bottom: 1px solid black; padding: 4px 8px; white-space: pre-line; @@ -145,9 +147,13 @@ aside { line-height: 18px; } +#turn_info:empty { + display: none; +} + #log { grid-column: 1; - grid-row: 2; + grid-row: 3; overflow-y: scroll; } @@ -398,21 +404,51 @@ menu li:hover img { /* ROLES */ -.role_info { +.role { + display: grid; + grid-template-columns: 1fr auto; + padding-top: 3px; border-bottom: 1px solid black; + font-size: 16px; + line-height: 1.5; +} + +.role.hide { + display: none; } .role_name { - border-bottom: 1px solid black; - padding-top: 3px; - padding-bottom: 3px; + grid-row: 1; + grid-column: 1; padding-left: 4px; + white-space: nowrap; + overflow: clip; + text-overflow: ellipsis; +} + +.role_name::before { + content: "\25cb "; + opacity: 0.6; +} + +.role.present .role_name::before { + content: "\25cf "; +} + +.role_stat { + grid-row: 1; + grid-column: 2; + text-align: right; padding-right: 4px; } .role_user { - font-style: italic; + grid-row: 2; + grid-column: 1 / 3; text-align: right; + padding-bottom: 3px; + padding-right: 5px; + font-style: italic; } .role_user a { @@ -424,13 +460,15 @@ menu li:hover img { text-decoration: underline; } -.role_name::before { - content: "\25cb "; - opacity: 0.6; +.role_info { + grid-row: 3; + grid-column: 1 / 3; + border-top: 1px solid black; + background-color: silver; } -.role.present .role_name::before { - content: "\25cf "; +.role_info:empty { + display: none; } /* MAP */ @@ -580,9 +618,9 @@ menu li:hover img { } @media (max-height: 600px) { - .role_name:not(:hover) div.role_user { - display: none; - } + .role:not(:hover) .role_name { padding-bottom: 3px; } + .role:not(:hover) .role_stat { padding-bottom: 3px; } + .role:not(:hover) .role_user { display: none; } } @media (max-width: 800px) { diff --git a/public/common/client.js b/public/common/client.js index ae0f0b8..79592c9 100644 --- a/public/common/client.js +++ b/public/common/client.js @@ -4,7 +4,7 @@ /* PUBLIC GLOBALS */ -var roles = Array.from(document.querySelectorAll(".role")).map(x=>({id:x.id,role:x.id.replace(/^role_/,"").replace(/_/g," ")})) +var roles = null var player = "Observer" var view = null @@ -163,7 +163,7 @@ function init_chat() { <div id="chat_text"></div> <form id="chat_form" action=""><input id="chat_input" autocomplete="off"></form> ` - document.querySelector("body").appendChild(chat_window) + document.body.appendChild(chat_window) let chat_button = document.getElementById("chat_button") chat_button.classList.remove("hide") @@ -191,7 +191,7 @@ function init_chat() { } }) - document.querySelector("body").addEventListener("keydown", e => { + document.body.addEventListener("keydown", e => { if (e.key === "Escape") { if (chat.is_visible) { e.preventDefault() @@ -298,7 +298,7 @@ function init_notepad() { <textarea id="notepad_input" maxlength="16000" oninput="dirty_notepad()"></textarea> <div id="notepad_footer"><button id="notepad_save" onclick="save_notepad()" disabled>Save</button></div> ` - document.querySelector("body").appendChild(notepad_window) + document.body.appendChild(notepad_window) notepad = { is_visible: false, @@ -379,19 +379,46 @@ function on_game_over() { } } -/* CONNECT TO GAME SERVER */ +/* PLAYER ROLE LIST */ + +function init_role_element(role_id, role_name) { + let e_role = document.createElement("div") + e_role.id = role_id + e_role.className = "role" + e_role.innerHTML = + `<div class="role_name"><span>${role_name}</span></div>` + + `<div class="role_stat"></div>` + + `<div class="role_user"></div>` + + `<div class="role_info"></div>` + document.getElementById("roles").appendChild(e_role) + return e_role +} -// XXX function init_player_names(players) { - for (let i = 0; i < roles.length; ++i) { - let p = players.find(p => p.role === roles[i].role) - if (p) - document.getElementById(roles[i].id).querySelector(".role_user").innerHTML = `<a href="/user/${p.name}" target="_blank">${p.name}</a>` + roles = {} + for (let pp of players) { + let class_name = pp.role.replace(/\W/g, "_") + let id = "role_" + class_name + let e = document.getElementById(id) + if (!e) + e = init_role_element(id, pp.role) + let obj = roles[pp.role] = { + class_name: class_name, + id: id, + element: e, + name: e.querySelector(".role_name"), + stat: e.querySelector(".role_stat"), + user: e.querySelector(".role_user"), + } + if (pp.name) + obj.user.innerHTML = `<a href="/user/${pp.name}" target="_blank">${pp.name}</a>` else - document.getElementById(roles[i].id).querySelector(".role_user").textContent = "NONE" + obj.user.textContent = 'NONE' } } +/* CONNECT TO GAME SERVER */ + function send_message(cmd, arg) { let data = JSON.stringify([ cmd, arg ]) console.log("SEND %s %s", cmd, arg) @@ -476,7 +503,7 @@ function connect_play() { case "players": player = arg[0] - document.querySelector("body").classList.add(player.replace(/ /g, "_")) + document.body.classList.add(player.replace(/\W/g, "_")) if (player !== "Observer") { init_chat() init_notepad() @@ -487,13 +514,8 @@ function connect_play() { break case "presence": - { - let list = Array.isArray(arg) ? arg : Object.keys(arg) - for (let i = 0; i < roles.length; ++i) { - let elt = document.getElementById(roles[i].id) - elt.classList.toggle("present", list.includes(roles[i].role)) - } - } + for (let role in roles) + roles[role].element.classList.toggle("present", arg.includes(role)) break case "state": @@ -509,6 +531,7 @@ function connect_play() { game_log.push(line) on_update_header() + on_update_roles() if (typeof on_update === "function") on_update() on_update_log(view.log_start, game_log.length) @@ -521,12 +544,10 @@ function connect_play() { if (snap_count === 0) replay_panel.remove() else - document.querySelector("body").appendChild(replay_panel) - console.log("SNAPSIZE", snap_count) + document.body.appendChild(replay_panel) break case "snap": - console.log("SNAP", arg[0]) snap_active[arg[0]] = arg[1] snap_cache[arg[0]] = arg[2] show_snap(arg[0]) @@ -569,6 +590,12 @@ function on_update_header() { old_active = view.active } +function on_update_roles() { + if (view.active !== undefined) + for (let role in roles) + roles[role].element.classList.toggle("active", view.active === role) +} + /* LOG */ function on_update_log(change_start, end) { @@ -591,7 +618,7 @@ function on_update_log(change_start, end) { entry.style.textDecoration = "none" div.appendChild(entry) } else if (typeof on_log === "function") { - div.appendChild(on_log(text)) + div.appendChild(on_log(text, i)) } else { let entry = document.createElement("div") entry.textContent = text @@ -860,6 +887,7 @@ function show_snap(snap_id) { view = snap_cache[snap_id] view.prompt = "Replay " + snap_id + " / " + snap_count + " \u2013 " + snap_active[snap_id] on_update_header() + on_update_roles() on_update() on_update_log(view.log, view.log) } @@ -889,6 +917,7 @@ function on_snap_stop() { view = snap_view snap_view = null on_update_header() + on_update_roles() on_update() on_update_log(game_log.length, game_log.length) } @@ -902,16 +931,16 @@ window.addEventListener("keydown", (evt) => { if (document.activeElement === document.getElementById("notepad_input")) return if (evt.key === "Shift") - document.querySelector("body").classList.add("shift") + document.body.classList.add("shift") }) window.addEventListener("keyup", (evt) => { if (evt.key === "Shift") - document.querySelector("body").classList.remove("shift") + document.body.classList.remove("shift") }) window.addEventListener("blur", function (evt) { - document.querySelector("body").classList.remove("shift") + document.body.classList.remove("shift") }) /* TOGGLE ZOOM MAP TO FIT */ @@ -976,8 +1005,6 @@ var update_zoom = function () {} update_map_size() - console.log("INIT MAP", map, map_w, map_h, window.devicePixelRatio) - var transform0 = { x: 0, y: 0, scale: 1 } var transform1 = { x: 0, y: 0, scale: 1 } var old_scale = 1 diff --git a/public/common/replay.js b/public/common/replay.js index c1033f5..c8c04ea 100644 --- a/public/common/replay.js +++ b/public/common/replay.js @@ -137,11 +137,9 @@ function update_replay_view() { player = "Observer" } - let body = document.querySelector("body") - body.classList.remove("Observer") - for (let i = 0; i < roles.length; ++i) - body.classList.remove(roles[i].role.replace(/ /g, "_")) - body.classList.add(player.replace(/ /g, "_")) + document.body.classList.toggle("Observer", player === "Observer") + for (let r in roles) + document.body.classList.toggle(roles[r].class_name, player === r) view = rules.view(replay_state, player) if (params.mode !== "debug") @@ -153,7 +151,7 @@ function update_replay_view() { view.game_over = 1 if (replay.length > 0) { - if (document.querySelector("body").classList.contains("shift")) { + if (document.body.classList.contains("shift")) { view.prompt = `[${replay_this}/${replay.length}] ${replay_state.active} / ${replay_state.state}` if (replay_this < replay.length) view.prompt += ` / ${replay[replay_this][1]} ${replay[replay_this][2]}` @@ -308,7 +306,7 @@ async function load_replay() { set_hash(replay.length) on_hash_change() window.addEventListener("hashchange", on_hash_change) - document.querySelector("body").appendChild(replay_panel) + document.body.appendChild(replay_panel) } else { console.log("REPLAY NOT AVAILABLE") replay_state = body.state @@ -319,8 +317,8 @@ async function load_replay() { let viewpoint_panel = document.createElement("div") viewpoint_panel.id = "viewpoint_panel" create_viewpoint_button(viewpoint_panel, "Active", "Active") - for (let r of roles) - create_viewpoint_button(viewpoint_panel, r.role, r.role) + for (let r in roles) + create_viewpoint_button(viewpoint_panel, r, r) create_viewpoint_button(viewpoint_panel, "Observer", "Observer") document.getElementById("actions").appendChild(viewpoint_panel) |