Implement main list functionalities (keeping track of players and games)
This commit is contained in:
parent
f625b9954f
commit
16b356a92b
8 changed files with 221 additions and 126 deletions
|
@ -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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
85
js/GUI/Screen/Hall/Games.js
Normal file
85
js/GUI/Screen/Hall/Games.js
Normal 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');
|
||||||
|
}
|
||||||
|
}
|
62
js/GUI/Screen/Hall/Players.js
Normal file
62
js/GUI/Screen/Hall/Players.js
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
17
js/Table.js
17
js/Table.js
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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é";
|
||||||
|
|
|
@ -20,6 +20,6 @@
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listSelector .player {
|
.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue