summaryrefslogtreecommitdiff
path: root/public/common/client.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/common/client.js')
-rw-r--r--public/common/client.js375
1 files changed, 375 insertions, 0 deletions
diff --git a/public/common/client.js b/public/common/client.js
new file mode 100644
index 0000000..ea1c12b
--- /dev/null
+++ b/public/common/client.js
@@ -0,0 +1,375 @@
+let socket = null;
+let chat_is_visible = false;
+let chat_text = null;
+let chat_key = null;
+let chat_last_day = null;
+let chat_log = null;
+
+function scroll_with_middle_mouse(panel_sel, multiplier) {
+ let panel = document.querySelector(panel_sel);
+ let down_x, down_y, scroll_x, scroll_y;
+ if (!multiplier)
+ multiplier = 1;
+ function md(e) {
+ if (e.button === 1) {
+ down_x = e.clientX;
+ down_y = e.clientY;
+ scroll_x = panel.scrollLeft;
+ scroll_y = panel.scrollTop;
+ window.addEventListener('mousemove', mm);
+ window.addEventListener('mouseup', mu);
+ e.preventDefault();
+ }
+ }
+ function mm(e) {
+ let dx = down_x - e.clientX;
+ let dy = down_y - e.clientY;
+ panel.scrollLeft = scroll_x + dx * multiplier;
+ panel.scrollTop = scroll_y + dy * multiplier;
+ e.preventDefault();
+ }
+ function mu(e) {
+ if (e.button === 1) {
+ window.removeEventListener('mousemove', mm);
+ window.removeEventListener('mouseup', mu);
+ e.preventDefault();
+ }
+ }
+ panel.addEventListener('mousedown', md);
+}
+
+function drag_element_with_mouse(element_sel, grabber_sel) {
+ let element = document.querySelector(element_sel);
+ let grabber = document.querySelector(grabber_sel) || element;
+ let save_x, save_y;
+ function md(e) {
+ if (e.button === 0) {
+ save_x = e.clientX;
+ save_y = e.clientY;
+ window.addEventListener('mousemove', mm);
+ window.addEventListener('mouseup', mu);
+ e.preventDefault();
+ }
+ }
+ function mm(e) {
+ let dx = save_x - e.clientX;
+ let dy = save_y - e.clientY;
+ save_x = e.clientX;
+ save_y = e.clientY;
+ element.style.left = (element.offsetLeft - dx) + "px";
+ element.style.top = (element.offsetTop - dy) + "px";
+ e.preventDefault();
+ }
+ function mu(e) {
+ if (e.button === 0) {
+ window.removeEventListener('mousemove', mm);
+ window.removeEventListener('mouseup', mu);
+ e.preventDefault();
+ }
+ }
+ grabber.addEventListener('mousedown', md);
+}
+
+function add_chat_lines(log) {
+ function format_time(date) {
+ let mm = date.getMinutes();
+ let hh = date.getHours();
+ if (mm < 10) mm = "0" + mm;
+ if (hh < 10) hh = "0" + hh;
+ return hh + ":" + mm;
+ }
+ function add_date_line(date) {
+ let line = document.createElement("div");
+ line.className = "date";
+ line.textContent = "~ " + date + " ~";
+ chat_text.appendChild(line);
+ }
+ function add_chat_line(time, user, message) {
+ let line = document.createElement("div");
+ line.textContent = "[" + time + "] " + user + " \xbb " + message;
+ chat_text.appendChild(line);
+ chat_text.scrollTop = chat_text.scrollHeight;
+ }
+ for (let entry of log) {
+ chat_log.push(entry);
+ let [date, user, message] = entry;
+ date = new Date(date);
+ let day = date.toDateString();
+ if (day != chat_last_day) {
+ add_date_line(day);
+ chat_last_day = day;
+ }
+ add_chat_line(format_time(date), user, message);
+ }
+}
+
+function load_chat(game) {
+ chat_key = "chat/" + game;
+ chat_text = document.querySelector(".chat_text");
+ chat_last_day = null;
+ chat_log = [];
+ let save = JSON.parse(window.localStorage.getItem(chat_key));
+ if (save) {
+ if (Date.now() < save.expires)
+ add_chat_lines(save.chat);
+ else
+ window.localStorage.removeItem(chat_key);
+ }
+ return chat_log.length;
+}
+
+function save_chat() {
+ const DAY = 86400000;
+ let save = { expires: Date.now() + 7 * DAY, chat: chat_log };
+ window.localStorage.setItem(chat_key, JSON.stringify(save));
+}
+
+function update_chat(log_start, log) {
+ if (log_start == 0) {
+ chat_last_day = null;
+ chat_log = [];
+ while (chat_text.firstChild)
+ chat_text.removeChild(chat_text.firstChild);
+ }
+ add_chat_lines(log);
+}
+
+function init_client(roles) {
+ let params = new URLSearchParams(window.location.search);
+ let title = window.location.pathname.split("/")[1];
+ let game = params.get("game");
+ let role = params.get("role");
+ let player = null;
+
+ const ROLE_SEL = [
+ ".role.one",
+ ".role.two",
+ ".role.three",
+ ".role.four",
+ ".role.five",
+ ".role.six",
+ ".role.seven",
+ ];
+
+ const USER_SEL = [
+ ".role.one .role_user",
+ ".role.two .role_user",
+ ".role.three .role_user",
+ ".role.four .role_user",
+ ".role.five .role_user",
+ ".role.six .role_user",
+ ".role.seven .role_user",
+ ];
+
+ load_chat(game);
+
+ console.log("JOINING game", game, "role", role);
+
+ socket = io({
+ transports: ['websocket'],
+ query: { title: title, game: game, role: role },
+ });
+
+ socket.on('connect', () => {
+ console.log("CONNECTED");
+ document.querySelector(".grid_top").classList.remove('disconnected');
+ socket.emit('getchat', chat_log.length); // only send new messages when we reconnect!
+ });
+
+ socket.on('disconnect', () => {
+ console.log("DISCONNECTED");
+ document.getElementById("prompt").textContent = "Disconnected from server!";
+ document.querySelector(".grid_top").classList.add('disconnected');
+ });
+
+ socket.on('roles', (me, players) => {
+ console.log("ROLES", me, JSON.stringify(players));
+ player = me;
+ if (player == "Observer")
+ document.querySelector(".chat_button").style.display = "none";
+ document.querySelector(".grid_top").classList.add(player);
+ for (let i = 0; i < roles.length; ++i) {
+ let p = players.find(p => p.role == roles[i]);
+ document.querySelector(USER_SEL[i]).textContent = p ? p.name : "NONE";
+ }
+ });
+
+ socket.on('presence', (presence) => {
+ console.log("PRESENCE", presence);
+ for (let i = 0; i < roles.length; ++i) {
+ let elt = document.querySelector(ROLE_SEL[i]);
+ if (roles[i] in presence)
+ elt.classList.add('present');
+ else
+ elt.classList.remove('present');
+ }
+ });
+
+ socket.on('state', (state) => {
+ console.log("STATE");
+ on_update_log(state);
+ on_update_bar(state, player);
+ on_update(state, player);
+ });
+
+ socket.on('save', (msg) => {
+ console.log("SAVE");
+ window.localStorage[title + '/save'] = msg;
+ });
+
+ socket.on('error', (msg) => {
+ console.log("ERROR", msg);
+ document.getElementById("prompt").textContent = msg;
+ });
+
+ socket.on('chat', function (log_start, log) {
+ console.log("CHAT UPDATE", log_start, log.length);
+ update_chat(log_start, log);
+ let button = document.querySelector(".chat_button");
+ if (!chat_is_visible)
+ button.classList.add("new");
+ else
+ save_chat();
+ });
+
+ document.querySelector(".chat_form").addEventListener("submit", e => {
+ let input = document.querySelector("#chat_input");
+ e.preventDefault();
+ if (input.value) {
+ socket.emit('chat', input.value);
+ input.value = '';
+ } else {
+ hide_chat();
+ }
+ });
+
+ document.querySelector("body").addEventListener("keydown", e => {
+ if (player && player != "Observer") {
+ if (e.key == "Escape") {
+ if (chat_is_visible) {
+ e.preventDefault();
+ hide_chat();
+ }
+ }
+ if (e.key == "Enter") {
+ let input = document.querySelector("#chat_input");
+ if (document.activeElement != input) {
+ e.preventDefault();
+ show_chat();
+ }
+ }
+ }
+ });
+
+ drag_element_with_mouse(".chat_window", ".chat_header");
+}
+
+function on_update_bar(state, player) {
+ document.getElementById("prompt").textContent = state.prompt;
+ if (state.actions)
+ document.querySelector(".grid_top").classList.add("your_turn");
+ else
+ document.querySelector(".grid_top").classList.remove("your_turn");
+}
+
+function on_update_log(state) {
+ let parent = document.getElementById("log");
+ let to_delete = parent.children.length - state.log_start;
+ while (to_delete > 0) {
+ parent.removeChild(parent.firstChild);
+ --to_delete;
+ }
+ for (let entry of state.log) {
+ let p = document.createElement("div");
+ p.textContent = entry;
+ parent.prepend(p);
+ }
+}
+
+function toggle_fullscreen() {
+ if (document.fullscreen)
+ document.exitFullscreen();
+ else
+ document.documentElement.requestFullscreen();
+}
+
+function show_chat() {
+ if (!chat_is_visible) {
+ document.querySelector(".chat_button").classList.remove("new");
+ document.querySelector(".chat_window").classList.add("show");
+ document.querySelector("#chat_input").focus();
+ chat_is_visible = true;
+ save_chat();
+ }
+}
+
+function hide_chat() {
+ if (chat_is_visible) {
+ document.querySelector(".chat_window").classList.remove("show");
+ document.querySelector("#chat_input").blur();
+ chat_is_visible = false;
+ }
+}
+
+function toggle_chat() {
+ if (chat_is_visible)
+ hide_chat();
+ else
+ show_chat();
+}
+
+function toggle_log() {
+ document.querySelector(".grid_window").classList.toggle("hide_log");
+}
+
+function show_action_button(sel, action, use_label = false) {
+ let button = document.querySelector(sel);
+ if (game.actions && action in game.actions) {
+ button.classList.remove("hide");
+ if (game.actions[action]) {
+ if (use_label)
+ button.textContent = game.actions[action];
+ button.disabled = false;
+ } else {
+ button.disabled = true;
+ }
+ } else {
+ button.classList.add("hide");
+ }
+}
+
+function confirm_resign() {
+ if (window.confirm("Are you sure that you want to resign?"))
+ socket.emit('resign');
+}
+
+function send_action(verb, noun) {
+ // Reset action list here so we don't send more than one action per server prompt!
+ if (noun) {
+ if (game.actions && game.actions[verb] && game.actions[verb].includes(noun)) {
+ game.actions = null;
+ console.log("SEND ACTION", verb, noun);
+ socket.emit('action', verb, noun);
+ }
+ } else {
+ if (game.actions && game.actions[verb]) {
+ game.actions = null;
+ console.log("SEND ACTION", verb, noun);
+ socket.emit('action', verb);
+ }
+ }
+}
+
+function send_save() {
+ socket.emit('save');
+}
+
+function send_restore() {
+ let title = window.location.pathname.split("/")[1];
+ let save = window.localStorage[title + '/save'];
+ socket.emit('restore', window.localStorage[title + '/save']);
+}
+
+function send_restart(scenario) {
+ socket.emit('restart', scenario);
+}