Implement main list functionalities (keeping track of players and games)

This commit is contained in:
Tissevert 2020-01-11 19:46:41 +01:00
parent f625b9954f
commit 16b356a92b
8 changed files with 221 additions and 126 deletions

View File

@ -1,39 +1,17 @@
import * as Dom from UnitJS.Dom; import * as Dom from UnitJS.Dom;
import I18n; import I18n;
import * as ConnectedForm from GUI.ConnectedForm; import * as Players from GUI.Screen.Hall.Players;
import * as ListSelector from GUI.ListSelector; import * as Games from GUI.Screen.Hall.Games;
import Messaging; import Messaging;
import room as players from Room; import opponent from Room;
import Session; import Session;
import StatusHandler; import StatusHandler;
import Table;
var room = ConnectedForm.get('room');
var form = room.root;
var playersList = ListSelector.make('players', showPlayer);
var games = Table.make(game, 'date');
var gamesList = ListSelector.make('games', showGame);
var them = null;
return { return {
init: init init: init
}; };
function init() { function init() {
initDOMEvents();
initMessageHandlers();
}
function initDOMEvents() {
form.addEventListener('submit', function(e) {
e.preventDefault();
Messaging.send({tag: "Invitation", to: them});
});
form.them.addEventListener("input", function() {refreshPlayers();});
}
function initMessageHandlers() {
Messaging.addEventListener(["Okaeri"], function(o) { Messaging.addEventListener(["Okaeri"], function(o) {
refresh(); refresh();
}); });
@ -41,100 +19,33 @@ function initMessageHandlers() {
refresh(); refresh();
}); });
Messaging.addEventListener(["LogIn"], function(o) { Messaging.addEventListener(["LogIn"], function(o) {
if(!Session.is(o.from)) { refresh();
refresh();
}
}); });
Messaging.addEventListener(["LogOut"], function(o) { Messaging.addEventListener(["LogOut"], function(o) {
// Just in case there was a game proposal from that player, in which case the game proposal's ID is the player's ID
Games.table.remove(o.from);
refresh(); refresh();
}); });
Messaging.addEventListener(["Relay", "Invitation"], function(o) { Messaging.addEventListener(["Relay", "Invitation"], function(o) {
var from = players.get(o.from); StatusHandler.set("🎴");
// invitations should come only from known players, in doubt say «no» Games.table.insert(o.from, {vs: opponent(o.from), yourTurn: true});
if(from != undefined && from.name) { Games.refresh();
StatusHandler.set("🎴");
games.insert(o.from, from.name);
refreshGames();
} else {
Messaging.send({tag: "Answer", accept: false});
}
}); });
Messaging.addEventListener(["Relay", "Answer"], function(o) { Messaging.addEventListener(["Relay", "Answer"], function(o) {
games.remove(o.from); Games.table.remove(o.from);
refreshGames(); Games.refresh();
/*
if(o.message.accept) {
modules.screen.select("game");
}
*/
}); });
Messaging.addEventListener(["Game"], function(o) { Messaging.addEventListener(["Game"], function(o) {
var sessionKey = Session.getKey();
Games.table.insert(o.state.gameID, {
vs: opponent(o.state.public.nextPlayer[sessionKey]),
yourTurn: o.state.public.playing == sessionKey
});
Games.refresh();
}); });
} }
function showPlayer(player) {
return Dom.make('li', {
textContent: player.name,
onClick: function() {form.them.value = player.name; refreshPlayers();},
class: 'player'
});
}
function game(key, vs) {
return {
key: key,
vs: vs,
date: Date.now()
};
}
function showGame(game) {
return Dom.make('li', {}, [
Dom.make('button', {
textContent: I18n.get('accept'),
onClick: function() {
Messaging.send({tag: "Answer", accept: true, to: game.key});
}
}),
Dom.make('span', {textContent: 'A game vs. ' + game.vs}),
]);
}
function refresh() { function refresh() {
refreshPlayers(); Players.refresh();
refreshGames(); Games.refresh();
}
function refreshPlayers() {
var name = form.them.value;
them = null;
var filtered = players.getAll(
function(player) {return player.name.match(name);}
);
playersList.refresh(filtered);
var exact = filtered.find(exactMatch(name));
if(exact != undefined) {
them = exact.key;
} else if(filtered.length == 1) {
them = filtered[0].key;
} else if(filtered.length == 0) {
playersList.message.textContent = I18n.get(
name.length > 0 ? "notFound" : "alone"
);
}
room.enable(them != undefined);
}
function exactMatch(name) {
return function(player) {
return player.name === name;
};
}
function refreshGames() {
var sortedGames = games.getAll();
gamesList.refresh(sortedGames);
if(sortedGames.length < 1) {
gamesList.message.textContent = I18n.get('noGames');
}
} }

View File

@ -0,0 +1,85 @@
import * as ListSelector from GUI.ListSelector;
import I18n;
import Messaging;
import room from Room;
import dialog from GUI.Screen;
import Table;
import * as Dom from UnitJS.Dom;
var games = Table.make(game, 'date');
var list = ListSelector.make('games', showGame);
return {
refresh: refresh,
table: games
};
function game(key, config) {
return {
key: key,
vs: config.vs,
yourTurn: config.yourTurn,
date: Date.now()
};
}
function showGame(game) {
var liContent;
if(game.key.match(/^Player#/)) { // Game proposals use the ID of the opponent as ID
liContent = gameProposal(game);
} else {
liContent = pendingGame(game);
}
return Dom.make('li', {}, liContent);
}
function gameProposal(game) {
var properties = {
textContent: I18n.get('proposedGame')(game.yourTurn, game.vs.name),
};
if(game.yourTurn) {
properties.onClick = answerDialog(game.vs.id);
properties.class = 'clickable';
}
return [Dom.make('span', properties)];
}
function pendingGame(game) {
var status = room.get(game.vs.id) != undefined ? 'active' : 'inactive'
return [
Dom.make('span', { textContent: status}),
Dom.make('a', {
textContent: I18n.get('pendingGame')(game.yourTurn, game.vs.name),
href: '/game/' + game.key
})
];
}
function answer(key, accept) {
return function() {
Messaging.send({tag: "Answer", accept: accept, to: key});
games.remove(key);
refresh();
}
}
function answerDialog(key) {
return function() {
dialog({
text: I18n.get('questionAccept'),
answers: [
{label: 'accept', action: answer(key, true)},
{label: 'decline', action: answer(key, false)},
{label: 'notYet', action: function() {}}
]
});
};
}
function refresh() {
var sortedGames = games.getAll();
list.refresh(sortedGames);
if(sortedGames.length < 1) {
list.message.textContent = I18n.get('noGames');
}
}

View File

@ -0,0 +1,62 @@
import * as ConnectedForm from GUI.ConnectedForm;
import * as ListSelector from GUI.ListSelector;
import * as Games from GUI.Screen.Hall.Games;
import I18n;
import Messaging;
import {opponent, room} from Room;
import * as Dom from UnitJS.Dom;
var form = ConnectedForm.get('room');
var list = ListSelector.make('players', showPlayer);
var them = null;
initDOM();
return {
refresh: refresh
};
function initDOM() {
form.root.getElementsByTagName('label')[0].textContent = I18n.get('startGameWith');
form.root.invite.value = I18n.get('invite');
form.root.addEventListener('submit', function(e) {
e.preventDefault();
Messaging.send({tag: "Invitation", to: them});
Games.table.insert(them, {vs: opponent(them), yourTurn: false});
Games.refresh();
});
form.root.them.addEventListener("input", function() {refresh();});
}
function showPlayer(player) {
return Dom.make('li', {
textContent: player.name,
onClick: function() {form.root.them.value = player.name; refresh();},
class: 'clickable'
});
}
function refresh() {
var name = form.root.them.value;
them = null;
var filtered = room.getAll(
function(player) {return player.name.match(name);}
);
list.refresh(filtered);
var exact = filtered.find(exactMatch(name));
if(exact != undefined) {
them = exact.key;
} else if(filtered.length == 1) {
them = filtered[0].key;
} else if(filtered.length == 0) {
list.message.textContent = I18n.get(
name.length > 0 ? "notFound" : "alone"
);
}
form.enable(them != undefined);
}
function exactMatch(name) {
return function(player) {
return player.name === name;
};
}

View File

@ -6,9 +6,14 @@ var room = Table.make(player, 'name');
initMessageHandlers(); initMessageHandlers();
return { return {
opponent: opponent,
room: room room: room
}; };
function opponent(key) {
return {id: key, name: room.get(key).name};
}
function player(key, name) { function player(key, name) {
return { return {
key: key, key: key,

View File

@ -1,7 +1,6 @@
import Messaging; import Messaging;
import Save; import Save;
var key = null;
var playerKey = null; var playerKey = null;
var name = null; var name = null;
var loggedIn = false; var loggedIn = false;
@ -30,7 +29,7 @@ function is(somePlayerKey) {
} }
function getKey() { function getKey() {
return key; return playerKey;
} }
function isLoggedIn() { function isLoggedIn() {

View File

@ -26,9 +26,20 @@ function Table(itemMaker, sortCriterion) {
items[key] = itemMaker(key, value); items[key] = itemMaker(key, value);
} }
function insertAll(itemsByKey) { function insertAll(newItems) {
for(var key in itemsByKey) { for(var key in newItems) {
insert(key, itemsByKey[key]); insert(key, newItems[key]);
}
}
function update(mapper) {
for(var key in items) {
var newValue = mapper(items[key]);
if(newValue != undefined) {
insert(key, newValue);
} else {
remove(key);
}
} }
} }

View File

@ -12,16 +12,13 @@ return {
SusukiGrass: "susuki grass", SusukiGrass: "susuki grass",
Willow: "willow", Willow: "willow",
Wisteria: "wisteria", Wisteria: "wisteria",
accept: "Accept", accept: "Let's go !",
alone: "No one to play with yet ! Wait a little", alone: "No one to play with yet ! Wait a little",
decline: "Decline", decline: "No thanks",
endRound: "End the round", endRound: "End the round",
endGame: "Return to main menu", endGame: "Return to main menu",
join: "Join", join: "Join",
invite: "Invite", invite: "Invite",
invited: function(name) {
return name + " has invited you to a game";
},
koikoi: "KoiKoi !!", koikoi: "KoiKoi !!",
leave: "Leave", leave: "Leave",
lost: "You lost the game", lost: "You lost the game",
@ -30,11 +27,25 @@ return {
}, },
noGames: "No games being played", noGames: "No games being played",
notFound: "No one goes by that name", notFound: "No one goes by that name",
notYet: "Not yet",
ok: "Ok",
pendingGame: function(yourTurn, name) {
var whose = yourTurn ? 'your' : name + "'s";
return 'Game vs. ' + name + ' (' + whose + ' turn)';
},
pickName: "Pick a name you like", pickName: "Pick a name you like",
playing: function(name) { playing: function(name) {
return name + " is playing"; return name + " is playing";
}, },
ok: "Ok", proposedGame: function(yourTurn, name) {
var proposed = " proposed a game";
if(yourTurn) {
return name + proposed;
} else {
return "You" + proposed + " to " + name;
}
},
questionAccept: "Do you want to start the game ?",
startGameWith: "Start a game with", startGameWith: "Start a game with",
theyScored: function(name) { theyScored: function(name) {
return name + " scored"; return name + " scored";
@ -56,16 +67,13 @@ return {
SusukiGrass: "herbes susukis", SusukiGrass: "herbes susukis",
Willow: "saules", Willow: "saules",
Wisteria: "glycines", Wisteria: "glycines",
accept: "Accepter", accept: "C'est parti !",
alone: "Personne pour jouer pour l'instant ! Attendez un peu", alone: "Personne pour jouer pour l'instant ! Attendez un peu",
decline: "Refuser", decline: "Non merci",
endRound: "Finir la manche", endRound: "Finir la manche",
endGame: "Retourner au menu principal", endGame: "Retourner au menu principal",
join: "Entrer", join: "Entrer",
invite: "Inviter", invite: "Inviter",
invited: function(name) {
return name + " vous propose une partie";
},
koikoi: "KoiKoi !!", koikoi: "KoiKoi !!",
leave: "Partir", leave: "Partir",
lost: "Vous avez perdu", lost: "Vous avez perdu",
@ -74,11 +82,25 @@ return {
}, },
noGames: "Aucune partie en cours", noGames: "Aucune partie en cours",
notFound: "Personne ne s'appelle comme ça", notFound: "Personne ne s'appelle comme ça",
notYet: "Pas pour l'instant",
ok: "Ok",
pendingGame: function(yourTurn, name) {
var whose = yourTurn ? 'vous' : name;
return 'Partie en cours contre ' + name + ' (à ' + whose + ')';
},
pickName: "Choisissez votre nom", pickName: "Choisissez votre nom",
playing: function(name) { playing: function(name) {
return "C'est à " + name; return "C'est à " + name;
}, },
ok: "Ok", proposedGame: function(yourTurn, name) {
var proposed = " proposé une partie";
if(yourTurn) {
return name + " vous a" + proposed;
} else {
return "Vous avez" + proposed + " à " + name;
}
},
questionAccept: "Voulez-vous commencer la partie ?",
startGameWith: "Commencer une partie avec", startGameWith: "Commencer une partie avec",
theyScored: function(name) { theyScored: function(name) {
return name + " a marqué"; return name + " a marqué";

View File

@ -20,6 +20,6 @@
padding-left: 0; padding-left: 0;
} }
.listSelector .player { .clickable {
cursor: pointer; cursor: pointer;
} }