diff options
Diffstat (limited to 'WebInterface/NodeJSServer/src')
11 files changed, 216 insertions, 27 deletions
diff --git a/WebInterface/NodeJSServer/src/index.js b/WebInterface/NodeJSServer/src/index.js index 35ea63e..702ed19 100644 --- a/WebInterface/NodeJSServer/src/index.js +++ b/WebInterface/NodeJSServer/src/index.js @@ -1,7 +1,6 @@ import Backdrop from './modules/ui/backdrop.js'; import BannerController from './modules/ui/notification-banner.js'; import ServerClient from './modules/server-client.js'; -import LoginModal from './modules/ui/login-modal.js'; // TODO: JUST DEBUG let backdrop = new Backdrop('menu', 'front-layer', 'show-menu'); backdrop.register(); @@ -10,10 +9,10 @@ let notifications = new BannerController('notifications', 'banner-info', 'dismiss-banner', 'notification-amount'); notifications.register(); -let client = new ServerClient('http://89.183.8.51:5000/chatHub', 'server-list', true); +let client = new ServerClient('http://89.183.101.117:5000/chatHub', + 'server-list', notifications, [backdrop, notifications], true); document.getElementById('refresh-button') - .addEventListener('click', client.loadServers.bind(client)); - -new LoginModal('The Crew', client); + .addEventListener('click', + client.loadServers.bind(client)); window.client = client; // TODO: REMOVE, JUST FOR DEBUGGING diff --git a/WebInterface/NodeJSServer/src/modules/server-client.js b/WebInterface/NodeJSServer/src/modules/server-client.js index ea37e1e..1bc9822 100644 --- a/WebInterface/NodeJSServer/src/modules/server-client.js +++ b/WebInterface/NodeJSServer/src/modules/server-client.js @@ -10,9 +10,12 @@ export default class ServerClient { * @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, debug = false) { + constructor(url, serverListingId, notifications, ui, debug = false) { + this.ui = ui; const connectionBuilder = new signalR.HubConnectionBuilder() .withUrl(url); @@ -30,7 +33,7 @@ export default class ServerClient { // Initialize refreshing (blocks new refreshes if true) this.refreshing = false; - this.serverListing = new ServerListing(serverListingId); + this.serverListing = new ServerListing(serverListingId, notifications); this.messageHandling(); } @@ -44,7 +47,7 @@ export default class ServerClient { this.connection.on('ListGroups', (groups) => { // Populate server listing this.serverListing.flushElements(); - this.serverListing.addElements(groups); + this.serverListing.addElements(groups, this, this.ui); this.connection.off('ListGroups'); this.refreshing = false; @@ -76,7 +79,7 @@ export default class ServerClient { */ sendLogin(group, password, username, callback) { this.connection.on('LoginResponse', (result) => { - callback(result); + callback(result, this); this.connection.off('LoginResponse'); }); this.connection.invoke('Login', group, username, password); @@ -99,6 +102,7 @@ export default class ServerClient { /** * Callback to call with response to login request * @callback ServerClient~loginCallback - * @param {number} result 0: Success, 1: PasswordError, 2:UsernameTaken - * , 3:Unknown Error + * @param {number} result 0: Success, 1: PasswordError, 2:UsernameTaken, + * 3:Unknown Error + * @param {ServerClient} client ServerClient object, that handled the login */ diff --git a/WebInterface/NodeJSServer/src/modules/ui/backdrop.js b/WebInterface/NodeJSServer/src/modules/ui/backdrop.js index 1a24bd2..f89a3c9 100644 --- a/WebInterface/NodeJSServer/src/modules/ui/backdrop.js +++ b/WebInterface/NodeJSServer/src/modules/ui/backdrop.js @@ -11,6 +11,7 @@ export default class Backdrop { * @param {string} menuButton ID of Show / Hide Menu Button */ constructor(backdropMenu, frontLayer, menuButton) { + this.ids = {backdropMenu, frontLayer, menuButton}; this.backdrop = document.getElementById(backdropMenu); this.frontLayer = document.getElementById(frontLayer); this.menuButton = document.getElementById(menuButton); @@ -25,6 +26,16 @@ export default class Backdrop { } /** + * Reloads the object + */ + refresh() { + this.backdrop = document.getElementById(this.ids.backdropMenu); + this.frontLayer = document.getElementById(this.ids.frontLayer); + this.menuButton = document.getElementById(this.ids.menuButton); + this.register(); + } + + /** * Registers showing / hiding through menu button */ registerButtonEvent() { diff --git a/WebInterface/NodeJSServer/src/modules/ui/login-modal.js b/WebInterface/NodeJSServer/src/modules/ui/login-modal.js index 4c7b872..d2a88c4 100644 --- a/WebInterface/NodeJSServer/src/modules/ui/login-modal.js +++ b/WebInterface/NodeJSServer/src/modules/ui/login-modal.js @@ -11,11 +11,16 @@ export default class LoginModal extends Modal { * 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) { + 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'); @@ -23,15 +28,20 @@ export default class LoginModal extends Modal { 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'; @@ -39,17 +49,22 @@ export default class LoginModal extends Modal { 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); @@ -60,6 +75,9 @@ export default class LoginModal extends Modal { this.passwordInput = passwordInput; this.loginButton = sendButton; + this.passwordInvalid = passwordInvalid; + this.nameInvalid = nameInvalid; + this.registerLoginBtn(); } @@ -67,18 +85,87 @@ export default class LoginModal extends Modal { * Registers event to send login, on button press */ registerLoginBtn() { - let eventListener = () => { + let eventListener; + let loginCallBack = (result, client) => { + console.log(result); + if (result == 0) { + this.redirectToPlay(client); + 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); let userName = this.nameInput.value; this.passwordInput.value.getHash() .then((result) => { - this.serverClient.sendLogin(this.serverName, result, userName); - - // TODO: Wait for response, if error keep window intact, - // and reenable event listener - this.close(); + this.serverClient.sendLogin(this.serverName, result, + 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 {ServerClient} serverClient Main server client + */ + redirectToPlay(serverClient) { + window.history.pushState('object or string', 'Game Page', + 'play#game=' + this.serverName); + fetch('play').then((response) => { + response.text().then((htmlString) => { + htmlString = htmlString.replace(/\.\.\//g, './'); + htmlString = htmlString.replace(/<script src=".*"><\/script>/, ''); + htmlString = htmlString.replace( + /<remove_if_redirected>.*?<\/remove_if_redirected>/g, ''); + document.open(); + document.write(htmlString); + document.close(); + + for (let ui of this.pageUI) { + ui.refresh(); + } + + // import() + }); + }); + } } diff --git a/WebInterface/NodeJSServer/src/modules/ui/notification-banner.js b/WebInterface/NodeJSServer/src/modules/ui/notification-banner.js index 12461fa..7e6b8cb 100644 --- a/WebInterface/NodeJSServer/src/modules/ui/notification-banner.js +++ b/WebInterface/NodeJSServer/src/modules/ui/notification-banner.js @@ -10,6 +10,7 @@ export default class BannerController { * @param {string} notificationBadge ID of badge (# of notifications) */ constructor(bannerId, textP, dismissBtn, notificationBadge) { + this.ids = {bannerId, textP, dismissBtn, notificationBadge}; this.banner = document.getElementById(bannerId); this.bannerText = document.getElementById(textP); this.dismissBtn = document.getElementById(dismissBtn); @@ -30,6 +31,21 @@ export default class BannerController { } /** + * Reloads the object + */ + refresh() { + this.banner = document.getElementById(this.ids.bannerId); + this.bannerText = document.getElementById(this.ids.textP); + this.dismissBtn = document.getElementById(this.ids.dismissBtn); + this.notificationBadge = document.getElementById( + this.ids.notificationBadge); + this.bannerMsgs = []; + + // Hide Banner after JS loading finished + this.banner.classList.add('hidden'); + } + + /** * Pushes a new message to the notification banner and shows it * @param {string} name Name to register notification (referenced in hide) * @param {string} text Notification text diff --git a/WebInterface/NodeJSServer/src/modules/ui/server-listing.js b/WebInterface/NodeJSServer/src/modules/ui/server-listing.js index 0069ac6..ace8a0e 100644 --- a/WebInterface/NodeJSServer/src/modules/ui/server-listing.js +++ b/WebInterface/NodeJSServer/src/modules/ui/server-listing.js @@ -1,3 +1,5 @@ +import LoginModal from './login-modal.js'; + /** * Class for handling the server list */ @@ -5,9 +7,11 @@ export default class ServerListing { /** * Creates reference to container * @param {string} serverListId ID of the server list div + * @param {BannerController} notifications Notification Manager */ - constructor(serverListId) { + constructor(serverListId, notifications) { this.serverListing = document.getElementById(serverListId); + this.notifications = notifications; } /** @@ -20,8 +24,10 @@ export default class ServerListing { /** * 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) { + addElements(array, serverClient, ui) { for (let server of array) { const name = server['name']; const playerList = server['users']; @@ -46,13 +52,16 @@ export default class ServerListing { 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) + serverDiv.appendChild(rightAlignDiv); this.serverListing.appendChild(serverDiv); } } diff --git a/WebInterface/NodeJSServer/src/play-module.js b/WebInterface/NodeJSServer/src/play-module.js new file mode 100644 index 0000000..3781329 --- /dev/null +++ b/WebInterface/NodeJSServer/src/play-module.js @@ -0,0 +1,15 @@ + + +/** + * Handles ingame networking; + */ +export default class GameClient { + /** + * Defines basic attributes + * @param {HubConnection} connection Already established connection to the + * server + */ + constructor(connection) { + this.connection = connection; + } +} diff --git a/WebInterface/NodeJSServer/src/play.js b/WebInterface/NodeJSServer/src/play.js index e69de29..1e13355 100644 --- a/WebInterface/NodeJSServer/src/play.js +++ b/WebInterface/NodeJSServer/src/play.js @@ -0,0 +1,11 @@ +import Backdrop from './modules/ui/backdrop.js'; +import BannerController from './modules/ui/notification-banner.js'; + +// TODO: Implement login from the play page + +let backdrop = new Backdrop('menu', 'front-layer', 'show-menu'); +backdrop.register(); + +let notifications = new BannerController('notifications', + 'banner-info', 'dismiss-banner', 'notification-amount'); +notifications.register(); diff --git a/WebInterface/NodeJSServer/src/style/partials/_colors.scss b/WebInterface/NodeJSServer/src/style/partials/_colors.scss index 2c954fa..4683325 100644 --- a/WebInterface/NodeJSServer/src/style/partials/_colors.scss +++ b/WebInterface/NodeJSServer/src/style/partials/_colors.scss @@ -4,6 +4,7 @@ $primary-light: #484848; $primary-dark: #000000; $primary-text: #ffffff; $primary-text-disabled: #ffffff61; +$primary-warning-text: #ef5350; $secondary: #546e7a; $secondary-disabled: #546e7a61; $secondary-half-dark: #3e5864; diff --git a/WebInterface/NodeJSServer/src/style/partials/modal/_login.scss b/WebInterface/NodeJSServer/src/style/partials/modal/_login.scss index eed978f..71adf61 100644 --- a/WebInterface/NodeJSServer/src/style/partials/modal/_login.scss +++ b/WebInterface/NodeJSServer/src/style/partials/modal/_login.scss @@ -10,20 +10,41 @@ grid-template-rows: 1fr 1fr 1fr; grid-row-gap: 0.5rem; + &.frst-warning { + grid-template-rows: 1fr 1rem 1fr 1fr; + } + + &.scnd-warning { + grid-template-rows: 1fr 1fr 1rem 1fr; + } + div { display: contents; font-size: 1.25rem; label { - flex-basis: 30%; margin-right: 2rem; - - grid-column: 1 2; + grid-column: 1 / 2; + line-height: 1.25em; } input { - flex-basis: calc(70% - 2rem); - grid-column: 2 3; + grid-column: 2 / 3; + border-color: none; + } + + span { + margin-top: -0.5rem; + grid-column: 1 / 3; + color: $primary-warning-text; + background-color: $primary; + font-size: 0.9rem; + line-height: 1.2rem; + padding: 0.25rem; + + &.hidden { + display: none; + } } button { diff --git a/WebInterface/NodeJSServer/src/style/play.scss b/WebInterface/NodeJSServer/src/style/play.scss new file mode 100644 index 0000000..bfeec6d --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/play.scss @@ -0,0 +1,15 @@ +@import 'partials/base'; +@import 'partials/btn'; +@import 'partials/backdrop/base'; +@import 'partials/backdrop/menu'; +@import 'partials/front-layer/base'; +@import 'partials/front-layer/notifications'; +@import 'partials/front-layer/copyright'; +@import 'partials/modal/base'; +@import 'partials/modal/login'; + +remove_if_redirected { + width: 100vw; + height: 100vh; + text-align: center; +} |