<html>
<head>
<meta charset="utf-8" />
- <script src="main.js"></script>
+ <link rel="stylesheet" href="./style.css" />
+ <script type="module" src="main.js"></script>
</head>
<body>
- <h1>Pokerwave</h1>
+ <div id="login-background">
+ <div id="login">
+ <label id="username-label" for="username">username</label>
+ <input id="username-input" />
+ <label id="password-label" for="password">password</label>
+ <input id="password-input" type="password" />
+ <button id="login-button">Sign In</button>
+ <p id="login-error"></p>
+ </div>
+ </div>
+ <div id="game-tile-background">
+ <!--<div class="game-list">
+ <div class="game-summary">
+ <div class="game-id">#2</div>
+ <div class="game-title">Poker chat</div>
+ <div class="stub"></div>
+ <div class="game-format">Chatroom</div>
+ <ul class="game-settings">
+ <li>max_players: 4</li>
+ </ul>
+ </div>
+ <div class="game-summary">
+ <div class="game-id">#1</div>
+ <div class="game-title">General discussion</div>
+ <div class="game-format">Chatroom</div>
+ <ul class="game-settings">
+ <li>max_players: 8</li>
+ </ul>
+ </div>
+ <div class="game-summary">
+ <div class="game-id">#0</div>
+ <div class="game-title">Test chatroom</div>
+ <div class="game-format">Chatroom</div>
+ <ul class="game-settings">
+ <li>max_players: 2</li>
+ </ul>
+ </div>
+ </div>-->
+ </div>
</body>
</html>
-"use strict";
+import { Auth } from "./modules/auth.js";
+import { Socket } from "./modules/socket.js";
-var socket;
+var sockets = [];
-function socket_open() {
- let proto = window.location.protocol === "https:" ? "wss:" : "ws:";
- let uri = proto + "//" + window.location.host + "/api";
- socket = new WebSocket(uri);
- socket.onopen = socket_onopen;
- socket.onmessage = socket_onmessage;
+function hide_login() {
+ document.getElementById("login-background").classList.add("hidden");
}
-function socket_onopen() {
- console.log("WebSocket connected");
- socket_send({type: "Login", username: "geoff"});
-}
-
-function socket_send(object) {
- console.log(">>", object);
- socket.send(JSON.stringify(object));
+function show_login(error) {
+ if (error) {
+ document.getElementById("login-error").classList.remove("hidden");
+ document.getElementById("login-error").innerText = error;
+ } else {
+ document.getElementById("login-error").classList.add("hidden");
+ document.getElementById("login-error").innerText = "";
+ }
+ document.getElementById("login-background").classList.remove("hidden");
+ document.getElementById("login-button").onclick = login;
+ document.getElementById("password-input").onchange = login;
}
-function socket_onmessage(msg) {
- var message = JSON.parse(msg.data);
- console.log("<<", message);
- switch (message.type) {
- case "LoginAuthChallenge":
- socket_send({type: "LoginAuthResponse", signature: "hunter2"});
- break;
+function login() {
+ var username = document.getElementById("username-input").value;
+ var password = document.getElementById("password-input").value;
+ delete document.getElementById("login-button").onclick;
+ delete document.getElementById("password-input").onchange;
+ var auth = new Auth(username, password);
+ for (var socket of sockets) {
+ socket.login(auth);
}
}
window.onload = function() {
- socket_open();
+ var container = document.getElementById("game-tile-background");
+ sockets.push(new Socket(container));
+ show_login();
};
--- /dev/null
+export class Auth {
+ constructor(username, password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ login_message() {
+ return {
+ type: "Login",
+ username: this.username
+ };
+ }
+
+ challenge_response(challenge) {
+ return {
+ type: "LoginAuthResponse",
+ signature: this.password
+ };
+ }
+}
--- /dev/null
+export class Socket {
+ constructor(container) {
+ this.container = container;
+ let proto = window.location.protocol === "https:" ? "wss:" : "ws:";
+ let uri = proto + "//" + window.location.host + "/api";
+ this.socket = new WebSocket(uri);
+ this.socket.onopen = this.onopen.bind(this);
+ this.socket.onmessage = this.onmessage.bind(this);
+ this.socket.onclose = this.onclose.bind(this);
+ this.state = "Connecting";
+ }
+
+ onopen() {
+ console.log("WebSocket connected");
+ this.state = "Connected";
+ }
+
+ send(object) {
+ console.log(">>", object);
+ this.socket.send(JSON.stringify(object));
+ }
+
+ login(auth) {
+ this.auth = auth;
+ this.send(auth.login_message());
+ this.state = "LoginSent";
+ }
+
+ onmessage(msg) {
+ var message = JSON.parse(msg.data);
+ console.log("<<", message);
+ switch (message.type) {
+ case "LoginAuthChallenge":
+ this.send(this.auth.challenge_response(message.challenge));
+ this.state = "LoginAuthResponseSent";
+ break;
+ case "LoginFailure":
+ this.auth = null;
+ this.show_login(message.reason);
+ this.state = "Connected";
+ break;
+ case "LoginSuccess":
+ this.hide_login();
+ this.send({type: "JoinLobby", filter: ""});
+ this.state = "JoinLobbySent";
+ break;
+ case "JoinLobbySuccess":
+ this.create_game_list();
+ this.games = message.games;
+ this.redraw_games();
+ this.state = "InLobby";
+ break;
+ case "AddGame":
+ this.add_game(message.game);
+ break;
+ case "LogoutSuccess":
+ this.auth = null;
+ this.show_login();
+ this.state = "Connected";
+ break;
+ }
+ }
+
+ hide_login() {
+ document.getElementById("login-background").classList.add("hidden");
+ }
+
+ show_login(error) {
+ if (error) {
+ document.getElementById("login-error").classList.remove("hidden");
+ document.getElementById("login-error").innerText = error;
+ } else {
+ document.getElementById("login-error").classList.add("hidden");
+ document.getElementById("login-error").innerText = "";
+ }
+ document.getElementById("login-background").classList.remove("hidden");
+ document.getElementById("login-button").onclick = login;
+ document.getElementById("password-input").onchange = login;
+ }
+
+ game_element(game) {
+ console.log("getting game element for ", game);
+ var game_element = document.createElement("div");
+ game_element.classList.add("game-summary");
+ var id = document.createElement("div");
+ id.innerText = "#" + game.id;
+ id.classList.add("game-id");
+ game_element.appendChild(id);
+ var title = document.createElement("div");
+ title.innerText = game.settings.format; // TODO
+ title.classList.add("game-title");
+ game_element.appendChild(title);
+ var format = document.createElement("div");
+ format.innerText = game.settings.format;
+ format.classList.add("game-format");
+ game_element.appendChild(format);
+ var settings = document.createElement("ul");
+ settings.classList.add("game-settings");
+ for (var setting of Object.keys(game.settings)) {
+ if (setting !== "id" && setting !== "title" && setting !== "format") {
+ var li = document.createElement("li");
+ li.innerText = setting + ": " + game.settings[setting];
+ settings.appendChild(li);
+ }
+ }
+ game_element.appendChild(settings);
+ return game_element;
+ }
+
+ add_game(game) {
+ this.games.push(game);
+ var game_element = this.game_element(game);
+ this.game_list.prepend(game_element);
+ }
+
+ create_game_list() {
+ this.container.textContent = "";
+ this.game_list = document.createElement("div");
+ this.game_list.classList.add("game-list");
+ this.container.append(this.game_list);
+ }
+
+ redraw_games() {
+ for (var game of this.games) {
+ var game_element = this.game_element(game);
+ this.game_list.prepend(game_element);
+ }
+ }
+
+ onclose() {
+ console.error("Websocket closed unexpectedly");
+ this.state = "Disconnected";
+ }
+}
--- /dev/null
+html, body {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+}
+
+.hidden {
+ display: none !important;
+}
+
+#login-background {
+ background-color: rgba(0, 0, 100, 0.5);
+ width: 100%;
+ height: 100%;
+ position: fixed;
+ display: grid;
+ grid: 1fr 1fr 1fr / 1fr 1fr 1fr;
+}
+
+#login {
+ grid-column: 2 / 3;
+ grid-row: 2 / 3;
+ background-color: skyblue;
+ border-radius: 2vmax;
+ padding: 4vmax;
+ display: grid;
+ grid: 1fr;
+ font-size: 4vmax;
+}
+
+#login > label {
+ font-family: monospace;
+}
+
+#login > input {
+ font-size: inherit;
+ margin-bottom: 1vmax;
+}
+
+#login > button {
+ font-size: inherit;
+ margin-top: 2vmax;
+}
+
+#login > #login-error {
+ font-size: 2vmax;
+ color: red;
+ margin-bottom: 0;
+}
+
+#game-tile-background {
+ width: 100%;
+ height: 100%;
+ display: grid;
+ grid: 1fr / 1fr;
+}
+
+.game-list {
+ width: 100%;
+ display: grid;
+ grid-auto-rows: 30vw;
+}
+
+.game-summary {
+ border: 1px solid grey;
+ border-bottom: none;
+ font-family: sans;
+ font-size: 4vw;
+ display: grid;
+ grid: 'id title blank'
+ 'format format format'
+ 'settings settings settings'
+ 'settings settings settings';
+}
+
+.game-id {
+ font-style: italic;
+ color: grey;
+ grid-area: id;
+}
+
+.game-title {
+ text-align: center;
+ font-weight: bold;
+ grid-area: title;
+}
+
+.game-format {
+ text-align: left;
+ margin-left: 5vw;
+ grid-area: format;
+}
+
+.game-settings {
+ grid-area: settings;
+}