Show cards on client side

This commit is contained in:
Christoph Hagen 2021-12-01 22:50:42 +01:00
parent cdf079698e
commit 4fe71136a2
5 changed files with 408 additions and 41 deletions

View File

@ -60,6 +60,12 @@ async function performLeaveTableRequest(token) {
.then(function(value) {})
}
async function performDealCardsRequest(token) {
return fetch("/deal", { method: 'POST', body: token })
.then(convertServerResponse)
.then(function(value) {})
}
function convertServerResponse(response) {
switch (response.status) {
case 200: // Success

View File

@ -2,38 +2,65 @@
* This file acts as an abstraction layer between HTML and JS.
*/
function hideLoginWindow() {
document.getElementById("signup-window").style.display = "none"
var playerName = ""
function setDisplayStyle(id, style) {
document.getElementById(id).style.display = style
}
function showLoginWindow() {
document.getElementById("signup-window").style.display = "table"
}
function hideTableListElements() {
document.getElementById("table-list-bar").style.display = "none"
document.getElementById("table-list").style.display = "none"
function showLoginElements() {
setDisplayStyle("login-window", "table")
setDisplayStyle("top-bar", "none")
setDisplayStyle("table-list-bar", "none")
setDisplayStyle("table-list", "none")
setDisplayStyle("game-bar", "none")
setDisplayStyle("table-players", "none")
setDisplayStyle("player-cards", "none")
}
function showTableListElements() {
document.getElementById("table-list-bar").style.display = "grid"
document.getElementById("table-list").style.display = "inherit"
setDisplayStyle("login-window", "none")
setDisplayStyle("top-bar", "inherit")
setDisplayStyle("table-list-bar", "grid")
setDisplayStyle("table-list", "inherit")
setDisplayStyle("game-bar", "none")
setDisplayStyle("table-players", "none")
setDisplayStyle("player-cards", "none")
}
function showGameElements() {
document.getElementById("game-bar").style.display = "grid"
setDisplayStyle("login-window", "none")
setDisplayStyle("top-bar", "inherit")
setDisplayStyle("table-list-bar", "none")
setDisplayStyle("table-list", "none")
setDisplayStyle("game-bar", "grid")
setDisplayStyle("table-players", "grid")
setDisplayStyle("player-cards", "grid")
}
function hideGameElements() {
document.getElementById("game-bar").style.display = "none"
function showConnectedState() {
const label = document.getElementById("table-connected-label")
label.innerHTML = "Connected"
label.style.color = "var(--text-color)"
}
function showDisconnectedState() {
const label = document.getElementById("table-connected-label")
label.innerHTML = "Disconnected"
label.style.color = "var(--alert-color)"
}
function showDealButton() {
setDisplayStyle("deal-button", "inherit")
}
function hideDealButton() {
setDisplayStyle("deal-button", "none")
}
function setPlayerName(name) {
document.getElementById("player-name").innerHTML = name
}
function getPlayerName() {
return document.getElementById("player-name").innerHTML
playerName = name
}
function getLoginName() {
@ -83,3 +110,41 @@ function getTableVisibility() {
function setTableListContent(content) {
document.getElementById("table-list").innerHTML = content
}
function setTablePlayerInfo(nr, name, connected, active) {
const infoElement = "table-player-name" + nr.toString()
const connectionElement = "table-player-state" + nr
const nameElement = document.getElementById(infoElement)
if (name == "") {
nameElement.innerHTML = "Empty"
nameElement.style.color = "var(--secondary-text-color)"
setDisplayStyle(connectionElement, "none")
return
}
nameElement.innerHTML = name
nameElement.style.color = active ? "var(--button-color)" : "var(--text-color)"
if (connected) {
setDisplayStyle(connectionElement, "none")
} else {
setDisplayStyle(connectionElement, "inherit")
}
}
function setTableCard(index, card) {
const id = "table-player-card" + index.toString()
setCard(id, card)
}
function setHandCard(index, card, playable) {
const id = "player-card" + index.toString()
setCard(id, card)
document.getElementById(id).disabled = true
}
function setCard(id, card) {
if (card == "") {
document.getElementById(id).style.backgroundColor = "var(--element-background)"
} else {
document.getElementById(id).style.backgroundImage = "url('/cards/" + card + ".jpeg')"
}
}

View File

@ -10,9 +10,12 @@ function closeSocketIfNeeded() {
}
}
function didLeaveTable() {
tableId = ""
}
function didCloseSocket() {
socket = null
tableId = ""
}
function setTableId(table) {
@ -21,25 +24,20 @@ function setTableId(table) {
function showBlankLoginScreen(text) {
closeSocketIfNeeded()
didLeaveTable()
clearLoginPassword()
clearLoginName()
deleteSessionToken()
showLoginWindow()
showLoginElements()
setLoginError(text)
}
function showTableList() {
showTableListElements()
hideLoginWindow()
}
function showGame(tableId) {
setTableId(tableId)
const token = getSessionToken()
if (token) {
openSocket(token)
hideTableListElements()
showGameElements()
openSocket(token)
// TODO: Show interface
console.log("Show table " + tableId)
} else {
@ -62,7 +60,7 @@ function registerUser() {
.then(function(token) {
setSessionToken(token)
setPlayerName(username)
showTableList()
showTableListElements()
loadCurrentTable(token)
}).catch(function(error) {
setLoginError(error.message)
@ -79,6 +77,7 @@ function deletePlayerAccount() {
console.log("Player deleted")
} else {
closeSocketIfNeeded()
didLeaveTable()
deleteSessionToken()
alert(error)
console.log(error)
@ -101,7 +100,7 @@ function loginUser() {
.then(function(token) {
setSessionToken(token)
setPlayerName(username)
showTableList()
showTableListElements()
loadCurrentTable(token)
}).catch(function(error) {
setLoginError(error.message)
@ -129,7 +128,7 @@ function loadExistingSession() {
resumeSessionRequest(token)
.then(function(name) {
setPlayerName(name)
showTableList()
showTableListElements()
loadCurrentTable(token)
}).catch(function(error) {
showBlankLoginScreen(error.message)
@ -143,9 +142,11 @@ function loadCurrentTable(token) {
performGetCurrentTableRequest(token)
.then(function(tableId) {
if (tableId == "") {
didLeaveTable()
refreshTables()
return
}
console.log("Loaded table " + tableId)
showGame(tableId)
}).catch(function(error) {
showBlankLoginScreen(error.message)
@ -192,8 +193,10 @@ function leaveTable() {
if (token) {
performLeaveTableRequest(token)
.then(function() {
showTableList()
hideGameElements()
showTableListElements()
closeSocketIfNeeded()
didLeaveTable()
refreshTables()
})
.catch(function(error) {
showBlankLoginScreen(error.message)
@ -208,22 +211,26 @@ function openSocket(token) {
socket.onopen = function(e) {
socket.send(token);
showConnectedState()
};
socket.onmessage = function(event) {
// TODO: Handle server data
//event.data
handleServerUpdates(event.data)
};
socket.onclose = function(event) {
if (event.wasClean) {
didCloseSocket()
} else {
// e.g. server process killed or network down
// event.code is usually 1006 in this case
// TODO: Retry several times to open socket,
// stop after too many failed attempts
}
didCloseSocket()
showDisconnectedState()
};
socket.onerror = function(error) {
@ -231,6 +238,39 @@ function openSocket(token) {
};
}
function handleServerUpdates(data) {
const info = JSON.parse(data.substring(1))
if (data.startsWith("t")) {
handleTableInfoUpdate(info)
} else if (data.startsWith("c")) {
handleCardInfoUpdate(info)
} else {
console.log("Unhandled update: " + data)
}
}
function handleTableInfoUpdate(info) {
for (let i = 0, len = info.players.length; i < len; i += 1) {
const player = info.players[i]
// TODO: Mark active player
setTablePlayerInfo(i + 1, player.name, player.connected, false)
}
if (info.tableIsFull) {
showDealButton()
} else {
hideDealButton()
}
}
function handleCardInfoUpdate(info) {
for (let i = 0, len = info.cards.length; i < len; i += 1) {
setHandCard(i+1, info.cards[i].card, info.cards[i].playable)
}
for (let i = 0, len = info.tableCards.length; i < len; i += 1) {
setTableCard(i+1, info.tableCards[i])
}
}
function refreshTables() {
const token = getSessionToken()
if (token) {
@ -240,7 +280,6 @@ function refreshTables() {
setTableListContent(html)
}).catch(function(error) {
showBlankLoginScreen(error.message)
return
})
} else {
showBlankLoginScreen()
@ -258,8 +297,25 @@ function processTableList(tables) {
html += "<button class=\"table-join-btn\" disabled>Full</button>"
}
html += "<div class=\"table-title\">" + tableInfo.name + "</div>"
html += "<div class=\"table-subtitle\">Players: " + tableInfo.players.join(", ") + "</div>"
if (tableInfo.players.length == 0) {
html += "<div class=\"table-subtitle\">No players</div>"
} else {
const names = tableInfo.players.map(function(player) { return player.name }).join(", ")
html += "<div class=\"table-subtitle\">Players: " + names + "</div>"
}
html += "</div>" // table-row
}
return html
}
function dealCards() {
const token = getSessionToken()
if (token) {
performDealCardsRequest(token)
.catch(function(error) {
showBlankLoginScreen(error.message)
})
} else {
showBlankLoginScreen()
}
}

View File

@ -24,11 +24,50 @@
</div>
<div id="game-bar">
<button id="leave-table" class="standard-button" onclick="leaveTable()">Leave table</button>
<span id="table-connected-label">Disconnected</span>
</div>
</div>
<div id="main">
<div id="main-spacer"></div>
<div id="table-list">
</div>
<div id="table-players">
<button id="deal-button" class="standard-button" onclick="dealCards()">Deal cards</button>
<button id="bid-button" class="standard-button" onclick="increaseBid()">Bid</button>
<button id="fold-button" class="standard-button" onclick="fold()">Fold</button>
<div id="table-player-card1" class="table-card"></div>
<div id="table-player-card2" class="table-card"></div>
<div id="table-player-card3" class="table-card"></div>
<div id="table-player-card4" class="table-card"></div>
<div id="table-player-info1">
<div id="table-player-name1">Player 1</div>
<div id="table-player-state1" class="player-connection-state">Offline</div>
</div>
<div id="table-player-info2">
<div id="table-player-name2">Player 2</div>
<div id="table-player-state2" class="player-connection-state">Offline</div>
</div>
<div id="table-player-info3">
<div id="table-player-name3">Player 3</div>
<div id="table-player-state3" class="player-connection-state">Offline</div>
</div>
<div id="table-player-info4">
<div id="table-player-name4">Player 4</div>
<div id="table-player-state4" class="player-connection-state">Offline</div>
</div>
</div>
<div id="player-cards">
<button id="player-card1" class="player-card" disabled></button>
<button id="player-card2" class="player-card" disabled></button>
<button id="player-card3" class="player-card" disabled></button>
<button id="player-card4" class="player-card" disabled></button>
<button id="player-card5" class="player-card" disabled></button>
<button id="player-card6" class="player-card" disabled></button>
<button id="player-card7" class="player-card" disabled></button>
<button id="player-card8" class="player-card" disabled></button>
</div>
</div>
<div id="login-window">
<div id="login-window-vertical-center">

View File

@ -1,13 +1,16 @@
:root {
/* Color definitions for light mode */
--button-color: rgb(255, 172, 39);
--button-hover: rgb(255, 185, 72);
--button-color: rgb(233, 144, 0);
--button-hover: rgb(255, 191, 89);
--button-disabled: rgb(128, 88, 24);
--button-text: rgb(0,0,0);
--standard-background: rgb(54, 54, 54);
--element-background: rgb(42, 42, 42);
--element-border: rgb(27, 27, 27);
--text-color: rgb(255,255,255);
--secondary-text-color: rgb(27, 27, 27);
--card-color: rgb(255,255,255);
--alert-color: rgb(255,0,0);
}
/* Style all input fields */
@ -47,10 +50,15 @@ html * {
body, html {
min-height: 100%;
height: 100%;
width: 100%;
margin: 0px;
background-color: var(--standard-background);
}
body {
position: absolute;
}
#login-window {
background-color: var(--standard-background);
height: 100%;
@ -91,15 +99,19 @@ body, html {
height: 50px;
background-color: var(--element-background);
padding: 0px;
z-index: 1;
width: 100%;
position: absolute;
}
#player-info {
position: absolute;
right: 8px;
height: 50px;
width: 205px;
display: grid;
align-items: center;
grid-template-columns: auto auto;
grid-template-columns: 120px 80px;
column-gap: 5px;
}
@ -107,6 +119,7 @@ body, html {
text-align: right;
grid-column: 1;
padding-right: 5px;
width: 120px;
}
#logout-button {
@ -164,12 +177,12 @@ body, html {
#game-bar {
position: absolute;
width: 120px;
width: 270px;
height: 40px;
top: 5px;
left: 10px;
display: none;
grid-template-columns: 1200px;
grid-template-columns: 120px 140px;
column-gap: 10px;
align-items: center;
justify-content: center;
@ -183,6 +196,26 @@ body, html {
height: 34px;
}
#table-connected-label {
grid-column: 2;
width: 140px;
}
#main {
height: 100%;
max-height: 100%;
width: 100%;
overflow: scroll;
}
#main-spacer {
height: 50px;
position: relative;
top: 0px;
width: 100%;
}
#table-list {
margin: 20px;
padding-right: 20px;
@ -236,3 +269,171 @@ body, html {
grid-row: 2;
font-size: small;
}
#table-players {
display: none;
margin-top: 20px;
margin-left: auto;
margin-right: auto;
width: 549px;
height: 437px;
grid-template-columns: 150px 71px 36px 35px 36px 71px 150px;
grid-template-rows: 111px 76px 35px 76px 111px;
column-gap: 0px;
row-gap: 0px;
align-items: center;
}
#deal-button {
display: none;
grid-column: 7;
grid-row: 5;
}
#fold-button {
display: none;
grid-column: 1;
grid-row: 5;
}
#bid-button {
display: none;
grid-column: 7;
grid-row: 5;
}
.table-card {
height: 187px;
border-radius: 17px;
background-color: var(--element-background);
}
#table-player-card1 { /* bottom */
grid-column: 3 / span 3;
grid-row: 4 / span 2;
z-index: 2;
}
#table-player-card2 { /* left */
grid-column: 2 / span 2;
grid-row: 2 / span 3;
z-index: 1;
}
#table-player-card3 { /* top */
grid-column: 3 / span 3;
grid-row: 1 / span 2;
z-index: 4;
}
#table-player-card4 { /* right */
grid-column: 5 / span 2;
grid-row: 2 / span 3;
z-index: 3;
}
#table-player-info1 { /* bottom */
grid-column: 1 / span 2;
grid-row: 5;
font-size: large;
text-align: right;
margin-right: 15px;
margin-top: 50px;
}
#table-player-info2 { /* left */
grid-column: 1;
grid-row: 3;
font-size: large;
text-align: right;
margin-right: 15px;
}
#table-player-info3 { /* top */
grid-column: 1 / span 2;
grid-row: 1;
font-size: large;
text-align: right;
margin-right: 15px;
margin-bottom: 50px;
}
#table-player-info4 { /* right */
grid-column: 7;
grid-row: 3;
font-size: large;
margin-left: 15px;
}
.player-connection-state {
font-size: x-small;
color: var(--alert-color);
}
#table-player-state1 {
display: none;
}
#table-player-state2 {
display: none;
}
#player-cards {
display: none;
margin-left: auto;
margin-right: auto;
width: 923px;
grid-template-columns: 111px 111px 111px 111px 111px 111px 111px 111px;
column-gap: 5px;
margin-top: 10px;
}
.player-card {
width: 111px;
height: 191px;
border: 2px solid var(--standard-background);
background-color: var(--element-background);
border-radius: 17px;
transition-duration: 0.2s;
}
.player-card:disabled,
.player-card[disabled] {
cursor: not-allowed;
}
.player-card:hover:enabled {
border-color: var(--button-hover);
}
#player-card1 {
grid-column: 1;
}
#player-card2 {
grid-column: 2;
}
#player-card3 {
grid-column: 3;
}
#player-card4 {
grid-column: 4;
}
#player-card5 {
grid-column: 5;
}
#player-card6 {
grid-column: 6;
}
#player-card7 {
grid-column: 7;
}
#player-card8 {
grid-column: 8;
}