From 6c4896d3aa9d618f024b54c8d51f25ca3f625744 Mon Sep 17 00:00:00 2001 From: Kyle Gunger Date: Fri, 15 Oct 2021 21:01:22 -0400 Subject: [Themes] Theme selection and small fixes --- scripts/client.js | 9 +- scripts/cookie.js | 6 +- scripts/gui/chat.js | 25 +++- scripts/gui/input.js | 37 ++++- scripts/gui/lobby.js | 391 ++++++++++++++++++++++++--------------------------- scripts/gui/table.js | 18 ++- scripts/theme.js | 43 ++++++ 7 files changed, 303 insertions(+), 226 deletions(-) (limited to 'scripts') diff --git a/scripts/client.js b/scripts/client.js index 7f98c7b..07e2fce 100644 --- a/scripts/client.js +++ b/scripts/client.js @@ -55,6 +55,7 @@ class Client{ this.socket.addEventListener("handshake", this.handshake.bind(this)); this.socket.addEventListener("menu", this.menu.bind(this)); this.socket.addEventListener("game", this.game.bind(this)); + this.socket.addEventListener("chat", this.chat.bind(this)); this.lobby = new Lobby(document.getElementsByClassName("lobby")[0], this.socket); @@ -63,8 +64,8 @@ class Client{ this.table = new Table(document.getElementsByClassName("table")[0], this.drag, this.socket); this.chat = new Chat(document.getElementsByClassName("chat")[0], this.socket); - this.chat.addChannel("global"); - this.chat.switchChannel("global"); + this.chat.addChannel("Global"); + this.chat.switchChannel("Global"); this.settings = new Settings(DefaultUserOps); this.settings.putSettings(this.lobby.e.settings); @@ -164,7 +165,9 @@ class Client{ game (m) { switch (m.type) { - + case "move": + this.table.moveByID(m.data.card, m.data.deck, m.data.pos); + break; } } diff --git a/scripts/cookie.js b/scripts/cookie.js index d614af7..44a0be9 100644 --- a/scripts/cookie.js +++ b/scripts/cookie.js @@ -12,7 +12,7 @@ class Cookies { return ""; } - static setCookie(name, value, data = {}) { + static setCookie(name, value, data = {SameSite: "Strict"}) { let extra = ""; for(let key in data) @@ -26,11 +26,11 @@ class Cookies { static setYearCookie(name, value) { var date = new Date(Date.now()); date.setFullYear(date.getFullYear() + 1); - Cookies.setCookie(name, value, {expires: date.toUTCString()}); + Cookies.setCookie(name, value, {SameSite: "Strict", expires: date.toUTCString()}); } static removeCookie(name) { var date = new Date(0); - Cookies.setCookie(name, "", {expires: date.toUTCString()}); + Cookies.setCookie(name, "", {SameSite: "Strict", expires: date.toUTCString()}); } } diff --git a/scripts/gui/chat.js b/scripts/gui/chat.js index fa4b88d..8a5db9f 100644 --- a/scripts/gui/chat.js +++ b/scripts/gui/chat.js @@ -1,11 +1,17 @@ 'use strict'; class Chat { - constructor(e) + constructor(e, soc) { this.chats = []; this.root = e; + this.socket = soc; e.getElementsByClassName("toggle-chat")[0].onclick = this.toggle.bind(this); + let cin = e.getElementsByClassName("chat-input")[0]; + this.chatInput = cin.children[0]; + + cin.children[0].addEventListener("keydown", this.checkEnter.bind(this)); + cin.children[0].addEventListener("click", this.sendMessage.bind(this)); } getChannel (name) @@ -50,7 +56,7 @@ class Chat { b.onclick = this.switchChannel.bind(this, name); - b.innerText = name[0].toUpperCase() + name.slice(1).toLowerCase(); + b.innerText = name; d.className = "chat-text"; @@ -92,6 +98,21 @@ class Chat { }); } + checkEnter(e) + { + if(e.key === "Enter") { + this.sendMessage(); + } + } + + sendMessage () + { + var str = this.chatInput.value; + this.chatInput.value = ""; + this.socket.send("chat", str); + + } + recieveMessage (channel, msg) { let c = this.getChannel(channel); diff --git a/scripts/gui/input.js b/scripts/gui/input.js index f72dd91..a44784b 100644 --- a/scripts/gui/input.js +++ b/scripts/gui/input.js @@ -199,6 +199,10 @@ class MakeInput { var wrapper = MakeInput.wrapInputs("select", se); wrapper.getValue = MakeInput.selValue.bind(null, se); + wrapper.getIndex = MakeInput.selIndex.bind(null, se); + wrapper.addOption = MakeInput.selAdd.bind(se); + wrapper.removeOption = MakeInput.selRem.bind(se); + wrapper.setIndex = MakeInput.selSet.bind(se); wrapper.setAttribute("tabindex", 0); return wrapper; @@ -213,18 +217,47 @@ class MakeInput { return ""; } + + static selIndex (el) { + return parseInt(el.getAttribute("selected")); + } - static selOption (el) { + static selOption (el, dispatch = true) { let sn = el.selectIndex; let psn = parseInt(el.parentElement.getAttribute("selected")); - if(Number.isInteger(psn)) + if(Number.isInteger(psn) && psn < el.parentElement.childElementCount) el.parentElement.children[psn].setAttribute("selected", false); el.parentElement.setAttribute("selected", sn); el.setAttribute("selected", true); + + if(dispatch) + el.parentElement.parentElement.dispatchEvent(new InputEvent("change")); } + static selSet (index) { + MakeInput.selOption(this.children[index], false); + } + + static selAdd (name, value) { + this.appendChild(MakeInput.selectOption(value, name, this.childElementCount, false)); + return this.childElementCount - 1; + } + + static selRem (index) { + if(index >= this.childElementCount) + return false; + + this.children[index].remove(); + + for(let i = index; i < this.childElementCount; i++) { + this.children[index].selectIndex = "" + i; + } + + return true; + } + static titleWrap(el, title) { var wrapper = document.createElement("div"); wrapper.className = "input-title-wrapper"; diff --git a/scripts/gui/lobby.js b/scripts/gui/lobby.js index 13f3eab..8242843 100644 --- a/scripts/gui/lobby.js +++ b/scripts/gui/lobby.js @@ -6,43 +6,43 @@ // TopBar represents the bar at the top of the screen when client is in the lobby. class TopBar{ - constructor (el, desktopSettings) - { - this.root = el; - this.desktopSettings = desktopSettings; - - this.newGame = el.getElementsByClassName("new-game")[0]; - this.mobileSettings = el.getElementsByClassName("mobile-settings")[0]; - this.status = el.getElementsByClassName("status")[0]; - } - - // Set color of status bar - setStatus (s) { - this.status.setAttribute("s", s); - } - - // Toggle showing the new game screen - toggleNewGame () { - if (this.newGame.style.display !== "none") - this.newGame.style.display = "none"; - else - this.newGame.style.display = "block"; - } - - // Toggle showing the mobile settings - toggleMobileSettings (settings) { - if (this.mobileSettings.style.display !== "none"){ - this.mobileSettings.style.display = "none"; - settings.putSettings(this.desktopSettings); - } else { - this.mobileSettings.style.display = "block"; - settings.putSettings(this.mobileSettings); - } - } - - mobileSettingsOpen() { - return this.mobileSettings.style.display !== "none" - } + constructor (el, desktopSettings) + { + this.root = el; + this.desktopSettings = desktopSettings; + + this.newGame = el.getElementsByClassName("new-game")[0]; + this.mobileSettings = el.getElementsByClassName("mobile-settings")[0]; + this.status = el.getElementsByClassName("status")[0]; + } + + // Set color of status bar + setStatus (s) { + this.status.setAttribute("s", s); + } + + // Toggle showing the new game screen + toggleNewGame () { + if (this.newGame.style.display !== "none") + this.newGame.style.display = "none"; + else + this.newGame.style.display = "block"; + } + + // Toggle showing the mobile settings + toggleMobileSettings (settings) { + if (this.mobileSettings.style.display !== "none"){ + this.mobileSettings.style.display = "none"; + settings.putSettings(this.desktopSettings); + } else { + this.mobileSettings.style.display = "block"; + settings.putSettings(this.mobileSettings); + } + } + + mobileSettingsOpen() { + return this.mobileSettings.style.display !== "none" + } } // ############# @@ -50,22 +50,32 @@ class TopBar{ // ############# // Game represents a single game in the lobby view. It has methods for setting up the elements and such. -function createGameEl (options = {id: 0, name: ""}, el) -{ - let e = document.createElement("div"); - e.className = "game"; - - let title = document.createElement("h2"); - title.textContent = options.name; - e.appendChild(title); - - let join = document.createElement("button"); - join.className = "join"; - join.textContent = "Join"; - join.addEventListener("click", game.joinGame.bind(game, options.id)); - e.appendChild(join); - - el.appendChild(e); +class Game { + constructor(options = {id: 0, name: ""}, el) + { + this.getID = function () { + return options.id; + } + + this.getName = function () { + return options.name; + } + + let e = document.createElement("div"); + e.className = "game"; + + let title = document.createElement("h2"); + title.textContent = options.name; + e.appendChild(title); + + let join = document.createElement("button"); + join.className = "join"; + join.textContent = "Join"; + join.addEventListener("click", game.joinGame.bind(game, options.id)); + e.appendChild(join); + + el.appendChild(e); + } } // ############## @@ -74,160 +84,123 @@ function createGameEl (options = {id: 0, name: ""}, el) // Lobby manages the players and games provided by the server and allows users to join or create their own games. class Lobby { - constructor (el) - { - this.root = el; - - this.e = { - status: el.getElementsByClassName("status")[0], - addr: el.getElementsByClassName("addr")[0], - games: el.getElementsByClassName("games")[0], - settings: el.getElementsByClassName("settings")[0], - - stats: { - game: document.getElementById("game"), - packs: document.getElementById("packs"), - online: document.getElementById("online"), - ingame: document.getElementById("ingame"), - pubgame: document.getElementById("pubgame") - } - }; - - this.top = new TopBar( - document.getElementsByClassName("topbar")[0], - this.e.settings - ); - - this.init = false; - this.online = []; - this.games = []; - this.packs = []; - this.players = []; - } - - // Set initial pack list - // {data array} array of strings representing pack names - packList (data) { - this.packs = data; - this.top.setPacks(this.packs) - this.e.stats.packs.innerText = this.packs.length(); - } - - // Set initial game list. - // { data object } object containing {games} and {name} - // { data.name string } name of the game the server runs - // { data.games array } array of public games the server is running - // { data.games[n].name } room name - // { data.games[n].packs } list of the pack names used by this game - // { data.games[n].id } room identifier (uuid) - // { data.games[n].max } max players in room - gameList (data) { - while (this.e.games.firstChild != null) { - this.e.games.remove(this.elements.games.firstChild) - } - - for (let i in data.games) { - let gel = new Game(i.name, i.packs, i.id); - this.games.push(gel); - this.e.games.appendChild(gel.getElement()); - } - - this.e.stats.game.innerText = data.name; - this.e.stats.pubgame.innerText = this.games.length(); - } - - // Set the initial player list. - // { data array } represents a list of player objects from the server - // { data[n].name string } name of the player - // { data[n].game string } id of the game room (empty if not in game). - // { data[n].color string } css color chosen by player. - // { data[n].uuid string } uuid of the player - players (data) { - - this.e.stats.online.innerText = this.players.length(); - this.init = true; - } - - // Called when a new public game is created on the server - // { data object } the game object - // { data.name } room name - // { data.packs } list of the pack names used by this game - // { data.id } room identifier (uuid) - addGame (data) { - createGameEl(data, this.e.games); - } - - // Called when a new public game is removed on the server - // { data string } the uuid of the game to delete - removeGame (data) { - - } - - // Called when a new player enters the lobby. - // { data object } an object representing the player - // { data.name string } name of the player - // { data.game string } id of the game room (empty if not in game). - // { data.color string } css color chosen by player. - // { data.uuid string } uuid of the player - addPlayer (data) { - - } - - // Called when a player modifies their settings in the lobby. - // { data object } new player settings - // { data.name string } non null if the player has changed their name - // { data.color string } non null if the player has changed their color - // { data.uuid string } uuid of player changing their settings - modPlayer (data) { - - } - - // Called when a player moves between the lobby and a game, or between two games - // { data object } new location - // { data.player } uuid of player changing location - // { data.loc } uuid of room player is moving to (empty if moving to lobby) - movePlayer (data) { - - } - - // Called when a player exits the game (from lobby or game) - // { data string } uuid of player - removePlayer (data) { - - } - - // Called when the client wants to toggle the new game screen - newGame () { - //if(this.init) return; - this.top.toggleNewGame(); - } - - // Called when the client wants to toggle the mobile settings screen - mobileSettings (settings) { - //if(this.init) return; - this.top.toggleMobileSettings(settings); - } - - // Called when the WebSocket state has changed. - setState (text, s, server) { - this.e.status.setAttribute("s", s); - if(this.e.status.innerText != "Error" || ( this.e.status.innerText == "Error" && text != "Closed")) - this.e.status.innerText = text; - this.e.addr.innerText = server; - this.top.setStatus(s); - } - - getState () { - return this.e.status.innerText.toLowerCase(); - } - - // Called when we are resetting the game. - reset () { - while (this.e.games.firstElementChild != null) { - this.e.games.removeChild(this.e.games.firstElementChild) - } - - this.setState("Connecting", "loading", this.e.addr.innerText); - this.init = false; - } + constructor (el) + { + this.root = el; + + this.e = { + status: el.getElementsByClassName("status")[0], + addr: el.getElementsByClassName("addr")[0], + games: el.getElementsByClassName("games")[0], + settings: el.getElementsByClassName("settings")[0], + + stats: { + game: document.getElementById("game"), + packs: document.getElementById("packs"), + online: document.getElementById("online"), + ingame: document.getElementById("ingame"), + pubgame: document.getElementById("pubgame") + } + }; + + this.top = new TopBar( + document.getElementsByClassName("topbar")[0], + this.e.settings + ); + + this.init = false; + this.online = []; + this.games = []; + this.packs = []; + } + + // Set initial pack list + // {data array} array of strings representing pack names + packList (data) { + this.packs = data; + this.top.setPacks(this.packs) + this.e.stats.packs.innerText = this.packs.length(); + } + + // Set initial game list. + // { data object } object containing {games} and {name} + // { data.name string } name of the game the server runs + // { data.games array } array of public games the server is running + // { data.games[n].name } room name + // { data.games[n].packs } list of the pack names used by this game + // { data.games[n].id } room identifier (uuid) + // { data.games[n].max } max players in room + gameList (data) { + while (this.e.games.firstChild != null) { + this.e.games.remove(this.elements.games.firstChild) + } + + for (let i of data.games) { + let g = new Game(i, this.e.games); + this.games.push(g); + } + + this.e.stats.game.innerText = data.name; + this.e.stats.pubgame.innerText = this.games.length(); + } + + // Set the initial player list. + // { data object } player statistics from the server + // { data.online number } players on server + // { data.ingame number } players on server and in game + players (data) { + this.e.stats.online.innerText = data.online; + this.e.stats.ingame.innerText = data.ingame; + } + + // Called when a new public game is created on the server + // { data object } the game object + // { data.name } room name + // { data.packs } list of the pack names used by this game + // { data.id } room identifier (uuid) + addGame (data) { + let g = new Game(data, this.e.games); + this.games.push(g); + } + + // Called when a new public game is removed on the server + // { data string } the uuid of the game to delete + removeGame (data) { + + } + + // Called when the client wants to toggle the new game screen + newGame () { + //if(this.init) return; + this.top.toggleNewGame(); + } + + // Called when the client wants to toggle the mobile settings screen + mobileSettings (settings) { + //if(this.init) return; + this.top.toggleMobileSettings(settings); + } + + // Called when the WebSocket state has changed. + setState (text, s, server) { + this.e.status.setAttribute("s", s); + if(this.e.status.innerText != "Error" || ( this.e.status.innerText == "Error" && text != "Closed")) + this.e.status.innerText = text; + this.e.addr.innerText = server; + this.top.setStatus(s); + } + + getState () { + return this.e.status.innerText.toLowerCase(); + } + + // Called when we are resetting the game. + reset () { + while (this.e.games.firstElementChild != null) { + this.e.games.removeChild(this.e.games.firstElementChild) + } + + this.setState("Connecting", "loading", this.e.addr.innerText); + this.init = false; + } } diff --git a/scripts/gui/table.js b/scripts/gui/table.js index 0d21262..9aac2ae 100644 --- a/scripts/gui/table.js +++ b/scripts/gui/table.js @@ -83,7 +83,7 @@ class Table{ return null; } - moveCard(card, newDeck) + moveCard(card, newDeck, index = -1) { for(let d of this.decks) { @@ -91,10 +91,14 @@ class Table{ break; } card.resetPos(); - newDeck.appendCard(card); + + if(index < 0) + newDeck.appendCard(card); + else + newDeck.addCardAt(card, index); } - moveByID(cardID, deckID) + moveByID(cardID, deckID, index = -1) { let card, deck; for(let d of this.decks) @@ -107,12 +111,12 @@ class Table{ deck = d; } - this.moveCard(card, deck); + this.moveCard(card, deck, index); } - checkMove(cardID, deckID) + checkMove(cardID, deckID, index = -1) { - this.socket.send("game", {}); + this.socket.send("game", {type: "move", card: cardID, deck: deckID, pos: index}); } dragCheck(cap) @@ -131,7 +135,7 @@ class Table{ if(c !== null) { if(d !== null) - this.moveCard(c, d); + this.checkMove(c.getID(), d.getID()); else c.resetPos(); } diff --git a/scripts/theme.js b/scripts/theme.js index 627b833..b9dcb37 100644 --- a/scripts/theme.js +++ b/scripts/theme.js @@ -1,10 +1,28 @@ 'use strict'; +const BASE_THEMES = [[ + "styles/themes/colors-base.css", + "styles/themes/colors-dark.css" +], +[ + "Light", + "Dark" +]]; + class Theme{ static theme = document.getElementById("theme"); + static UserThemes = [[],[]]; static init() { + let uth = Cookies.getCookie("userThemes").split(','); + + for (let i = 1; i < uth.length; i += 2) + { + this.UserThemes[0].push(uth[i - 1]); + this.UserThemes[1].push(uth[i]); + } + if(Cookies.getCookie("theme") == ""){ Cookies.setYearCookie("theme", "styles/themes/colors-base.css"); } @@ -21,6 +39,31 @@ class Theme{ Cookies.setYearCookie("theme", sheet); Theme.theme.setAttribute("href", sheet + "?v=" + Date.now()); } + + static setUserThemes() { + let out = ""; + for (let i = 0; i < this.UserThemes[0].length; i++) + { + if(i !== 0) + out = out + ","; + + out = out + this.UserThemes[0][i] + "," + this.UserThemes[1][i]; + } + + Cookies.setYearCookie("userThemes", out); + } + + static removeUserTheme (index) { + this.UserThemes[0].splice(index, 1); + this.UserThemes[1].splice(index, 1); + this.setUserThemes(); + } + + static addUserTheme (name, value) { + this.UserThemes[0].push(name); + this.UserThemes[1].push(value); + this.setUserThemes(); + } } Theme.restore(); \ No newline at end of file -- cgit v1.2.3