successful editing of role list

This commit is contained in:
AlecM33
2023-08-03 16:52:03 -04:00
parent 0d82227824
commit 24ae53209f
19 changed files with 260 additions and 103 deletions

View File

@@ -54,7 +54,8 @@ export const globals = {
UPDATE_SPECTATORS: 'updateSpectators',
RESTART_GAME: 'restartGame',
ASSIGN_DEDICATED_MOD: 'assignDedicatedMod',
KICK_PERSON: 'kickPerson'
KICK_PERSON: 'kickPerson',
UPDATE_GAME_ROLES: 'updateGameRoles'
},
TIMER_EVENTS: function () {
return [
@@ -68,7 +69,8 @@ export const globals = {
return [
this.EVENT_IDS.PLAYER_JOINED,
this.EVENT_IDS.ADD_SPECTATOR,
this.EVENT_IDS.KICK_PERSON
this.EVENT_IDS.KICK_PERSON,
this.EVENT_IDS.UPDATE_GAME_ROLES
];
},
IN_PROGRESS_EVENTS: function () {

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#d7d7d7" width="800px" height="800px" viewBox="0 0 16 16" id="save-16px" xmlns="http://www.w3.org/2000/svg">
<path id="Path_42" data-name="Path 42" d="M-5.732,2.97-7.97.732a2.474,2.474,0,0,0-1.483-.7A.491.491,0,0,0-9.591,0H-18.5A2.5,2.5,0,0,0-21,2.5v11A2.5,2.5,0,0,0-18.5,16h11A2.5,2.5,0,0,0-5,13.5V4.737A2.483,2.483,0,0,0-5.732,2.97ZM-13,1V5.455h-3.591V1Zm-4.272,14V10.545h8.544V15ZM-6,13.5A1.5,1.5,0,0,1-7.5,15h-.228V10.045a.5.5,0,0,0-.5-.5h-9.544a.5.5,0,0,0-.5.5V15H-18.5A1.5,1.5,0,0,1-20,13.5V2.5A1.5,1.5,0,0,1-18.5,1h.909V5.955a.5.5,0,0,0,.5.5h7.5a.5.5,0,0,0,.5-.5v-4.8a1.492,1.492,0,0,1,.414.285l2.238,2.238A1.511,1.511,0,0,1-6,4.737Z" transform="translate(21)"/>
</svg>

After

Width:  |  Height:  |  Size: 809 B

View File

@@ -45,10 +45,8 @@ export const HTMLFragments = {
</select>
</div>`,
START_GAME_PROMPT:
`<div>
<button id='start-game-button'>Start Game</button>
<p>All players must join to start.</p>
</div>`,
`<button id='start-game-button'>Start Game</button>
<button id='edit-roles-button'>Edit Roles</button>`,
GAME_CONTROL_PROMPT:
`<div id='game-control-prompt'>
<button id='end-game-button'>End Game</button>
@@ -361,21 +359,21 @@ export const HTMLFragments = {
</div>
<div class="role-options">
<img tabindex="0" class="role-include" src="images/add.svg" title="add one" alt="add one"/>
<img tabindex="0" class="role-info" src="images/info.svg" title="info" alt="info"/>
<img tabindex="0" class="role-edit" src="images/pencil.svg" title="edit" alt="edit"/>
<img tabindex="0" class="role-remove" src="images/delete.svg" title="remove" alt="remove"/>
<img tabindex="0" class="role-include" src="../images/add.svg" title="add one" alt="add one"/>
<img tabindex="0" class="role-info" src="../images/info.svg" title="info" alt="info"/>
<img tabindex="0" class="role-edit" src="../images/pencil.svg" title="edit" alt="edit"/>
<img tabindex="0" class="role-remove" src="../images/delete.svg" title="remove" alt="remove"/>
</div>`,
DECK_SELECT_ROLE_DEFAULT:
`<div class="role-name"></div>
<div class="role-options">
<img tabindex="0" class="role-include" src="images/add.svg" title="add one" alt="add one"/>
<img tabindex="0" class="role-info" src="images/info.svg" title="info" alt="info"/>
<img tabindex="0" class="role-include" src="../images/add.svg" title="add one" alt="add one"/>
<img tabindex="0" class="role-info" src="../images/info.svg" title="info" alt="info"/>
</div>`,
DECK_SELECT_ROLE_ADDED_TO_DECK:
`<div class="role-name"></div>
<div class="role-options">
<img tabindex="0" class="role-remove" src="images/remove.svg" title="remove one" alt="remove one"/>
<img tabindex="0" class="role-info" src="images/info.svg" title="info" alt="info"/>
<img tabindex="0" class="role-remove" src="../images/remove.svg" title="remove one" alt="remove one"/>
<img tabindex="0" class="role-info" src="../images/info.svg" title="info" alt="info"/>
</div>`
};

View File

@@ -191,7 +191,7 @@ export class GameCreationStepManager {
showButtons(false, true, this.steps[step].forwardHandler, null);
break;
case 2:
this.renderRoleSelectionStep(this.currentGame, containerId, step, this.deckManager);
this.renderRoleSelectionStep(this.currentGame, containerId, step);
showButtons(true, true, this.steps[step].forwardHandler, this.steps[step].backHandler);
break;
case 3:
@@ -216,7 +216,7 @@ export class GameCreationStepManager {
document.getElementById('step-' + stepNumber)?.remove();
}
renderRoleSelectionStep = (game, containerId, step, deckManager) => {
renderRoleSelectionStep = (game, containerId, step) => {
const stepContainer = document.createElement('div');
setAttributes(stepContainer, { id: 'step-' + step, class: 'flex-row-container-left-align step' });
@@ -225,13 +225,13 @@ export class GameCreationStepManager {
document.getElementById(containerId).appendChild(stepContainer);
this.roleBox = new RoleBox(stepContainer, deckManager);
deckManager.roleBox = this.roleBox;
this.roleBox = new RoleBox(stepContainer, this.deckManager);
this.deckManager.roleBox = this.roleBox;
this.roleBox.loadDefaultRoles();
this.roleBox.loadCustomRolesFromCookies();
this.roleBox.displayDefaultRoles(document.getElementById('role-select'));
deckManager.loadDeckTemplates(this.roleBox);
this.deckManager.loadDeckTemplates(this.roleBox);
const exportHandler = (e) => {
if (e.type === 'click' || e.code === 'Enter') {
@@ -290,9 +290,9 @@ export class GameCreationStepManager {
document.getElementById('custom-role-hamburger').addEventListener('click', clickHandler);
deckManager.updateDeckStatus();
this.deckManager.updateDeckStatus();
initializeRemainingEventListeners(deckManager, this.roleBox);
initializeRemainingEventListeners(this.deckManager, this.roleBox);
};
}

View File

@@ -49,7 +49,8 @@ export class RoleBox {
id: createRandomId(),
role: roleObj.role,
team: roleObj.team,
description: roleObj.description
description: roleObj.description,
custom: true
};
}); // we know it is valid JSON from the validate function
}
@@ -73,7 +74,8 @@ export class RoleBox {
id: createRandomId(),
role: roleObj.role,
team: roleObj.team,
description: roleObj.description
description: roleObj.description,
custom: true
};
}); // we know it is valid JSON from the validate function
const initialLength = this.customRoles.length;
@@ -107,6 +109,26 @@ export class RoleBox {
reader.readAsText(file);
}
loadSelectedRolesFromCurrentGame = (game) => {
for (const card of game.deck) {
if (card.quantity) {
for (let i = 0; i < card.quantity; i ++) {
if (!this.deckManager.hasRole(card.role)) {
const role = this.getDefaultRole(card.role)
? this.getDefaultRole(card.role)
: this.getCustomRole(card.role);
role.id = card.id;
this.deckManager.addToDeck(role);
} else {
this.deckManager.addCopyOfCard(card.role);
}
}
}
}
this.deckManager.updateDeckStatus();
}
// via https://stackoverflow.com/a/18197341
downloadCustomRoles = (filename, text) => {
const element = document.createElement('a');

View File

@@ -4,6 +4,9 @@ import { globals } from '../../../config/globals.js';
import { HTMLFragments } from '../../front_end_components/HTMLFragments.js';
import { Confirmation } from '../../front_end_components/Confirmation.js';
import { SharedStateUtil } from './shared/SharedStateUtil.js';
import { GameCreationStepManager } from '../../game_creation/GameCreationStepManager.js';
import { DeckStateManager } from '../../game_creation/DeckStateManager.js';
import { hiddenMenus } from '../../../view_templates/CreateTemplate.js';
export class Lobby {
constructor (containerId, stateBucket, socket) {
@@ -11,6 +14,7 @@ export class Lobby {
this.socket = socket;
this.container = document.getElementById(containerId);
this.container.innerHTML = HTMLFragments.LOBBY;
this.gameCreationStepManager = new GameCreationStepManager(new DeckStateManager());
this.startGameHandler = (e) => {
e.preventDefault();
@@ -38,13 +42,45 @@ export class Lobby {
);
});
};
this.editRolesHandler = (e) => {
e.preventDefault();
document.querySelector('#mid-game-role-editor')?.remove();
const roleEditContainer = document.createElement('div');
roleEditContainer.setAttribute('id', 'mid-game-role-editor');
roleEditContainer.innerHTML = hiddenMenus;
document.body.appendChild(roleEditContainer);
this.gameCreationStepManager.deckManager.deck = [];
this.gameCreationStepManager
.renderRoleSelectionStep(this.stateBucket.currentGameState, 'mid-game-role-editor', '2');
this.gameCreationStepManager.roleBox.loadSelectedRolesFromCurrentGame(this.stateBucket.currentGameState);
const saveButton = document.createElement('button');
saveButton.classList.add('app-button');
saveButton.setAttribute('id', 'save-role-changes-button');
saveButton.innerHTML = '<p>Save</p><img src=\'../images/save-svgrepo-com.svg\'/>';
saveButton.addEventListener('click', () => {
if (this.gameCreationStepManager.deckManager.getDeckSize() > 50) {
toast('Your deck is too large. The max is 50 cards.', 'error', true);
} else if (this.gameCreationStepManager.deckManager.getDeckSize() < 1) {
toast('You must add at least one card', 'error', true);
} else {
document.querySelector('#mid-game-role-editor')?.remove();
this.socket.emit(
globals.SOCKET_EVENTS.IN_GAME_MESSAGE,
globals.EVENT_IDS.UPDATE_GAME_ROLES,
stateBucket.currentGameState.accessCode,
{ deck: this.gameCreationStepManager.deckManager.deck.filter((card) => card.quantity > 0) },
() => {
toast('Roles updated successfully!', 'success');
}
);
}
});
roleEditContainer.appendChild(saveButton);
};
}
populateHeader () {
const timeString = getTimeString(this.stateBucket.currentGameState);
const time = this.container.querySelector('#game-time');
time.innerText = timeString;
setLink (timeString) {
const linkContainer = this.container.querySelector('#game-link');
linkContainer.innerHTML = '<img src=\'../images/copy.svg\' alt=\'copy\'/>';
const link = window.location.protocol + '//' + window.location.host +
@@ -56,8 +92,27 @@ export class Lobby {
linkContainer.prepend(linkDiv);
activateLink(linkContainer, link);
return link;
}
setPlayerCount () {
const playerCount = this.container.querySelector('#game-player-count');
playerCount.innerText = this.stateBucket.currentGameState.gameSize + ' Players';
const inLobbyCount = this.stateBucket.currentGameState.people.filter(
p => p.userType !== globals.USER_TYPES.MODERATOR && p.userType !== globals.USER_TYPES.SPECTATOR
).length;
document.querySelector("label[for='lobby-players']").innerText =
'Participants (' + inLobbyCount + '/' + this.stateBucket.currentGameState.gameSize + ' Players)';
}
populateHeader () {
const timeString = getTimeString(this.stateBucket.currentGameState);
const time = this.container.querySelector('#game-time');
time.innerText = timeString;
const link = this.setLink(timeString);
this.setPlayerCount();
const spectatorHandler = (e) => {
if (e.type === 'click' || e.code === 'Enter') {
@@ -158,12 +213,20 @@ export class Lobby {
}
}
});
this.socket.on(globals.EVENT_IDS.UPDATE_GAME_ROLES, (deck, gameSize) => {
this.stateBucket.currentGameState.deck = deck;
this.stateBucket.currentGameState.gameSize = gameSize;
this.setLink(getTimeString(this.stateBucket.currentGameState));
this.setPlayerCount();
});
}
displayStartGamePromptForModerators () {
const existingPrompt = document.getElementById('start-game-prompt');
if (existingPrompt) {
enableOrDisableStartButton(this.stateBucket.currentGameState, existingPrompt, this.startGameHandler);
document.getElementById('edit-roles-button').addEventListener('click', this.editRolesHandler);
} else {
const newPrompt = document.createElement('div');
newPrompt.setAttribute('id', 'start-game-prompt');
@@ -171,6 +234,7 @@ export class Lobby {
document.body.appendChild(newPrompt);
enableOrDisableStartButton(this.stateBucket.currentGameState, newPrompt, this.startGameHandler);
document.getElementById('edit-roles-button').addEventListener('click', this.editRolesHandler);
}
}

View File

@@ -315,14 +315,15 @@ function processGameState (
break;
}
activateRoleInfoButton(stateBucket.currentGameState.deck);
activateRoleInfoButton();
}
function activateRoleInfoButton (deck) {
deck.sort((a, b) => {
return a.team === globals.ALIGNMENT.GOOD ? -1 : 1;
});
function activateRoleInfoButton () {
document.getElementById('role-info-button').addEventListener('click', (e) => {
const deck = stateBucket.currentGameState.deck;
deck.sort((a, b) => {
return a.team === globals.ALIGNMENT.GOOD ? -1 : 1;
});
e.preventDefault();
document.getElementById('role-info-prompt').innerHTML = HTMLFragments.ROLE_INFO_MODAL;
const modalContent = document.getElementById('game-role-info-container');

View File

@@ -1,8 +1,8 @@
import { injectNavbar } from '../front_end_components/Navbar.js';
import createTemplate from '../../view_templates/CreateTemplate.js';
import { fullCreateTemplate } from '../../view_templates/CreateTemplate.js';
export const createHandler = (gameCreationStepManager) => {
injectNavbar();
document.getElementById('game-creation-container').innerHTML = createTemplate;
document.getElementById('game-creation-container').innerHTML = fullCreateTemplate;
gameCreationStepManager.renderStep('creation-step-container', 1);
};

View File

@@ -31,6 +31,7 @@ const joinHandler = (e) => {
.then((res) => {
const json = JSON.parse(res.content);
UserUtility.setAnonymousUserId(json.cookie, json.environment);
resetJoinButtonState(e, res, joinHandler);
window.location = '/game/' + accessCode;
}).catch((res) => {
handleJoinError(e, res, joinHandler);
@@ -59,10 +60,14 @@ function sendJoinRequest (e, name, accessCode) {
);
}
function handleJoinError (e, res, joinHandler) {
function resetJoinButtonState (e, res, joinHandler) {
document.getElementById('join-game-form').onsubmit = joinHandler;
e.submitter.classList.remove('submitted');
e.submitter.setAttribute('value', 'Join');
}
function handleJoinError (e, res, joinHandler) {
resetJoinButtonState(e, res, joinHandler);
if (res.status === 404) {
toast('This game was not found.', 'error', true, true, 'long');

View File

@@ -663,8 +663,8 @@ input {
}
.info-message {
padding: 5px;
font-size: 16px;
padding: 10px;
font-size: 18px;
}
}

View File

@@ -385,7 +385,7 @@ select {
display: flex;
}
#game-time {
#creation-step-container #game-time {
display: flex;
flex-wrap: wrap;
border-radius: 5px;
@@ -673,7 +673,7 @@ input[type="number"] {
@media(max-width: 550px) {
#custom-roles-container, #deck-status-container {
min-width: 90%;
min-width: 85%;
}
h1 {
font-size: 32px;

View File

@@ -106,16 +106,66 @@
max-width: 17em;
}
#return-to-lobby-button, #end-of-game-buttons #return-to-lobby-button, #mod-transfer-button {
#save-role-changes-button {
padding: 10px;
font-size: 25px;
margin: 0.5em 0;
}
#save-role-changes-button img {
width: 20px;
margin-left: 10px;
}
#return-to-lobby-button,
#end-of-game-buttons #return-to-lobby-button,
#mod-transfer-button,
#edit-roles-button,
#save-role-changes-button {
background-color: #045EA6;
border: 2px solid #024070;
}
#return-to-lobby-button:hover, #end-of-game-buttons #return-to-lobby-button:hover, #mod-transfer-button:hover {
#return-to-lobby-button:hover,
#end-of-game-buttons #return-to-lobby-button:hover,
#mod-transfer-button:hover,
#edit-roles-button:hover,
#save-role-changes-button:hover {
background-color: rgba(0, 120, 215, 0.45);
border: 2px solid #045EA6;
}
#mid-game-role-editor {
display: flex;
border-radius: 5px;
position: fixed;
width: 100%;
height: 100%;
z-index: 100001;
background-color: #000000d4;
align-items: center;
justify-content: center;
font-family: 'signika-negative', sans-serif;
flex-direction: column;
overflow: auto;
}
#mid-game-role-editor #step-2 {
width: 100%;
display: flex;
justify-content: center;
overflow: auto;
align-items: center;
}
#save-button {
}
#mid-game-role-editor #custom-roles-container {
height: fit-content;
}
#play-pause-placeholder {
width: 60px;
height: 60px;
@@ -435,7 +485,7 @@ h1 {
background-color: #361a1a;
}
#role-name {
#game-role #role-name {
position: absolute;
top: 6%;
left: 50%;
@@ -461,7 +511,7 @@ h1 {
width: 78%;
}
#role-description {
#game-role #role-description {
overflow: auto;
position: absolute;
bottom: 6%;
@@ -479,6 +529,7 @@ h1 {
#game-link img {
width: 20px;
height: 20px;
margin-left: 0.5em;
}
@@ -529,26 +580,6 @@ label[for='moderator'] {
}
#start-game-prompt, #game-control-prompt {
padding: 0.5em 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
position: fixed;
z-index: 3;
font-family: 'signika-negative', sans-serif;
font-weight: 100;
box-shadow: 0 -6px 15px rgb(0 0 0 / 50%);
bottom: 0;
border-radius: 5px;
font-size: 20px;
height: 100px;
margin: 0 auto;
background-color: #1b1a24;
width: 100%;
}
#game-control-prompt {
padding: 0.5em 0;
display: flex;
flex-direction: row;
@@ -571,7 +602,7 @@ label[for='moderator'] {
background-color: #1b1a24;
}
#game-control-prompt button {
#game-control-prompt button, #start-game-prompt button {
margin: 0 15px;
min-width: 5em;
}
@@ -592,7 +623,7 @@ label[for='moderator'] {
box-shadow: 0 -6px 40px black;
}
#start-game-button, #end-game-button, #return-to-lobby-button {
#start-game-button, #end-game-button, #return-to-lobby-button, #edit-roles-button {
font-family: 'signika-negative', sans-serif !important;
padding: 10px;
border-radius: 5px;
@@ -610,7 +641,6 @@ label[for='moderator'] {
#start-game-button {
background-color: #1c8a36;
margin-bottom: 10px;
animation: shadow-pulse 1.5s infinite ease-out;
}
@@ -959,7 +989,7 @@ canvas {
height: 65px;
}
#start-game-button, #end-game-button, #return-to-lobby-button {
#start-game-button, #end-game-button, #return-to-lobby-button, #edit-roles-button {
font-size: 20px;
padding: 5px;
}

View File

@@ -1,4 +1,4 @@
const template =
export const hiddenMenus =
`<div id="modal-background" class="modal-background"></div>
<div tabindex="-1" id="role-modal" class="modal">
<form id="role-form">
@@ -49,7 +49,10 @@ const template =
<div class='modal-button-container single-button'>
<button id='close-deck-template-modal-button' class='cancel app-button'>Close</button>
</div>
</div>
</div>`;
export const fullCreateTemplate =
hiddenMenus + `
<h1>Create A Game</h1>
<div id="tracker-container">
<div id="creation-step-tracker">
@@ -69,5 +72,3 @@ const template =
<div class="animated-placeholder animated-placeholder-long"></div>
<div class="animated-placeholder animated-placeholder-long"></div>
</div>`;
export default template;

View File

@@ -14,6 +14,7 @@
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="/styles/GLOBAL.css">
<link rel="stylesheet" href="/styles/game.css">
<link rel="stylesheet" href="/styles/create.css">
<link rel="stylesheet" href="/styles/modal.css">
<link rel="stylesheet" href="/styles/confirmation.css">
<link rel="stylesheet" href="/styles/hamburgers.css">