Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- index.html
- global.js
- sections/
- login/
- login.html
- login.js
- top_navbar/
- top_navbar.html
- server_interface/
- server_interface.js
- styles/
- cardshifter.css
- utils/
- formatDate.js
- loadHtml.js
- logDebugMessage.js
- <!DOCTYPE html>
- <html>
- <head>
- <title>Cardshifter</title>
- <!-- Bootstrap -->
- <link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" />
- <!-- Local styles -->
- <link rel="stylesheet" href="styles/cardshifter.css" />
- <!-- Local JavaScript -->
- <script src="global.js"></script>
- <script src="server_interface/server_interface.js"></script>
- <script src="utils/loadHtml.js"></script>
- <script src="utils/formatDate.js"></script>
- <script src="utils/logDebugMessage.js"></script>
- <!-- Local Section JavaScript -->
- <script src="sections/login/login.js"></script>
- <!-- Favicon links -->
- <link rel="apple-touch-icon" sizes="57x57" href="images/favicon/apple-icon-57x57.png" />
- <link rel="apple-touch-icon" sizes="60x60" href="images/favicon/apple-icon-60x60.png" />
- <link rel="apple-touch-icon" sizes="72x72" href="images/favicon/apple-icon-72x72.png" />
- <link rel="apple-touch-icon" sizes="76x76" href="images/favicon/apple-icon-76x76.png" />
- <link rel="apple-touch-icon" sizes="114x114" href="images/favicon/apple-icon-114x114.png" />
- <link rel="apple-touch-icon" sizes="120x120" href="images/favicon/apple-icon-120x120.png" />
- <link rel="apple-touch-icon" sizes="144x144" href="images/favicon/apple-icon-144x144.png" />
- <link rel="apple-touch-icon" sizes="152x152" href="images/favicon/apple-icon-152x152.png" />
- <link rel="apple-touch-icon" sizes="180x180" href="images/favicon/apple-icon-180x180.png" />
- <link rel="icon" type="image/png" sizes="192x192" href="images/favicon/android-icon-192x192.png" />
- <link rel="icon" type="image/png" sizes="32x32" href="images/favicon/favicon-32x32.png" />
- <link rel="icon" type="image/png" sizes="96x96" href="images/favicon/favicon-96x96.png" />
- <link rel="icon" type="image/png" sizes="16x16" href="images/favicon/favicon-16x16.png" />
- <link rel="manifest" href="images/favicon/manifest.json" />
- <meta name="msapplication-TileColor" content="#ffffff" />
- <meta name="msapplication-TileImage" content="images/favicon/ms-icon-144x144.png" />
- <meta name="theme-color" content="#ffffff" />
- </head>
- <body>
- <!-- Top navigation bar -->
- <div id="top_navbar_container">
- <script>
- const navbarContainerId = "top_navbar_container";
- const navbarFilePath = "sections/top_navbar/top_navbar.html";
- loadHtml(navbarContainerId, navbarFilePath)
- .then(function() {
- if (DEBUG) {
- logDebugMessage(`"${navbarFilePath}" loaded OK!`);
- }
- });
- </script>
- </div>
- <div class="csh-body">
- <div id="login_container">
- <script>
- const loginContainerId = "login_container";
- const loginFilePath = "sections/login/login.html";
- loadHtml(loginContainerId, loginFilePath)
- .then(function() {
- loginHandler();
- if (DEBUG) {
- logDebugMessage(`"${loginFilePath}" loaded OK!`);
- }
- });
- </script>
- </div>
- </div>
- </body>
- </html>
- /*
- * This file is for global values to be used throughout the site.
- */
- 'use strict';
- /*
- * Setting to `true` will log messages in the browser console
- * to help in debugging and keeping track of what is happening on the page.
- * This should be set to `false` on the public client.
- */
- const DEBUG = true;
- /*
- * Port number used for WebSocket.
- */
- const WS_PORT = 4243;
- /*
- * List of game server names and WebSocket URIs.
- */
- const GAME_SERVERS = {
- "localhost" : `ws://127.0.0.1:${WS_PORT}`,
- "dwarftowers.com" : `ws://dwarftowers.com:${WS_PORT}`,
- "zomis.net" : `ws://stats.zomis.net:${WS_PORT}`,
- "Other" : ""
- };
- /**
- * Default date format for the application.
- * @type String
- */
- const DEFAULT_DATE_FORMAT = "yyyy/MM/dd hh:mm:ss";
- <div id="login">
- <h4>Please log in to continue.</h4>
- <form name="login_form" id="login_form" class="login-form">
- <div id="login_server_select_container" class="form-group">
- <label for="login_server_list" aria-label="Server">Server:</label>
- <select name="login_server_list" id="login_server_list" class="form-control">
- </select>
- <div id="login_server_other_container" class="form-group" style="display : none">
- <label for="login_server_other_input">Other Server:</label>
- <input name="login_server_other_input" id="login_server_other_input" type="text" class="form-control" />
- <input type="button" name="test_login_server_other" id="test_login_server_other" class="btn" value="Test connection" />
- </div>
- <input readonly name="server_loading_display" id="server_connecting" class="form-control" style="background-color: #DDD; display: none" />
- <label for="login_secure">Is secure server:</label>
- <input name="login_secure" id="login_secure" type="checkbox" value="secure" />
- <span id="login_server_connection_status" class="label" style="display: block; text-align: left"></span>
- </div>
- <div id="login_username_container" class="form-group">
- <label for="login_username">Username:</label>
- <input name="login_username" id="login_username" type="text" class="form-control" placeholder="Enter name..." />
- </div>
- <div class="form-group">
- <input type="button" name="login_submit" id="login_submit" type="button" class="btn btn-success" value="Log in" />
- </div>
- </form>
- </div>
- /* global GAME_SERVERS, DEBUG, CardshifterServerAPI, DEFAULT_DATE_FORMAT */
- const loginHandler = function() {
- const serverSelectContainer = document.getElementById("login_server_select_container");
- const serverSelect = serverSelectContainer.querySelector("#login_server_list");
- const serverOtherInputContainer = serverSelectContainer.querySelector("#login_server_other_container");
- const serverLoading = serverSelectContainer.querySelector("#server_connecting");
- const connStatusMsg = serverSelectContainer.querySelector("#login_server_connection_status");
- let currentServerHasValidConnection = null;
- /**
- * Adds options to the server selection based on GAME_SERVERS global.
- * @returns {undefined}
- */
- const populateServerSelect = function() {
- for (let key in GAME_SERVERS) {
- if (GAME_SERVERS.hasOwnProperty(key)) {
- const option = document.createElement("option");
- option.text = key;
- option.value = GAME_SERVERS[key];
- serverSelect.add(option);
- }
- }
- };
- /**
- * Tests the WebSocket connection to a server and displays a message on the page
- * to give the user information about the connection status.
- * @returns {undefined}
- */
- const testWebsocketConnection = function() {
- const serverUri = serverSelect.value;
- const isSecure = false;
- let msgText = "";
- if (serverUri) {
- displayConnStatus("connecting", serverUri);
- /**
- * Test WebSocket connection and display status if successful.
- * @returns {undefined}
- */
- const onReady = function() {
- makeServerSelectReadWrite();
- msgText = displayConnStatus("success", serverUri);
- if (DEBUG) { logDebugMessage(msgText); }
- currentServerHasValidConnection = true;
- };
- /**
- * Test WebSocket connection and display status if failed.
- * @returns {undefined}
- */
- const onError = function() {
- makeServerSelectReadWrite();
- msgText = displayConnStatus("failure", serverUri);
- if (DEBUG) { logDebugMessage(msgText); }
- currentServerHasValidConnection = false;
- };
- CardshifterServerAPI.init(serverUri, isSecure, onReady, onError);
- makeServerSelectReadOnly(serverUri);
- }
- else {
- displayConnStatus("unknown", serverUri);
- }
- };
- /**
- * Displays connection status in the page.
- * @param {string} status - Keyword representing the connection status
- * @param {type} serverUri - The URI of the server the client is connecting to
- * @returns {String} - The message text, largely for debug purposes
- */
- const displayConnStatus = function(status, serverUri) {
- let msgText = "";
- switch (status.toLowerCase()) {
- case "connecting":
- msgText =
- `<h5>Connecting to server...</h5>` +
- `<pre class='bg-warning'>` +
- `Address: ${serverUri}` +
- `n${formatDate(new Date())}` +
- `</pre>`;
- connStatusMsg.className = "label label-warning";
- connStatusMsg.innerHTML = msgText;
- break;
- case "success":
- msgText =
- `<h5>WebSocket connection OK.</h5>n` +
- `<pre class='bg-success'>`+
- `Address: ${serverUri}` +
- `n${formatDate(new Date())}` +
- `</pre>`;
- connStatusMsg.innerHTML = msgText;
- connStatusMsg.className = "label label-success";
- break;
- case "failure":
- msgText =
- `<h5>WebSocket connection FAILED.</h5>n` +
- `<pre class='bg-danger'>`+
- `Address: ${serverUri}` +
- `n${formatDate(new Date())}` +
- `</pre>`;
- connStatusMsg.innerHTML = msgText;
- connStatusMsg.className = "label label-danger";
- break;
- case "unknown":
- default:
- msgText = `<h5>Unknown connection status...</h5>`;
- connStatusMsg.innerHTML = msgText;
- connStatusMsg.className = "label label-default";
- break;
- }
- return msgText;
- };
- /**
- * Hides the `select` element and shows a read-only `input` instead.
- * @param {string} serverUri
- * @returns {undefined}
- */
- const makeServerSelectReadOnly = function(serverUri) {
- const selector = document.getElementById("login_server_list");
- const connecting = document.getElementById("server_connecting");
- selector.style.display = "none";
- connecting.style.display = "block";
- connecting.value = `Connecting to ${serverUri}...`;
- };
- /**
- * Makes the server `select` element visible and hides the read-only `input`
- * @returns {undefined}
- */
- const makeServerSelectReadWrite = function() {
- const selector = document.getElementById("login_server_list");
- const connecting = document.getElementById("server_connecting");
- selector.style.display = "block";
- connecting.style.display = "none";
- };
- /**
- * Displays an input field for server address if "Other" server is selected.
- * @returns {undefined}
- */
- const handleServerSelectChanges = function() {
- if (serverSelect.value) {
- serverOtherInputContainer.style.display = "none";
- }
- else {
- serverOtherInputContainer.style.display = "block";
- }
- };
- /**
- * Attempts to login to game server.
- * @returns {undefined}
- */
- const tryLogin = function() {
- const username = document.getElementById("login_username").value;
- if (!username) {
- displayNoUsernameWarning();
- }
- else {
- const isSecure = false;
- var loggedIn = null;
- let serverUri = serverSelect.value;
- if (!serverUri) {
- serverUri = document.getElementById("login_server_other_input").value;
- }
- /**
- * Short-circuit login attempt if we've already found that the connection not valid.
- * @type String
- */
- if (!currentServerHasValidConnection) {
- const msg = "Websocket error(error 1)";
- console.log(msg);
- displayLoginFailureWarning(msg);
- }
- /**
- * Attempt to log in once the WebSocket connection is ready.
- * @returns {undefined}
- */
- const onReady = function() {
- let login = new CardshifterServerAPI.messageTypes.LoginMessage(username);
- /**
- * Listens for a welcome message from the game server, and stores user values in the browser.
- * @param {Object} welcome
- * @returns {undefined}
- */
- const messageListener = function(welcome) {
- const SUCCESS = 200;
- const SUCCESS_MESSAGE = "OK";
- if(welcome.status === SUCCESS && welcome.message === SUCCESS_MESSAGE) {
- localStorage.setItem("username", username);
- localStorage.setItem("id", welcome.userId);
- localStorage.setItem("playerIndex", null);
- localStorage.setItem("game", { "id" : null, "mod" : null });
- }
- else {
- console.log(`${new Date()} server message: ${welcome.message}`);
- loggedIn = false;
- }
- };
- try {
- CardshifterServerAPI.setMessageListener(messageListener, ["loginresponse"]);
- CardshifterServerAPI.sendMessage(login);
- }
- catch(error) {
- const msg = "LoginMessage error(error 2)";
- if (DEBUG) { logDebugMessage(`${msg} ${error}`); }
- displayLoginFailureWarning(msg, error);
- loggedIn = false;
- }
- };
- /**
- * Log error if the connection fails
- * @returns {undefined}
- */
- const onError = function() {
- const msg = "Websocket error(error 1)";
- if (DEBUG) { logDebugMessage(msg); }
- displayLoginFailureWarning(msg);
- loggedIn = false;
- };
- CardshifterServerAPI.init(serverUri, isSecure, onReady, onError);
- }
- };
- /**
- * Displays a warning if no username is entered.
- * @returns {undefined}
- */
- const displayNoUsernameWarning = function() {
- const container = document.getElementById("login_username_container");
- if (!container.querySelector("#login_username_missing_msg")) {
- const msg = document.createElement("span");
- msg.id = "login_username_missing_msg";
- msg.className = "label label-danger";
- msg.innerHTML = "Please enter a username.";
- container.appendChild(msg);
- }
- };
- const displayLoginFailureWarning = function(message, error) {
- const container = document.getElementById("login_username_container");
- const warning = document.createElement("span");
- warning.id = "login_failure_msg";
- warning.className = "label label-danger";
- warning.style = "display: block; text-align: left;";
- warning.innerHTML = `<h5>Login failed: ${message}</h5>`;
- if (error) {
- warning.innerHTML += `<pre>${error}</pre>`;
- }
- container.appendChild(warning);
- };
- const testOtherServerConnection = function() {
- const otherServerInput = document.getElementById("login_server_other_input");
- const otherServerUri = otherServerInput.value;
- const isSecure = false;
- /**
- * Test WebSocket connection and display status if successful.
- * @returns {undefined}
- */
- const onReady = function() {
- makeServerSelectReadWrite();
- msgText = displayConnStatus("success", otherServerUri);
- if (DEBUG) { logDebugMessage(msgText); }
- currentServerHasValidConnection = true;
- };
- /**
- * Test WebSocket connection and display status if failed.
- * @returns {undefined}
- */
- const onError = function() {
- makeServerSelectReadWrite();
- msgText = displayConnStatus("failure", otherServerUri);
- if (DEBUG) { logDebugMessage(msgText); }
- currentServerHasValidConnection = false;
- };
- CardshifterServerAPI.init(otherServerUri, isSecure, onReady, onError);
- makeServerSelectReadOnly();
- displayConnStatus("connecting", otherServerUri);
- };
- /**
- * IIFE to setup the login handling for the page it is loaded in.
- * @type undefined
- */
- const runLoginHandler = function() {
- populateServerSelect();
- document.getElementById("login_server_list").addEventListener("change", handleServerSelectChanges, false);
- document.getElementById("login_server_list").addEventListener("change", testWebsocketConnection, false);
- document.getElementById("login_submit").addEventListener("click", tryLogin, false);
- document.getElementById("test_login_server_other").addEventListener("click", testOtherServerConnection, false);
- testWebsocketConnection();
- }();
- };
- <nav id="top_navbar" class="navbar navbar-inverse">
- <div class="container-fluid">
- <div class="navbar-header">
- <!-- TODO fix this logic -->
- <div class="navbar-brand csh-top-link">Cardshifter</div>
- </div>
- <form class="navbar-form">
- <ul class ="navbar-form navbar-left" style="margin-top: 8px;">
- <li class="dropdown">
- <a href="#" class="dropdown-toggle csh-dropdown-link" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
- Mods
- <span class="caret"></span></a>
- <ul class="dropdown-menu">
- <li class="cyborg-font">Cyborg Chronicles</li>
- <li class="cyborg-font"><a href=#>Game rules</a></li>
- <li class="cyborg-font"><a href=#>Cards</a></li>
- <li role="separator" class="divider"></li>
- <li class="mythos-font">Mythos</li>
- <li class="mythos-font"><a href=#>Game rules</a></li>
- <li class="mythos-font"><a href=#>Cards</a></li>
- </ul>
- </li>
- </ul>
- <ul class ="navbar-form navbar-left" style="margin-top: 8px;">
- <li class="dropdown">
- <a href="#" class="dropdown-toggle csh-dropdown-link" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
- Help
- <span class="caret"></span></a>
- </li>
- </ul>
- <ul class ="navbar-form navbar-left" style="margin-top: 8px;">
- <li class="dropdown">
- <a href="#" class="dropdown-toggle csh-dropdown-link" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
- About
- <span class="caret"></span></a>
- </li>
- </ul>
- <div class="form-group navbar-form navbar-left">
- <input name="disconnect_websocket" id="disconnect_websocket" type="button" value="Log Out" class="btn btn-navbar csh-button" />
- </div>
- <div class="form-group navbar-form navbar-left">
- <input name="display_console" id="display_console" type="button" value="Console" class="btn btn-navbar csh-button" />
- </div>
- </form>
- </div>
- </nav>
- "use strict";
- // checks if the string begins with either ws:// or wss://
- const wsProtocolFinder = /ws(s)*:///;
- /*
- * Enum for WebSocket ready state constants.
- * @enum {number}
- */
- const readyStates = {
- CONNECTING : 0,
- OPEN : 1,
- CLOSING : 2,
- CLOSED : 3
- };
- const MAIN_LOBBY = 1;
- let eventTypes = [];
- /**
- * The base class Message for all the other message types
- * to inherit from.
- *
- * TODO: Would it just be easier to set the `.command` property
- * individually for each card type?
- *
- * @param {string} command - The command of the message.
- */
- const Message = function(command) {
- this.command = command;
- };
- /**
- * The exception that is thrown when the code is trying to
- * interact with the API when the API has not been
- * initialized with `.init` yet.
- *
- * @param {string} message - Informational message about the exception.
- */
- const NotInitializedException = function(message) {
- this.name = "NotInitializedException";
- this.message = message || "";
- };
- /**
- * The exception that is thrown when the code is telling the
- * API to interact with the socket when the socket is not
- * ready to accept any information.
- *
- * @param {string} message - Informational message about the exception.
- * @param {number} readyState - Ready state constant from WebSocket API, https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- */
- const SocketNotReadyException = function(message, readyState) {
- this.name = "SocketNotReadyException";
- this.message = message || "";
- this.readyState = readyState;
- };
- /*
- * Returns all the keys of an object and its inherited keys.
- * This is used so `JSON.stringify` can get the `.command` of a message.
- *
- * @param {Object} obj - The object to flatten
- * @return {Object} - a new Object, containing obj's keys and inherited keys
- * @source http://stackoverflow.com/questions/8779249/how-to-stringify-inherited-objects-to-json
- */
- const flatten = function(obj) {
- let result = Object.create(obj);
- for(let key in result) {
- // TODO this assignment is weird, why is `result[key]` being assigned to its own value?
- result[key] = result[key];
- }
- return result;
- };
- /*
- * Singleton object to handle communication via WebSocket between the client
- * and the game server.
- */
- const CardshifterServerAPI = {
- socket: null,
- messageTypes: {
- /*
- * Incoming login message.
- * A login message from a client to add a user to the available users on the server.
- * This login message is required before any other action or message can be performed between a client and a server.
- * @constructor
- * @param {string} username - The incoming user name passed from client to server, not null
- * @example Message: <code>{ "command":"login","username":"JohnDoe" }</code>
- */
- LoginMessage : function(username) {
- this.username = username;
- },
- /*
- * Request available targets for a specific action to be performed by an entity.
- * These in-game messages request a list of all available targets for a given action and entity.
- * The client uses this request in order to point out targets (hopefully with a visual aid such as highlighting targets)
- * that an entity (such as a creature card, or a player) can perform an action on (for example attack or enchant a card).
- * @constructor
- * @param {number} gameId - The Id of this game currently being played
- * @param {number} id - The Id of this entity which requests to perform an action
- * @param {string} action - The name of this action requested to be performed
- */
- RequestTargetsMessage : function(gameId, id, action) {
- this.gameId = gameId;
- this.id = id;
- this.action = action;
- },
- /*
- * Make a specific type of request to the server.
- * This is used to request an action from the server which requires server-side information.
- * @constructor
- * @param {string} request - This request
- * @param {string} message - The message accompanying this request
- */
- ServerQueryMessage : function(request, message) {
- this.request = request;
- this.message = message;
- this.toString = function() {
- return `ServerQueryMessage: Request${this.request} message: ${this.message}`;
- };
- },
- /*
- * Request to start a new game.
- * This is sent from the Client to the Server when this player invites another player (including AI)
- * to start a new game of a chosen type.
- * @constructor
- * @param opponent - The Id of the player entity being invited by this player
- * @param gameType - The type / mod of the game chosen by this player
- */
- StartGameRequest : function(opponent, gameType) {
- this.opponent = opponent;
- this.gameType = gameType;
- },
- /*
- * Serialize message from JSON to byte.
- * Primarily used for libGDX client.
- * Constructor.
- * @param type - This message type
- */
- TransformerMessage : function(type) {
- this.type = type;
- },
- /*
- * Message for a game entity to use a certain ability.
- * Game entities (e.g., cards, players) may have one or more ability actions that they can perform.
- * Certain abilities can have multiple targets, hence the use of an array.
- * @constructor
- * Used for multiple target actions.
- *
- * @param gameId - This current game
- * @param entity - This game entity performing an action
- * @param action - This action
- * @param targets - The set of multiple targets affected by this action
- */
- UseAbilityMessage : function(gameId, id, action, targets) {
- this.gameId = gameId;
- this.id = id;
- this.action = action;
- this.targets = targets;
- this.toString = function() {
- return ``
- + `UseAbilityMessage`
- + `[id=${this.id},`
- + `action=${this.action},`
- + `gameId=${this.gameId}`
- + `targets=${this.targets.toString()}]`
- ;
- };
- },
- /*
- * Chat message in game lobby.
- * These are messages printed to the game lobby which are visible to all users present at the time the message is posted.
- * @constructor
- * @param {string} message - The content of this chat message
- */
- ChatMessage : function(message) {
- this.chatId = MAIN_LOBBY;
- this.message = message;
- this.toString = function() {
- // TODO where does that `from` param/var come from?
- return `ChatMessage [chatId=${chatId}, message=${message}, from=${from}]`;
- };
- },
- /*
- * Request to invite a player to start a new game.
- * @constructor
- * @param id - The Id of this invite request
- * @param {string} name - The name of the player being invited
- * @param gameType - The game type of this invite request
- */
- InviteRequest : function(id, name, gameType) {
- this.id = id;
- this.name = name;
- this.gameType = gameType;
- },
- /*
- * Response to an InviteRequest message.
- * @constructor
- * @param inviteId - Id of this incoming InviteRequest message
- * @param {boolean} accepted - Whether or not the InviteRequest is accepted
- */
- InviteResponse : function(inviteId, accepted) {
- this.inviteId = inviteId;
- this.accepted = accepted;
- },
- /*
- * Player configuration for a given game.
- * @constructor
- * @param gameId - This game
- * @param {string} modName - The mod name for this game
- * @param {Map} configs - Map of player name and applicable player configuration
- */
- PlayerConfigMessage : function(gameId, modName, configs) {
- this.gameId = gameId;
- this.modName = modName;
- this.configs = configs;
- this.toString = function() {
- return ``
- + `PlayerConfigMessage{`
- + `configs=${configs}, `
- + `gameId=${gameId}, `
- + `modName='${modName}'`
- + `}`
- ;
- };
- }
- },
- /*
- * Initializes the API for use.
- *
- * This sets up all the message types to inherit the main `Message` class, and sets
- * up the websocket that will be used to communicate to the server, and to recieve
- * information from the server.
- *
- * @param {string} server - The server address to connect to
- * @param {boolean} isSecure - Whether to use SSL for the connection (NOT IMPLEMENTED)
- * @param onReady - Function to assign to `socket.onopen`
- * @param onError - Function to assign to `socket.onerror`
- */
- init : function(server, isSecure, onReady, onError) {
- let types = this.messageTypes;
- // TODO find out why this unused variable is here
- let self = this; // for the events
- types.LoginMessage.prototype = new Message("login");
- types.RequestTargetsMessage.prototype = new Message("requestTargets");
- types.ServerQueryMessage.prototype = new Message("query");
- types.StartGameRequest.prototype = new Message("startgame");
- types.TransformerMessage.prototype = new Message("serial");
- types.UseAbilityMessage.prototype = new Message("use");
- types.ChatMessage.prototype = new Message("chat");
- types.InviteRequest.prototype = new Message("inviteRequest");
- types.InviteResponse.prototype = new Message("inviteResponse");
- types.PlayerConfigMessage.prototype = new Message("playerconfig");
- NotInitializedException.prototype = new Error();
- SocketNotReadyException.prototype = new Error();
- // secure websocket is wss://, rather than ws://
- const secureAddon = (isSecure ? "s" : "");
- // if the protocol is not found in the string, store the correct protocol (is secure?)
- const protocolAddon = (wsProtocolFinder.test(server) ? "" : `ws${secureAddon}://`);
- let socket = new WebSocket(protocolAddon + server);
- socket.onopen = onReady;
- socket.onerror = function() {
- onError();
- this.socket = null;
- };
- this.socket = socket;
- },
- /**
- * Sends a message to the server
- *
- * @param {Object} message - The message to send
- * @error SocketNotReadyException - The socket is not ready to be used
- * @error NotInitializedException - The API has not yet been initialized
- */
- sendMessage : function(message) {
- const socket = this.socket;
- // TODO find out why this unused variable is here
- let self = this;
- if (socket) {
- if (socket.readyState === readyStates.OPEN) {
- this.socket.send(JSON.stringify(flatten(message)));
- }
- else {
- throw new SocketNotReadyException("The Websocket is not ready to be used.", socket.readyState);
- }
- }
- else {
- throw new NotInitializedException("The API has not yet been initialized.");
- }
- },
- /**
- * Sets an event listener for when the server sends a message and
- * the message type is one of the types in types
- *
- * @param listener - The function to fire when a message of types is received
- * @param {string[]} types - (OPTIONAL) Only fire the listener when the message type is in this array
- * @param {Object} timeout - (OPTIONAL) The function(.ontimeout) to call after MS(.ms) of no reply
- *
- * TODO: Maybe a timeout will be needed? Pass in a function and a MS count.
- */
- setMessageListener : function(listener, types, timeout) {
- eventTypes = types;
- this.socket.onmessage = function(message) {
- var data = JSON.parse(message.data);
- if (eventTypes) {
- if(eventTypes.indexOf(data.command) !== -1) { // if contains
- listener(data);
- }
- }
- else {
- listener(data);
- }
- };
- },
- /**
- * Adds types to the types to listen for in the message event listener
- *
- * @param {string[]} types - The types to add
- */
- addEventTypes : function(types) {
- eventTypes = eventTypes.concat(types);
- },
- /**
- * Removes the message event listener
- */
- removeMessageListener : function() {
- this.socket.onmessage = null;
- }
- };
- /* global DEFAULT_DATE_FORMAT */
- /**
- * Formats a Date object based on a format string, e.g., "yyyy/MM/dd hh:MM:ss"
- * Original source:
- * https://dzone.com/articles/javascript-formatdate-function
- * Original source modified to fix a few bugs and modernize.
- *
- * @param {Date} date - the Date to format
- * @param {String} formatString - the format string to use
- * @returns {String} - the formatted date
- */
- const formatDate = function (date, formatString=DEFAULT_DATE_FORMAT) {
- if(date instanceof Date) {
- const months = new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
- const yyyy = date.getFullYear();
- const yy = yyyy.toString().slice(-2);
- const M = date.getMonth() + 1;
- const MM = M < 10 ? `0${M}` : M;
- const MMM = months[M - 1];
- const d = date.getDate();
- const dd = d < 10 ? `0${d}` : d;
- const h = date.getHours();
- const hh = h < 10 ? `0${h}` : h;
- const m = date.getMinutes();
- const mm = m < 10 ? `0${m}` : m;
- const s = date.getSeconds();
- const ss = s < 10 ? `0${s}` : s;
- formatString = formatString.replace(/yyyy/, yyyy);
- formatString = formatString.replace(/yy/, yy);
- formatString = formatString.replace(/MMM/, MMM);
- formatString = formatString.replace(/MM/, MM);
- formatString = formatString.replace(/M/, M);
- formatString = formatString.replace(/dd/, dd);
- formatString = formatString.replace(/d/, d);
- formatString = formatString.replace(/hh/, hh);
- formatString = formatString.replace(/h/, h);
- formatString = formatString.replace(/mm/, mm);
- formatString = formatString.replace(/m/, m);
- formatString = formatString.replace(/ss/, ss);
- formatString = formatString.replace(/s/, s);
- return formatString;
- } else {
- return "";
- }
- };
- /* global fetch, DEBUG */
- "use strict";
- /*
- * Replicates the functionality of jQuery's `load` function,
- * used to load some HTML from another file into the current one.
- *
- * Based on this Stack Overflow answer:
- * https://stackoverflow.com/a/38132775/3626537
- * And `fetch` documentation:
- * https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
- *
- * @param {string} parentElementId - The ID of the DOM element to load into
- * @param {string} htmlFilePath - The path of the HTML file to load
- */
- const loadHtml = function (parentElementId, filePath) {
- const init = {
- method: "GET",
- headers: { "Content-Type": "text/html" },
- mode: "cors",
- cache: "default"
- };
- // Return Promise from `fetch` allows to use `.then` after call.
- return fetch(filePath, init)
- .then(function (response) {
- return response.text();
- })
- .then(function (body) {
- // Replace `#` char in case the function gets called `querySelector` or jQuery style
- if (parentElementId.startsWith("#")) {
- parentElementId.replace("#", "");
- }
- document.getElementById(parentElementId).innerHTML = body;
- if (DEBUG) {
- console.log(`File "${filePath}" loaded into element ID "${parentElementId}"`);
- }
- })
- .catch(function(err) {
- throw new FailureToLoadHTMLException(
- `Could not load "${filePath} ` +
- `into element ID "${parentElementId}"` +
- `n${err}`
- );
- });
- };
- const FailureToLoadHTMLException = function(message) {
- this.name = "FailureToLoadHTMLException";
- this.message = message;
- this.stack = (new Error()).stack;
- };
- FailureToLoadHTMLException.prototype = new Error;
- /* global DEFAULT_DATE_FORMAT */
- /**
- * Log a debug message to the browser's JavaScript console.
- * @param {String} msg
- * @param {String} dateFormat
- * @returns {undefined}
- */
- const logDebugMessage = function(msg, dateFormat=DEFAULT_DATE_FORMAT) {
- const timestamp = new Date();
- console.log(`DEBUG | ${formatDate(timestamp, dateFormat)} | ${msg}`);
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement