From dbaf69557c0d6e648120b068fec1920b9391a24a Mon Sep 17 00:00:00 2001 From: Kyle Gunger Date: Fri, 18 Sep 2020 12:19:44 -0400 Subject: Update from local repo --- scripts/gui/chat.js | 149 +++++++++++++++++++++++++++++++++ scripts/gui/input.js | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++ scripts/gui/lobby.js | 209 ++++++++++++++++++++++++++++++++++++++++++++++ scripts/gui/table.js | 79 ++++++++++++++++++ 4 files changed, 668 insertions(+) create mode 100644 scripts/gui/chat.js create mode 100644 scripts/gui/input.js create mode 100644 scripts/gui/lobby.js create mode 100644 scripts/gui/table.js (limited to 'scripts/gui') diff --git a/scripts/gui/chat.js b/scripts/gui/chat.js new file mode 100644 index 0000000..68b8f5d --- /dev/null +++ b/scripts/gui/chat.js @@ -0,0 +1,149 @@ +'use strict'; + +class Chat { + constructor(e) + { + this.chats = []; + this.root = e; + e.getElementsByClassName("toggle-chat")[0].onclick = this.toggle.bind(this); + } + + getChannel (name) + { + for(let i in this.chats) + { + if (this.chats[i].name == name) + { + return this.chats[i]; + } + } + + return null; + } + + isActive (name) + { + for(let i in this.chats) + { + if (this.chats[i].name == name) + { + if(this.chats[i].btn.getAttribute("active") == "true") + return true; + return false; + } + } + + return false; + } + + addChannel (name, follow = true) + { + if(this.getChannel(name) != null) + return; + + let d = document.createElement("div"); + let b = document.createElement("button"); + + this.root.getElementsByClassName("chat-select")[0].appendChild(b); + + b.setAttribute("active", false); + + b.onclick = this.switchChannel.bind(this, name); + + b.innerText = name[0].toUpperCase() + name.slice(1).toLowerCase(); + + d.className = "chat-text"; + + this.chats.push({name: name, e: d, btn: b}); + + if(follow) + this.switchChannel(name) + } + + getActiveChannel () + { + for(let i in this.chats) + { + if (this.chats[i].btn.getAttribute("active") == "true") + { + return this.chats[i]; + } + } + + return null; + } + + switchChannel (name) + { + let c = this.getChannel(name); + + if(c == null) + return; + + if(this.getActiveChannel() != null) + this.getActiveChannel().btn.setAttribute("active", false); + + c.btn.setAttribute("active", true); + var ct = this.root.getElementsByClassName("chat-text")[0]; + ct.replaceWith(c.e); + + c.e.scroll({ + top: c.e.scrollTopMax + }); + } + + recieveMessage (channel, msg) + { + let c = this.getChannel(channel); + + if(c == null) + return; + + let autoscroll = c.e.scrollTop == c.e.scrollTopMax; + + let csp = document.createElement("span"); + csp.style.color = msg.color; + csp.innerText = msg.user + ": "; + let tsp = document.createElement("span"); + tsp.innerText = msg.text; + let d = document.createElement("div"); + d.appendChild(csp); + d.appendChild(tsp); + + c.e.appendChild(d); + + if(autoscroll) + c.e.scroll({top: c.e.scrollTopMax}); + } + + clearChannel (name) + { + let c = this.getChannel(name); + if(c == null) + return; + + while(c.e.firstElementChild != null) + c.e.firstElementChild.remove(); + } + + deleteChannel (name) + { + let c = this.getChannel(name); + if(c == null) + return; + + while(c.e.firstElementChild != null) + c.e.firstElementChild.remove(); + + c.btn.remove(); + + this.chats.splice(this.chats.indexOf(c), 1); + } + + toggle () { + if(this.root.getAttribute("show") != "true") + this.root.setAttribute("show", "true"); + else + this.root.setAttribute("show", "false"); + } +} diff --git a/scripts/gui/input.js b/scripts/gui/input.js new file mode 100644 index 0000000..6ed3d39 --- /dev/null +++ b/scripts/gui/input.js @@ -0,0 +1,231 @@ +'use strict'; + +//This whole clusterfuq of functions needs fixing. +class MakeInput { + static createInput(type = "text", id) + { + var el = document.createElement("input"); + el.setAttribute("type", type); + + if(typeof id == "string") + el.setAttribute("id", id); + + el.getValue = function () { + return this.value; + } + + return el; + } + + static inputLabel(text, id) + { + var el = document.createElement("label"); + el.innerText = text; + if(typeof id == "string") + el.setAttribute("for", id); + return el; + } + + static colorInput (value, id) { + var el = MakeInput.createInput("color", id); + el.value = value; + return el; + } + + static textInput (value, placeholder, id) + { + var el = MakeInput.createInput("text", id); + el.setAttribute("placeholder", placeholder); + el.value = value; + return el; + } + + static numberInput (value, id) + { + var el = MakeInput.createInput("number", id); + el.value = value; + return el; + } + + //To fix + static fileInput (value, id) { + var el = MakeInput.createInput("file", id); + + el.value = value; + + el.setAttribute("data-files", "Choose a file"); + + el.firstElementChild.onchange = function () { + let text = ""; + switch (this.files.length) { + case 0: + text = "Choose a file"; + break; + case 1: + text = "File: " + this.files[0].name; + break; + default: + text = "Files: " + this.files[0].name + "..."; + break; + } + el.setAttribute("data-files", text); + } + + return el; + } + + static checkboxInput (checked = false, id) { + var el = MakeInput.createInput("checkbox", false, id); + if(checked) + el.setAttribute("checked"); + return el; + } + + static radioInput (group, value, checked = false, id) { + var el = MakeInput.createInput("radio", false, id); + el.setAttribute("name", group); + el.setAttribute("value", value); + if(checked) + el.checked = true; + return el; + } + + static radioInputs (group, names, values, checked = 0, id) { + + let toWrap = []; + + for(let i = 0; i < values.length; i++) { + toWrap.push(MakeInput.inputLabel(names[i], group+"-"+i)); + if(i == checked) + toWrap.push(MakeInput.radioInput(group, values[i], true, group+"-"+i)); + else + toWrap.push(MakeInput.radioInput(group, values[i], false, group+"-"+i)); + toWrap.push(document.createElement("br")); + } + + var wrapper = MakeInput.wrapInputs("radio", ...toWrap); + + wrapper.getValue = function() { + for(let i = 0; i < this.children.length; i++){ + if(this.children[i].checked) + return this.children[i].value; + } + }; + + if(typeof id == "string") + wrapper.setAttribute("id", id); + + return wrapper; + } + + static selectOption (text, value, selected) { + var so = document.createElement("div"); + so.innerText = text; + so.setAttribute("value", value); + so.addEventListener("mousedown", customSelectOption.bind(null, so)); + + if(selected === true) + so.setAttribute("selected", true); + + return so + } + + static selectInput (names, values, id, select = 0) { + var se = document.createElement("div"); + se.className = "input-select"; + se.setAttribute("tabindex", 0); + se.setAttribute("selected", select); + + for(let i in names) + { + se.appendChild(MakeInput.selectOption(names[i], values[i], i == select)); + } + + if(typeof id == "string") + se.setAttribute("id", id); + + var wrapper = MakeInput.wrapInputs("select", se); + wrapper.getValue = MakeInput.selValue.bind(null, se); + wrapper.setAttribute("tabindex", 0); + + return wrapper; + } + + static wrapInputs (type, ...el) { + + var wrapper = document.createElement("div"); + wrapper.className = "input-container"; + wrapper.setAttribute("type", type); + + for(let i = 0; i < el.length; i++) + { + wrapper.appendChild(el[i]); + } + + return wrapper; + } + + static selValue (el) { + let sel = parseInt(el.getAttribute("selected")); + + if(typeof sel != "undefined") { + return el.children[sel].getAttribute("value"); + } + + return ""; + } + + static selOption (el) { + let sn = Array.prototype.indexOf.call(el.parentElement.children, el); + let psn = parseInt(el.parentElement.getAttribute("selected")); + + if(Number.isInteger(psn)) + el.parentElement.children[psn].setAttribute("selected", false); + + el.parentElement.setAttribute("selected", sn); + el.setAttribute("selected", true); + } +} + +class Settings { + constructor (template = {}) + { + this.settings = Settings.genSettings(template); + } + + static genSettings (template) + { + var out = {}; + + for(let key in template) + { + switch(template[key].type) + { + case "radio": + out[key] = MakeInput.radioInputs(...template[key].args); + break; + default: + if(typeof MakeInput[template[key].type+"Input"] != null) + out[key] = MakeInput[template[key].type+"Input"](...template[key].args); + } + } + + return out; + } + + getSettings () + { + var out = {}; + + for(let key in this.settings) + out[key] = this.settings[key].getValue(); + + return out; + } + + putSettings (el) + { + for(let key in this.settings) + el.appendChild(this.settings[key]); + } +} diff --git a/scripts/gui/lobby.js b/scripts/gui/lobby.js new file mode 100644 index 0000000..7d2b6cd --- /dev/null +++ b/scripts/gui/lobby.js @@ -0,0 +1,209 @@ +// ############### +// # TopBar Code # +// ############### + +// TopBar represents the bar at the top of the screen when client is in the lobby. + +class TopBar{ + constructor (el) + { + this.root = el; + + 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 () { + if (this.mobileSettings.style.display !== "none") + this.mobileSettings.style.display = "none"; + else + this.mobileSettings.style.display = "block"; + } +} + +// ############# +// # Game code # +// ############# + +// Game represents a single game in the lobby view. It has methods for setting up the elements and such. +class Game{ + constructor (name, packs, maxp, id) + { + } +} + +// ############## +// # Lobby Code # +// ############## + +// 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.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) { + + } + + // 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 () { + //if(this.init) return; + this.top.toggleMobileSettings(); + } + + // 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 new file mode 100644 index 0000000..c4878a0 --- /dev/null +++ b/scripts/gui/table.js @@ -0,0 +1,79 @@ +// Table represents and manages the actual game. It accepts inputs from the server and tries to query the server when the player makes a move. +class Table{ + constructor(e, drag, socket) { + this.root = e; + this.drag = drag; + + this.root.addEventListener("mouseup", drag.stopDraggingAll.bind(drag)); + + //drag.addEventListener("dragstop", ); + + this.socket = socket; + + this.decks = []; + } + + openTable () + { + let state = this.root.getAttribute("state") + if((state == "close" || state == "closed") && state != "") { + this.root.setAttribute("state", "closed"); + setTimeout(this.root.setAttribute.bind(this.root), 50, "state", "open"); + } + } + + closeTable () + { + let state = this.root.getAttribute("state") + if(state != "close" && state != "closed") { + this.root.setAttribute("state", ""); + setTimeout(this.root.setAttribute.bind(this.root), 50, "state", "close"); + } + } + + handleClose () + { + this.reset(); + } + + reset () + { + while(this.root.firstElementChild != null) + this.root.firstElementChild.remove(); + + this.decks = []; + + this.closeTable(); + this.drag.stopDraggingAll(); + } + + /* Deck and card functions */ + newDeck(options) + { + var d = new Deck(options); + this.decks.push(d); + this.root.appendChild(d.e); + } + + newCard(data, deck = 0) + { + var c = new Card(data); + this.decks[deck].appendCard(c); + this.drag.addTarget(c.e); + } + + checkDeck(x, y) + { + for(let d of this.decks) + { + if(d.isInside(x, y)) + return true; + } + return false; + } + + dragCheck(cap) + { + console.log(cap); + } +} -- cgit v1.2.3