diff options
author | Dennis Kobert <d-kobert@web.de> | 2019-06-11 23:53:30 +0200 |
---|---|---|
committer | Dennis Kobert <d-kobert@web.de> | 2019-06-11 23:53:30 +0200 |
commit | 3a3d0fc3d4733f8908e23a03f860d76340479ec4 (patch) | |
tree | cf4b82f61d01d2a24836e9820d73972436847982 /WebInterface/src/js/src_old | |
parent | c28c9fafa2c74b101f7ce777aac722dcdeecefc6 (diff) |
Reorganize Project structure
Diffstat (limited to 'WebInterface/src/js/src_old')
-rw-r--r-- | WebInterface/src/js/src_old/modules/playModule.js | 46 | ||||
-rw-r--r-- | WebInterface/src/js/src_old/modules/server-client.js | 93 | ||||
-rw-r--r-- | WebInterface/src/js/src_old/modules/ui/login-modal.js | 181 | ||||
-rw-r--r-- | WebInterface/src/js/src_old/modules/ui/modal.js | 67 | ||||
-rw-r--r-- | WebInterface/src/js/src_old/modules/ui/server-listing.js | 67 |
5 files changed, 454 insertions, 0 deletions
diff --git a/WebInterface/src/js/src_old/modules/playModule.js b/WebInterface/src/js/src_old/modules/playModule.js new file mode 100644 index 0000000..931f598 --- /dev/null +++ b/WebInterface/src/js/src_old/modules/playModule.js @@ -0,0 +1,46 @@ +// TODO: Handle disconnect + +/** + * Handles ingame networking; + */ +export default class GameClient { + /** + * Defines basic attributes + * @param {string} user The username of the player + * @param {HubConnection} connection Already established connection to the + * server + */ + constructor(user, connection) { + this.user = user; + this.connection = connection; + } + + /** + * Registers chat html component + * @param {string} chatId Id of chat component + */ + registerChat(chatId) { + this.chat = document.getElementById(chatId); + this.messageList = this.chat.querySelector('#message-list'); + this.messageInput = this.chat.querySelector('#input-message'); + this.messageSend = this.chat.querySelector('#send-message'); + + this.connection.on('ReceiveMessage', (user, message) => { + let msg = message.replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>'); + let encodedMsg = user + ' sagt: ' + msg; + + let messageP = document.createElement('p'); + messageP.class = 'message'; + messageP.textContent = encodedMsg; + + this.messageList.appendChild(messageP); + }); + + this.messageSend.addEventListener('click', () => { + let message = this.messageInput.value; + this.connection.invoke('SendMessage', this.user, message); + }); + } +} diff --git a/WebInterface/src/js/src_old/modules/server-client.js b/WebInterface/src/js/src_old/modules/server-client.js new file mode 100644 index 0000000..2f712b5 --- /dev/null +++ b/WebInterface/src/js/src_old/modules/server-client.js @@ -0,0 +1,93 @@ +import * as signalR from '@aspnet/signalr'; +import ServerListing from './ui/server-listing.js'; + +/** + * Class for communication to server + */ +export default class ServerClient { + /** + * Creates new connection + * @param {string} url URL of server running signalR + * @param {string} serverListingId HTML ID of server-listing element, + * to populate with available games + * @param {BannerController} notifications Notification Manager + * @param {array} ui UI Elements to reload on login + * @param {boolean} [debug=false] Enable debug output? + */ + constructor(url, serverListingId, notifications, ui, debug = false) { + this.ui = ui; + const connectionBuilder = new signalR.HubConnectionBuilder() + .withUrl(url); + + if (debug) { + connectionBuilder.configureLogging(signalR.LogLevel.Debug); + } else { + connectionBuilder.configureLogging(signalR.LogLevel.Error); + } + + this.connection = connectionBuilder.build(); + this.connection.start() + .then(() => this.loadServers()) // Load games list, once connected + .catch((err) => console.error(err.toString())); + + // Initialize refreshing (blocks new refreshes if true) + this.refreshing = false; + + this.serverListing = new ServerListing(serverListingId, notifications); + } + + /** + * Requests list of avalable games on the server + */ + loadServers() { + if (this.refreshing) return; // If already refreshing, no new request + + this.connection.on('ListGroups', (groups) => { + // Populate server listing + this.serverListing.flushElements(); + this.serverListing.addElements(groups, this, this.ui); + this.connection.off('ListGroups'); + + this.refreshing = false; + }); + + this.connection.invoke('GetGroups') + .catch((err) => { + this.refreshing = false; + console.error(err.toString()); + }); + this.refreshing = true; + } + + /** + * Sends a game creating request to the server + * @param {string} name Name of the new game + * @param {string} password Password + */ + createServer(name, password) { + // TODO: Create + } + + /** + * Sends a login request + * @param {string} group Group name to join + * @param {string} password Password to send as SHA-256 Base64 String + * @param {string} username Display name to use + * @param {ServerClient~loginCallback} callback Callback function to use + */ + sendLogin(group, password, username, callback) { + this.connection.on('LoginResponse', (result) => { + callback(result, this.connection); + this.connection.off('LoginResponse'); + }); + this.connection.invoke('Login', group, username, password); + } +} + +/** + * Callback to call with response to login request + * @callback ServerClient~loginCallback + * @param {number} result 0: Success, 1: PasswordError, 2:UsernameTaken, + * 3:Unknown Error + * @param {ConnectionHub} connection Connection to the server + */ diff --git a/WebInterface/src/js/src_old/modules/ui/login-modal.js b/WebInterface/src/js/src_old/modules/ui/login-modal.js new file mode 100644 index 0000000..13de78e --- /dev/null +++ b/WebInterface/src/js/src_old/modules/ui/login-modal.js @@ -0,0 +1,181 @@ +import Modal from './modal.js'; +import '../hash.js'; + +/** + * Class to implement a login modal from the parent modal class + */ +export default class LoginModal extends Modal { + /** + * Creates necessary elements for login modal + * @param {string} serverName Name of the server, used for login and displayed + * in title + * @param {ServerClient} serverClient Server client object used to send the + * login + * @param {BannerController} notificationManager Object controlling the main + * notification banners + * @param {array} ui UI elements to call refresh method on after login + */ + constructor(serverName, serverClient, notificationManager, ui) { + super(serverName); + this.serverName = serverName; + this.serverClient = serverClient; + this.notificationManager = notificationManager; + this.pageUI = ui; + + let passBox = document.createElement('div'); + let nameBox = document.createElement('div'); + let sendBox = document.createElement('div'); + + let passwordLabel = document.createElement('label'); + let passwordInput = document.createElement('input'); + let passwordInvalid = document.createElement('span'); + passwordLabel.setAttribute('for', 'password-input'); + passwordLabel.textContent = 'Passwort:'; + passwordLabel.title = 'Das Passwort des Spiels'; + passwordInput.id = 'password-input'; + passwordInput.type = 'password'; + passwordInput.placeholder = 'Passwort'; + passwordInput.title = 'Das Passwort des Spiels'; + passwordInvalid.className = 'invalid hidden'; + passwordInvalid.textContent = 'Das eingegebene Passwort ist falsch.'; + + let nameLabel = document.createElement('label'); + let nameInput = document.createElement('input'); + let nameInvalid = document.createElement('span'); + nameLabel.setAttribute('for', 'name-input'); + nameLabel.textContent = 'Benutzername:'; + nameLabel.title = 'Dein Anzeigename'; + nameInput.id = 'name-input'; + nameInput.type = 'text'; + nameInput.autocomplete = 'on'; + nameInput.placeholder = 'Name'; + nameInput.title = 'Dein Anzeigename'; + nameInvalid.className = 'invalid hidden'; + nameInvalid.textContent = + 'Der eingegebene Nutzername ist bereits vergeben.'; + + let sendButton = document.createElement('button'); + sendButton.className = 'btn'; + sendButton.textContent = 'Login'; + sendButton.id = 'login-button'; + + passBox.appendChild(passwordLabel); + passBox.appendChild(passwordInput); + passBox.appendChild(passwordInvalid); + nameBox.appendChild(nameLabel); + nameBox.appendChild(nameInput); + nameBox.appendChild(nameInvalid); + sendBox.appendChild(sendButton); + + this.body.appendChild(passBox); + this.body.appendChild(nameBox); + this.body.appendChild(sendBox); + + this.nameInput = nameInput; + this.passwordInput = passwordInput; + this.loginButton = sendButton; + + this.passwordInvalid = passwordInvalid; + this.nameInvalid = nameInvalid; + + this.registerLoginBtn(); + } + + /** + * Registers event to send login, on button press + */ + registerLoginBtn() { + let eventListener; + let loginCallBack = (result, connection) => { + console.log(result); + if (result == 0) { + this.redirectToPlay(connection); + this.close(); + } else if (result == 1) { + this.invalid('Name'); + this.loginButton.addEventListener('click', eventListener); + } else if (result == 2) { + this.invalid('Pass'); + this.loginButton.addEventListener('click', eventListener); + } else { + this.notificationManager.show('unknownLoginErr', + 'Ein unbekannter Fehler ist aufgetreten'); + this.close(); + } + }; + + eventListener = () => { + this.invalid(); // Remove 'invalid' messages + this.loginButton.removeEventListener('click', eventListener); + this.userName = this.nameInput.value; + this.passwordInput.value.getHash() + .then((result) => { + this.serverClient.sendLogin(this.serverName, result, + this.userName, loginCallBack); + }); + }; + this.loginButton.addEventListener('click', eventListener); + } + + /** + * Displays text under invalid password / username + * @param {string} inv Which field to display under (Pass / Name) + * Blank inv will hide both + */ + invalid(inv) { + this.body.classList.remove('frst-warning'); + this.body.classList.remove('scnd-warning'); + + this.passwordInvalid.classList.add('hidden'); + this.nameInvalid.classList.add('hidden'); + + this.passwordInput.style.borderColor = 'none'; + this.nameInput.style.borderColor = 'none'; + + if (inv == 'Pass') { + this.body.classList.add('frst-warning'); + this.passwordInvalid.classList.remove('hidden'); + this.passwordInput.style.borderColor = '#ef5350'; + } else if (inv == 'Name') { + this.body.classList.add('scnd-warning'); + this.nameInvalid.classList.remove('hidden'); + this.nameInput.style.borderColor = '#ef5350'; + } + } + + /** + * Loads play site + * @param {HubConnection} connection Connection to the server + */ + redirectToPlay(connection) { + window.history.pushState('object or string', 'Game Page', + 'play#game=' + this.serverName); + fetch('play').then((response) => { + response.text().then((htmlString) => { + // Replace all references, since we're starting one level farther up + htmlString = htmlString.replace(/\.\.\//g, './'); + htmlString = /<body>((.)|(\n))*<\/body>/g.exec(htmlString)[0]; + htmlString = htmlString.replace(/<script src=".*"><\/script>/, ''); + htmlString = htmlString.replace( + /<remove_if_redirected>((.)|\n)*?<\/remove_if_redirected>/g, ''); + document.body.innerHTML = htmlString; + + let stylesheet = document.createElement('link'); + stylesheet.rel = 'stylesheet'; + stylesheet.type = 'text/css'; + stylesheet.href = './style/play.css'; + document.head.appendChild(stylesheet); + + for (let ui of this.pageUI) { + ui.refresh(); + } + + import(/* webpackChunkName: "/playModule" */ '../playModule') + .then(({default: GameClient}) => { + let gameClient = new GameClient(this.userName, connection); + gameClient.registerChat('chat'); + }); + }); + }); + } +} diff --git a/WebInterface/src/js/src_old/modules/ui/modal.js b/WebInterface/src/js/src_old/modules/ui/modal.js new file mode 100644 index 0000000..10a1be5 --- /dev/null +++ b/WebInterface/src/js/src_old/modules/ui/modal.js @@ -0,0 +1,67 @@ +/** + * Parent class to create Modals on the screen + * Contains no content, as that is implemented by child classes + */ +export default class Modal { + /** + * Creates a new modal with a title and empty content + * @param {string} titleString Title to show at the top of the modal + */ + constructor(titleString) { + let modalBackground = document.createElement('div'); + let modal = document.createElement('div'); + let title = document.createElement('h1'); + let body = document.createElement('div'); + + modalBackground.className = 'modal-container'; + modal.className = 'modal'; + title.className = 'modal-title'; + body.className = 'modal-body'; + + title.textContent = titleString; + + modal.appendChild(title); + modal.appendChild(body); + modalBackground.appendChild(modal); + document.body.appendChild(modalBackground); + + this.bg = modalBackground; + this.modal = modal; + this.title = title; + this.body = body; + + this.registerEvents(); + } + + /** + * Register event to close if clicked outside of modal + * Clicking on the modal itself should not close it though + */ + registerEvents() { + this.modal.addEventListener('click', (e) => { + e.stopPropagation(); + }); + + this.bg.addEventListener('click', () => { + this.close(); + }); + } + + /** + * Fades modal out and removes it from the flow of the document + */ + close() { + this.bg.classList.add('hidden'); + this.bg.addEventListener('transitionend', () => { + document.body.removeChild(this.bg); + }); + } + + /** + * Puts text in the body + * @param {string} text Text to put into the body + */ + setBodyText(text) { + this.body.textContent = text; + } +} diff --git a/WebInterface/src/js/src_old/modules/ui/server-listing.js b/WebInterface/src/js/src_old/modules/ui/server-listing.js new file mode 100644 index 0000000..78ca323 --- /dev/null +++ b/WebInterface/src/js/src_old/modules/ui/server-listing.js @@ -0,0 +1,67 @@ +import LoginModal from './login-modal.js'; + +/** + * Class for handling the server list + */ +export default class ServerListing { + /** + * Creates reference to container + * @param {string} serverListId ID of the server list div + * @param {BannerController} notifications Notification Manager + */ + constructor(serverListId, notifications) { + this.serverListing = document.getElementById(serverListId); + this.notifications = notifications; + } + + /** + * Removes all elements currently in the server listing + */ + flushElements() { + this.serverListing.innerHTML = ''; + } + + /** + * Populates servers from a given array of games + * @param {array} array Array of available games + * @param {ServerClient} serverClient Server Client to handle login + * @param {array} ui UI Elements to reload after login + */ + addElements(array, serverClient, ui) { + for (let server of array) { + const name = server['name']; + const playerAmount = server['userCount']; + + let serverDiv = document.createElement('div'); + let nameSpan = document.createElement('span'); + let rightAlignDiv = document.createElement('div'); + let onlineDot = document.createElement('div'); + let playerCountSpan = document.createElement('span'); + let playerCountStaticSpan = document.createElement('span'); + let joinButton = document.createElement('button'); + serverDiv.className = 'server'; + nameSpan.className = 'server-name'; + rightAlignDiv.className = 'right-aligned-items'; + onlineDot.className = 'player-count-dot'; + playerCountSpan.className = 'player-count'; + playerCountStaticSpan.className = 'player-count-static'; + joinButton.className = 'btn join-btn'; + joinButton.id = 'join'; + nameSpan.textContent = name; + playerCountSpan.textContent = playerAmount; + playerCountStaticSpan.textContent = 'Spieler online'; + joinButton.textContent = 'Beitreten'; + joinButton.addEventListener('click', () => { + new LoginModal(name, serverClient, this.notifications, ui); + }); + + rightAlignDiv.appendChild(onlineDot); + rightAlignDiv.appendChild(playerCountSpan); + rightAlignDiv.appendChild(playerCountStaticSpan); + rightAlignDiv.appendChild(joinButton); + serverDiv.appendChild(nameSpan); + serverDiv.appendChild(rightAlignDiv); + this.serverListing.appendChild(serverDiv); + } + } +} |