Registration, Login, Resume, Table Creation, Dark Style
This commit is contained in:
337
Public/game.js
337
Public/game.js
@ -1,15 +1,270 @@
|
||||
|
||||
// The web socket to connect to the server
|
||||
var socket = null;
|
||||
|
||||
function closeSocketIfNeeded() {
|
||||
if (socket) {
|
||||
socket.close()
|
||||
socket = null
|
||||
}
|
||||
}
|
||||
|
||||
function hideLoginWindow() {
|
||||
document.getElementById("signup-window").style.display = "none"
|
||||
}
|
||||
|
||||
function showLoginWindow() {
|
||||
document.getElementById("signup-window").style.display = "table"
|
||||
}
|
||||
|
||||
function setPlayerName(name) {
|
||||
document.getElementById("player-name").innerHTML = name
|
||||
}
|
||||
|
||||
function getPlayerName() {
|
||||
return document.getElementById("player-name").innerHTML
|
||||
}
|
||||
|
||||
function getLoginName() {
|
||||
return document.getElementById("user-name").value
|
||||
}
|
||||
|
||||
function clearLoginName() {
|
||||
document.getElementById("user-name").value = ""
|
||||
}
|
||||
|
||||
function getLoginPassword() {
|
||||
return document.getElementById("user-pwd").value
|
||||
}
|
||||
|
||||
function clearLoginPassword() {
|
||||
document.getElementById("user-pwd").value = ""
|
||||
}
|
||||
|
||||
function getSessionToken() {
|
||||
return localStorage.getItem('token')
|
||||
}
|
||||
|
||||
function setSessionToken(token) {
|
||||
localStorage.setItem('token', token)
|
||||
}
|
||||
|
||||
function deleteSessionToken() {
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
|
||||
function setLoginError(text) {
|
||||
document.getElementById("login-error").innerHTML = text
|
||||
}
|
||||
|
||||
function getTableName() {
|
||||
return document.getElementById("table-name-field").value
|
||||
}
|
||||
|
||||
function clearTableName() {
|
||||
return document.getElementById("table-name-field").value = ""
|
||||
}
|
||||
|
||||
function getTableVisibility() {
|
||||
return document.getElementById("table-public-checkbox").checked
|
||||
}
|
||||
|
||||
function setTableListContent(content) {
|
||||
document.getElementById("table-list").innerHTML = content
|
||||
}
|
||||
|
||||
function showBlankLoginScreen(text) {
|
||||
closeSocketIfNeeded()
|
||||
clearLoginPassword()
|
||||
clearLoginName()
|
||||
deleteSessionToken()
|
||||
showLoginWindow()
|
||||
setLoginError(text)
|
||||
}
|
||||
|
||||
async function registerUser() {
|
||||
let username = document.getElementById("user-name").value
|
||||
let password = document.getElementById("user-pwd").value
|
||||
errorField = document.getElementById("login-error")
|
||||
console.log("Registration started")
|
||||
performGetSessionTokenRequest("register")
|
||||
}
|
||||
|
||||
console.log("Registration started");
|
||||
async function deletePlayerAccount() {
|
||||
const name = getPlayerName()
|
||||
const password = getLoginPassword()
|
||||
|
||||
fetch("/create/user/" + username + "/" + password, { method: 'POST' })
|
||||
fetch("/player/delete/" + username, { method: 'POST', body: password })
|
||||
.then(function(response) {
|
||||
if (response.status == 200) { // Success
|
||||
return
|
||||
}
|
||||
if (response.status == 400) { // Bad request
|
||||
throw Error("The request had an error")
|
||||
}
|
||||
if (response.status == 401) { // Invalid session token
|
||||
throw Error("Please log in again")
|
||||
}
|
||||
if (response.status == 403) { // Forbidden
|
||||
throw Error("The password or name is incorrect")
|
||||
}
|
||||
if (response.status == 424) { // Failed dependency
|
||||
throw Error("The request couldn't be completed")
|
||||
}
|
||||
throw Error("Unexpected registration response: " + response.statusText)
|
||||
}).then(function() {
|
||||
showBlankLoginScreen("")
|
||||
console.log("Player deleted")
|
||||
}).catch(function(error) {
|
||||
closeSocketIfNeeded()
|
||||
deleteSessionToken()
|
||||
alert(error.message)
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
|
||||
async function loginUser() {
|
||||
console.log("Login started");
|
||||
performGetSessionTokenRequest("login")
|
||||
}
|
||||
|
||||
async function logoutUser() {
|
||||
const token = getSessionToken()
|
||||
if (token) {
|
||||
console.log("Logging out player")
|
||||
performLogoutRequest(token)
|
||||
} else {
|
||||
console.log("No player to log out")
|
||||
showBlankLoginScreen("")
|
||||
}
|
||||
}
|
||||
|
||||
async function performLogoutRequest(token) {
|
||||
fetch("/player/logout", { method: 'POST', body: token })
|
||||
.then(function(response) {
|
||||
if (response.status == 200) { // Success
|
||||
return
|
||||
}
|
||||
if (response.status == 400) { // Bad request
|
||||
throw Error("The request had an error")
|
||||
}
|
||||
throw Error("Unexpected logout response: " + response.statusText)
|
||||
}).then(function() {
|
||||
showBlankLoginScreen("")
|
||||
console.log("Player logged out")
|
||||
}).catch(function(error) {
|
||||
showBlankLoginScreen(error.message)
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
|
||||
function convertServerResponse(response) {
|
||||
if (response.status == 200) { // Success
|
||||
return response.text()
|
||||
}
|
||||
if (response.status == 400) { // Bad request
|
||||
throw Error("The request was malformed")
|
||||
}
|
||||
if (response.status == 403) { // Forbidden
|
||||
throw Error("Invalid username or password")
|
||||
}
|
||||
if (response.status == 406) { // notAcceptable
|
||||
throw Error("The password or name is too long")
|
||||
}
|
||||
if (response.status == 409) { // Conflict
|
||||
throw Error("A user with the same name is already registered")
|
||||
}
|
||||
if (response.status == 424) { // Failed dependency
|
||||
throw Error("The request couldn't be completed")
|
||||
}
|
||||
throw Error("Unexpected response: " + response.statusText)
|
||||
}
|
||||
|
||||
async function performGetSessionTokenRequest(type) {
|
||||
const username = getLoginName()
|
||||
const password = getLoginPassword()
|
||||
|
||||
console.log("Performing request " + type);
|
||||
fetch("/player/" + type + "/" + username, { method: 'POST', body: password })
|
||||
.then(convertServerResponse)
|
||||
.then(function(token) {
|
||||
setSessionToken(token)
|
||||
setPlayerName(username)
|
||||
hideLoginWindow()
|
||||
setLoginError("")
|
||||
console.log(type + " successful")
|
||||
performGetPublicTablesList(token)
|
||||
openSocket(token)
|
||||
}).catch(function(error) {
|
||||
setLoginError(error.message)
|
||||
console.log(error)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
async function loadExistingSession() {
|
||||
const token = getSessionToken()
|
||||
if (token) {
|
||||
console.log("Resuming session with token " + token)
|
||||
resumeSession(token)
|
||||
} else {
|
||||
console.log("No session to resume")
|
||||
showLoginWindow()
|
||||
}
|
||||
}
|
||||
|
||||
async function resumeSession(token) {
|
||||
fetch("/player/resume", { method: 'POST', body: token })
|
||||
.then(convertServerResponse)
|
||||
.then(function(name) {
|
||||
setPlayerName(name)
|
||||
hideLoginWindow()
|
||||
console.log("Session resumed")
|
||||
performGetPublicTablesList(token)
|
||||
openSocket(token)
|
||||
}).catch(function(error) {
|
||||
deleteSessionToken()
|
||||
setLoginError(error.message)
|
||||
showLoginWindow()
|
||||
console.log(error)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
async function openSocket(token) {
|
||||
socket = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/session/start")
|
||||
|
||||
socket.onopen = function(e) {
|
||||
socket.send(token);
|
||||
};
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
// TODO: Handle server data
|
||||
};
|
||||
|
||||
socket.onclose = function(event) {
|
||||
if (event.wasClean) {
|
||||
|
||||
} else {
|
||||
// e.g. server process killed or network down
|
||||
// event.code is usually 1006 in this case
|
||||
}
|
||||
};
|
||||
|
||||
socket.onerror = function(error) {
|
||||
// error.message
|
||||
};
|
||||
}
|
||||
|
||||
function createTable() {
|
||||
const tableName = getTableName()
|
||||
const isVisible = getTableVisibility()
|
||||
const token = getSessionToken()
|
||||
if (token) {
|
||||
performCreateTableRequest(token, tableName, isVisible)
|
||||
}
|
||||
}
|
||||
|
||||
async function performCreateTableRequest(token, name, visibility) {
|
||||
const vis = visibility ? "public" : "private";
|
||||
fetch("/table/create/" + vis + "/" + name, { method: 'POST', body: token })
|
||||
.then(function(response) {
|
||||
if (response.status == 200) { // Success
|
||||
return response.text()
|
||||
@ -17,36 +272,70 @@ async function registerUser() {
|
||||
if (response.status == 400) { // Bad request
|
||||
throw Error("The request had an error")
|
||||
}
|
||||
if (response.status == 409) { // Conflict
|
||||
throw Error("A user with the same name is already registered")
|
||||
if (response.status == 401) { // Token invalid
|
||||
showBlankLoginScreen("")
|
||||
return ""
|
||||
}
|
||||
throw Error("Unexpected response: " + response.statusText)
|
||||
}).then(function(text) {
|
||||
localStorage.setItem('token', text)
|
||||
hideLoginWindow()
|
||||
console.log("Registered")
|
||||
throw Error("Unexpected registration response: " + response.statusText)
|
||||
})
|
||||
.then(function(tableId) {
|
||||
if (tableId == "") {
|
||||
return;
|
||||
}
|
||||
clearTableName()
|
||||
console.log("Created table " + tableId)
|
||||
}).catch(function(error) {
|
||||
errorField.innerHTML = error.message
|
||||
showBlankLoginScreen(error.message)
|
||||
console.log(error)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
function loadExistingSession() {
|
||||
console.log("Checking to resume session");
|
||||
const token = localStorage.getItem('token');
|
||||
function refreshTables() {
|
||||
const token = getSessionToken()
|
||||
if (token) {
|
||||
console.log("Resuming session with token " + token);
|
||||
resumeSession(token);
|
||||
performGetPublicTablesList(token)
|
||||
} else {
|
||||
showBlankLoginScreen()
|
||||
}
|
||||
}
|
||||
|
||||
function resumeSession(token) {
|
||||
|
||||
localStorage.removeItem('token');
|
||||
hideLoginWindow()
|
||||
async function performGetPublicTablesList(token) {
|
||||
fetch("/tables/public", { method: 'POST', body: token })
|
||||
.then(convertServerResponse)
|
||||
.then(function(text) {
|
||||
const decoded = atob(text)
|
||||
const json = JSON.parse(decoded);
|
||||
const html = processTableList(json)
|
||||
setTableListContent(html)
|
||||
}).catch(function(error) {
|
||||
showBlankLoginScreen(error.message)
|
||||
console.log(error)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
function loginUser() {
|
||||
|
||||
function processTableList(tables) {
|
||||
var html = ""
|
||||
for (let i = 0, len = tables.length, text = ""; i < len; i++) {
|
||||
tableInfo = tables[i]
|
||||
html += "<div class=\"table-row\">" +
|
||||
"<button class=\"table-join-btn\" onclick=\"joinTable('" + tableInfo.id +
|
||||
"')\">Join</button><div class=\"table-title\">" + tableInfo.name +
|
||||
"</div><div class=\"table-subtitle\">Players: " + tableInfo.players.join(", ") + "</div></div>"
|
||||
}
|
||||
return html
|
||||
}
|
||||
|
||||
function joinTable(tableId) {
|
||||
const token = getSessionToken()
|
||||
if (token) {
|
||||
performJoinTableRequest(tableId, token)
|
||||
} else {
|
||||
showBlankLoginScreen()
|
||||
}
|
||||
}
|
||||
|
||||
async function performJoinTableRequest(tableId, token) {
|
||||
|
||||
}
|
@ -7,17 +7,38 @@
|
||||
<link rel='stylesheet' type='text/css' media='screen' href='style.css'>
|
||||
</head>
|
||||
<body>
|
||||
<div class="signup-backdrop" id="signup-window">
|
||||
<div class="signup-window-vertical">
|
||||
<div class="signup-window">
|
||||
<div id="top-bar">
|
||||
<div id="player-info">
|
||||
<div id="player-name"></div>
|
||||
<button id="logout-button" class="standard-button" onclick="logoutUser()">Log out</button>
|
||||
</div>
|
||||
<div class="table-list-bar">
|
||||
<input type="text" id="table-name-field" name="tablename" placeholder="Create new table..." required>
|
||||
<input type="checkbox" id="table-public-checkbox" name="public-table" checked="checked">
|
||||
<span id="table-public-label">Public</span>
|
||||
<button id="create-table-button" class="standard-button" onclick="createTable()">Create table</button>
|
||||
<button id="refresh-tables" class="standard-button" onclick="refreshTables()">Refresh</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="table-list">
|
||||
</div>
|
||||
|
||||
<div class="table-list-window" id="table-window">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="signup-window" id="signup-window">
|
||||
<div class="signup-window-vertical-center">
|
||||
<div class="signup-window-inner">
|
||||
<label for="usrname">Username</label>
|
||||
<input type="text" id="user-name" name="usrname" required>
|
||||
|
||||
<label for="psw">Password</label>
|
||||
<input type="password" id="user-pwd" name="psw" required>
|
||||
|
||||
<button class="login-buttons" onclick="registerUser()">Register</button>
|
||||
<button class="login-buttons" onclick="loginUser()">Log in</button>
|
||||
<button class="login-buttons standard-button" onclick="registerUser()">Register</button>
|
||||
<button class="login-buttons standard-button" onclick="loginUser()">Log in</button>
|
||||
<div id="login-error"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
168
Public/style.css
168
Public/style.css
@ -1,25 +1,57 @@
|
||||
:root {
|
||||
/* Color definitions for light mode */
|
||||
--button-color: rgb(255, 172, 39);
|
||||
--button-hover: rgb(255, 185, 72);
|
||||
--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);
|
||||
}
|
||||
|
||||
/* Style all input fields */
|
||||
|
||||
.standard-button {
|
||||
padding: 10px;
|
||||
background-color: var(--button-color);
|
||||
color: #000;
|
||||
border-style: hidden;
|
||||
border-radius: 5px;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.standard-button:hover {
|
||||
background-color: var(--button-hover);
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid var(--element-border);
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--standard-background);
|
||||
}
|
||||
|
||||
.signup-window input {
|
||||
width: 100%;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
html * {
|
||||
font-family:-apple-system, BlinkMacSystemFont, "SF Hello", "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
body, html {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
background-color: var(--standard-background);
|
||||
}
|
||||
|
||||
.signup-backdrop {
|
||||
background-color: #fff;
|
||||
.signup-window {
|
||||
background-color: var(--standard-background);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
@ -28,34 +60,142 @@ body, html {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.signup-window-vertical {
|
||||
.signup-window-vertical-center {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.signup-window {
|
||||
background-color: #f1f1f1;
|
||||
.signup-window-inner {
|
||||
background-color: var(--element-background);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 300px;
|
||||
border-radius: 10px;
|
||||
border-style: solid;
|
||||
border-width: thin;
|
||||
border-color: darkgray;
|
||||
border-color: var(--element-border);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.login-buttons {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#top-bar {
|
||||
height: 50px;
|
||||
background-color: var(--element-background);
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#player-info {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
height: 50px;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: auto auto;
|
||||
column-gap: 5px;
|
||||
}
|
||||
|
||||
#player-name {
|
||||
text-align: right;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
#logout-button {
|
||||
width: 80px;
|
||||
height: 34px;
|
||||
padding: 0px;
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.table-list-bar {
|
||||
position: absolute;
|
||||
width: 510px;
|
||||
height: 40px;
|
||||
top: 5px;
|
||||
left: 10px;
|
||||
display: grid;
|
||||
grid-template-columns: 200px 30px 50px 140px 90px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
#table-name-field {
|
||||
width: 100%;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
#table-public-checkbox {
|
||||
grid-column: 2;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
#table-public-label {
|
||||
grid-column: 3;
|
||||
}
|
||||
|
||||
#create-table-button {
|
||||
width: 120px;
|
||||
grid-column: 4;
|
||||
padding: 0px;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
#refresh-tables {
|
||||
width: 90px;
|
||||
grid-column: 5;
|
||||
padding: 0px;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
#table-list {
|
||||
margin: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
padding: 10px;
|
||||
background-color: #ccc;
|
||||
color: #000;
|
||||
margin-top: 10px;
|
||||
background-color: var(--element-background);
|
||||
border-style: hidden;
|
||||
border-radius: 5px;
|
||||
margin-top: 5px;
|
||||
font-size: medium;
|
||||
display: grid;
|
||||
grid-template-columns: 100px auto;
|
||||
grid-template-rows: auto auto;
|
||||
column-gap: 10px;
|
||||
/* justify-items: left; */
|
||||
}
|
||||
|
||||
.table-join-btn {
|
||||
padding: 10px;
|
||||
width: 100px;
|
||||
background-color: var(--button-color);
|
||||
color: var(--button-text);
|
||||
border-style: hidden;
|
||||
border-radius: 5px;
|
||||
font-size: medium;
|
||||
grid-column: 1;
|
||||
grid-row: 1 / span 2;
|
||||
}
|
||||
|
||||
.table-join-btn:hover {
|
||||
background-color: var(--button-hover);
|
||||
}
|
||||
|
||||
.table-title {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.login-buttons:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
.table-subtitle {
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
font-size: small;
|
||||
}
|
||||
|
Reference in New Issue
Block a user