Restructured app

This commit is contained in:
Chris Blanchard 2015-10-02 15:53:11 +01:00
parent e5ae57d8c0
commit 2eb33f3809
12 changed files with 374 additions and 320 deletions

View file

@ -20,7 +20,7 @@ var winston = require("winston");
module.exports = namespace => { module.exports = namespace => {
var broadcastUpdate = message => { var broadcastUpdate = message => {
namespace.emit("message:append", { chatHistory: [message.toJson()]}); namespace.emit("message:append", { messages: [message.toJson()]});
}; };
var refreshMessages = socket => { var refreshMessages = socket => {
@ -33,7 +33,7 @@ module.exports = namespace => {
var receiver = (socket === undefined) ? namespace : socket; var receiver = (socket === undefined) ? namespace : socket;
receiver.emit("message:refresh", { receiver.emit("message:refresh", {
chatHistory: messages messages: messages
}); });
}); });
}; };

View file

@ -26,15 +26,27 @@ var _ = require("lodash");
var winston = require("winston"); var winston = require("winston");
module.exports = function (namespace) { module.exports = function (namespace) {
// var refreshGather = _.debounce(function () {
// namespace.sockets.forEach(function (socket) {
// socket.emit("gather:refresh", {
// gather: Gather.current.toJson(),
// currentGatherer: Gather.current.getGatherer(socket._user),
// maps: Map.list,
// servers: Server.list,
// previousGather: Gather.previous ? Gather.previous.toJson() : null
// });
// });
// }, 200, {
// leading: true,
// trailing: true
// });
var refreshGather = _.debounce(function () { var refreshGather = _.debounce(function () {
namespace.sockets.forEach(function (socket) { namespace.emit("gather:refresh", {
socket.emit("gather:refresh", { gather: Gather.current ? Gather.current.toJson() : null,
gather: Gather.current.toJson(), maps: Map.list,
currentGatherer: Gather.current.getGatherer(socket._user), servers: Server.list,
maps: Map.list, previousGather: Gather.previous ? Gather.previous.toJson() : null
servers: Server.list,
previousGather: Gather.previous ? Gather.previous.toJson() : null
});
}); });
}, 200, { }, 200, {
leading: true, leading: true,
@ -54,6 +66,13 @@ module.exports = function (namespace) {
Gather.registerCallback('onDone', refreshGather); Gather.registerCallback('onDone', refreshGather);
Gather.registerCallback('onEvent', refreshGather); Gather.registerCallback('onEvent', refreshGather);
Gather.registerCallback('onEvent', (event, from, to) => {
if (from === 'gathering' && to === 'election') {
namespace.emit("notification", {
sound: "gather_starting"
});
}
});
Gather.onArchiveUpdate(refreshArchive); Gather.onArchiveUpdate(refreshArchive);
Gather.restart(); Gather.restart();

View file

@ -67,7 +67,7 @@ StateMachine.create({
callbacks: { callbacks: {
// Callbacks for events // Callbacks for events
onafterevent: function () { onafterevent: function () {
this.onEvent.call(this); this.onEvent.apply(this, [].slice.call(arguments));
}, },
// Gathering State // Gathering State
@ -155,7 +155,7 @@ StateMachine.create({
// On enter done // On enter done
onenterdone: function () { onenterdone: function () {
this.done.time = new Date(); this.done.time = new Date();
this.onDone.call(this); this.onDone.apply(this, [].slice.call(arguments));
} }
} }
}); });

View file

@ -12,21 +12,17 @@ gatherCallbacks['onDone'] = [function () {
rotateGather(); rotateGather();
}]; }];
let executeCallbacks = (context, type) => {
let cbs = gatherCallbacks[type];
if (!cbs) return;
cbs.forEach(function (cb) {
cb.call(context);
});
};
let newGather = () => { let newGather = () => {
return SingletonClass.current = Gather({ return SingletonClass.current = Gather({
onEvent: function () { onEvent: function () {
executeCallbacks(this, 'onEvent') gatherCallbacks['onEvent'].forEach(cb => {
cb.apply(this, [].slice.call(arguments))
});
}, },
onDone: function () { onDone: function () {
executeCallbacks(this, 'onDone') gatherCallbacks['onDone'].forEach(cb => {
cb.apply(this, [].slice.call(arguments))
});
} }
}); });
}; };

View file

@ -17,7 +17,8 @@ var SelectPlayerButton = React.createClass({
} else if (this.props.gatherer.team !== "lobby") { } else if (this.props.gatherer.team !== "lobby") {
button = <button button = <button
data-disabled="true" data-disabled="true"
className="btn btn-xs btn-default team-label"> {_.capitalize(this.props.gatherer.team)} className="btn btn-xs btn-default team-label">
{_.capitalize(this.props.gatherer.team)}
</button>; </button>;
} else { } else {
button = <button button = <button
@ -123,17 +124,18 @@ var ElectionProgressBar = React.createClass({
var ProgressBar = React.createClass({ var ProgressBar = React.createClass({
render() { render() {
let progress = this.props.progress;
var style = { var style = {
width: Math.round((this.props.progress.num / this.props.progress.den * 100)) + "%" width: Math.round((progress.num / progress.den * 100)) + "%"
}; };
var barMessage = this.props.progress.barMessage || ""; var barMessage = progress.barMessage || "";
return ( return (
<div className="progress"> <div className="progress">
<div className="progress-bar progress-bar-striped active" <div className="progress-bar progress-bar-striped active"
data-role="progressbar" data-role="progressbar"
data-aria-valuenow={this.props.progress.num} data-aria-valuenow={progress.num}
data-aria-valuemin="0" data-aria-valuemin="0"
data-aria-valuemax={this.props.progress.den} data-aria-valuemax={progress.den}
style={style}>{barMessage} style={style}>{barMessage}
</div> </div>
</div> </div>
@ -161,7 +163,8 @@ var GatherProgress = React.createClass({
var num = this.props.gather.gatherers.length; var num = this.props.gather.gatherers.length;
var den = 12; var den = 12;
var remaining = den - num; var remaining = den - num;
var message = (remaining === 1) ? "Waiting for last player" : "Waiting for " + remaining + " more players"; var message = (remaining === 1) ?
"Waiting for last player" : `Waiting for ${remaining} more players`;
return { return {
num: num, num: num,
den: den, den: den,
@ -245,13 +248,16 @@ var TeamSpeakButton = React.createClass({
return this.teamSpeakUrl(this.props.alien); return this.teamSpeakUrl(this.props.alien);
}, },
teamSpeakUrl(conn) { teamSpeakUrl(conn) {
let params = `channel=${encodeURIComponent(conn.channel)}&channelpassword=${encodeURIComponent(conn.password)}`; let params = `channel=${encodeURIComponent(conn.channel)}&
channelpassword=${encodeURIComponent(conn.password)}`;
return (`${this.props.url}?${params}`); return (`${this.props.url}?${params}`);
}, },
render() { render() {
return ( return (
<div className="btn-group dropup"> <div className="btn-group dropup">
<button type="button" className="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <button type="button"
className="btn btn-primary dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Teamspeak <span className="caret"></span> Teamspeak <span className="caret"></span>
</button> </button>
<ul className="dropdown-menu"> <ul className="dropdown-menu">
@ -259,13 +265,17 @@ var TeamSpeakButton = React.createClass({
<li><a href={this.marineUrl()}>Join Marine Teamspeak</a></li> <li><a href={this.marineUrl()}>Join Marine Teamspeak</a></li>
<li><a href={this.alienUrl()}>Join Alien Teamspeak</a></li> <li><a href={this.alienUrl()}>Join Alien Teamspeak</a></li>
<li role="separator" className="divider"></li> <li role="separator" className="divider"></li>
<li><a href="#" data-toggle="modal" data-target="#teamspeakmodal">Teamspeak Details</a></li> <li><a href="#" data-toggle="modal" data-target="#teamspeakmodal">
Teamspeak Details</a></li>
</ul> </ul>
<div className="modal fade text-left" id="teamspeakmodal"> <div className="modal fade text-left" id="teamspeakmodal">
<div className="modal-dialog"> <div className="modal-dialog">
<div className="modal-content"> <div className="modal-content">
<div className="modal-header"> <div className="modal-header">
<button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> <button type="button"
className="close"
data-dismiss="modal"
aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 className="modal-title">Teamspeak Server Information</h4> <h4 className="modal-title">Teamspeak Server Information</h4>
</div> </div>
<div className="modal-body"> <div className="modal-body">
@ -320,13 +330,14 @@ var JoinGatherButton = React.createClass({
}, },
render() { render() {
let currentGatherer = this.props.currentGatherer; let gather = this.props.gather;
if (currentGatherer) { let thisGatherer = this.props.thisGatherer;
if (thisGatherer) {
return <button return <button
onClick={this.leaveGather} onClick={this.leaveGather}
className="btn btn-danger">Leave Gather</button>; className="btn btn-danger">Leave Gather</button>;
} }
if (this.props.gather.state === 'gathering') { if (gather.state === 'gathering') {
let cooldownTime = this.cooldownTime(); let cooldownTime = this.cooldownTime();
if (cooldownTime) { if (cooldownTime) {
return <CooloffButton timeRemaining={cooldownTime} />; return <CooloffButton timeRemaining={cooldownTime} />;
@ -363,8 +374,9 @@ var GatherActions = React.createClass({
}, },
regatherVotes() { regatherVotes() {
if (!this.props.gather) return 0; let gather = this.props.gather;
return this.props.gather.gatherers.reduce((acc, gatherer) => { if (!gather) return 0;
return gather.gatherers.reduce((acc, gatherer) => {
if (gatherer.regatherVote) acc++; if (gatherer.regatherVote) acc++;
return acc; return acc;
}, 0); }, 0);
@ -372,21 +384,21 @@ var GatherActions = React.createClass({
render() { render() {
let regatherButton; let regatherButton;
let currentGatherer = this.props.currentGatherer; let user = this.props.user;
if (currentGatherer) { let gather = this.props.gather;
let thisGatherer = this.props.thisGatherer;
if (thisGatherer) {
let regatherVotes = this.regatherVotes(); let regatherVotes = this.regatherVotes();
if (currentGatherer.regatherVote) { if (thisGatherer.regatherVote) {
regatherButton = ( regatherButton = <button value="false" onClick={this.voteRegather}
<button className="btn btn-danger">
value="false" {`Voted Regather (${regatherVotes}/8)`}
onClick={this.voteRegather} </button>;
className="btn btn-danger">{`Voted Regather (${regatherVotes}/8)`}</button>);
} else { } else {
regatherButton = ( regatherButton = <button value="true" onClick={this.voteRegather}
<button className="btn btn-danger">
value="true" {`Vote Regather (${regatherVotes}/8)`}
onClick={this.voteRegather} </button>;
className="btn btn-danger">{`Vote Regather (${regatherVotes}/8)`}</button>);
} }
} }
@ -400,10 +412,8 @@ var GatherActions = React.createClass({
{regatherButton} {regatherButton}
</li> </li>
<li> <li>
<JoinGatherButton <JoinGatherButton gather={gather} thisGatherer={thisGatherer}
gather={this.props.gather} user={user} />
currentGatherer={this.props.currentGatherer}
user={this.props.user} />
</li> </li>
</ul> </ul>
</div> </div>
@ -432,10 +442,12 @@ var VoteButton = React.createClass({
}, },
render() { render() {
if (this.props.currentGatherer === null) { let candidate = this.props.candidate;
let thisGatherer = this.props.thisGatherer;
if (thisGatherer === null) {
return false; return false;
} }
if (this.props.currentGatherer.leaderVote === this.props.candidate.id) { if (thisGatherer.leaderVote === candidate.id) {
return ( return (
<button <button
onClick={this.cancelVote} onClick={this.cancelVote}
@ -447,7 +459,7 @@ var VoteButton = React.createClass({
<button <button
onClick={this.vote} onClick={this.vote}
className="btn btn-xs btn-primary vote-button" className="btn btn-xs btn-primary vote-button"
value={this.props.candidate.id}>Vote value={candidate.id}>Vote
</button> </button>
); );
} }
@ -474,23 +486,22 @@ var ServerVoting = React.createClass({
}, },
render() { render() {
var self = this; let self = this;
let servers = self.props.servers let thisGatherer = self.props.thisGatherer;
.sort((a, b) => { let servers = self.props.servers.sort((a, b) => {
var aVotes = self.votesForServer(a); var aVotes = self.votesForServer(a);
var bVotes = self.votesForServer(b); var bVotes = self.votesForServer(b);
return bVotes - aVotes; return bVotes - aVotes;
}) }).map(server => {
.map(server => {
let votes = self.votesForServer(server); let votes = self.votesForServer(server);
if (self.props.currentGatherer.serverVote === server.id) { if (thisGatherer.serverVote === server.id) {
return ( return (
<a href="#" <a href="#"
className="list-group-item list-group-item-success" className="list-group-item list-group-item-success"
onClick={ e => e.preventDefault() } onClick={ e => e.preventDefault() }
key={server.id}> key={server.id}>
<span className="badge">{votes}</span> <span className="badge">{votes}</span>
{server.name || server.description || server.dns} {server.name || server.description}
</a> </a>
); );
} else { } else {
@ -499,13 +510,13 @@ var ServerVoting = React.createClass({
onClick={self.voteHandler(server.id)} onClick={self.voteHandler(server.id)}
key={server.id}> key={server.id}>
<span className="badge">{votes}</span> <span className="badge">{votes}</span>
{server.name || server.description || server.dns} {server.name || server.description}
</a> </a>
); );
} }
}); });
let voted = self.props.currentGatherer.serverVote !== null; let voted = thisGatherer.serverVote !== null;
return ( return (
<div className="panel panel-primary"> <div className="panel panel-primary">
@ -541,38 +552,37 @@ var MapVoting = React.createClass({
render() { render() {
var self = this; var self = this;
let maps = self.props.maps let thisGatherer = self.props.thisGatherer
.sort((a, b) => { let maps = self.props.maps.sort((a, b) => {
var aVotes = self.votesForMap(a); var aVotes = self.votesForMap(a);
var bVotes = self.votesForMap(b); var bVotes = self.votesForMap(b);
return bVotes - aVotes; return bVotes - aVotes;
}) }).map(map => {
.map(map => { let votes = self.votesForMap(map);
let votes = self.votesForMap(map); if (thisGatherer.mapVote === map.id) {
if (self.props.currentGatherer.mapVote === map.id) { return (
return ( <a href="#"
<a href="#" key={map.id}
key={map.id} onClick={ e => e.preventDefault() }
onClick={ e => e.preventDefault() } className="list-group-item list-group-item-success">
className="list-group-item list-group-item-success"> <span className="badge">{votes}</span>
<span className="badge">{votes}</span> {map.name}
{map.name} </a>
</a> );
); } else {
} else { return (
return ( <a href="#"
<a href="#" key={map.id}
key={map.id} onClick={self.voteHandler(map.id)}
onClick={self.voteHandler(map.id)} className="list-group-item">
className="list-group-item"> <span className="badge">{votes}</span>
<span className="badge">{votes}</span> {map.name}
{map.name} </a>
</a> );
); }
} });
});
let voted = (self.props.currentGatherer.mapVote !== null); let voted = (thisGatherer.mapVote !== null);
return ( return (
<div className="panel panel-primary"> <div className="panel panel-primary">
@ -590,64 +600,78 @@ var MapVoting = React.createClass({
var Gather = React.createClass({ var Gather = React.createClass({
getDefaultProps() { getDefaultProps() {
return { return {
gather: { gather: null,
gatherers: [] user: null
}
} }
}, },
checkForStateChange: function (data) { // checkForStateChange: function (data) {
let previousState = this.props.gather.state; // let previousState = this.props.gather.state;
let newState = data.gather.state; // let newState = data.gather.state;
if (newState === previousState) return; // if (newState === previousState) return;
// Callbacks for new states // // Callbacks for new states
if (newState === "election" // if (newState === "election"
&& previousState === "gathering" // && previousState === "gathering"
&& data.currentGatherer) { // && data.currentGatherer) {
soundController.playGatherMusic(); // soundController.playGatherMusic();
// }
// },
thisGatherer() {
let gather = this.props.gather;
let user = this.props.user;
if (gather && user && gather.gatherers.length) {
return gather.gatherers
.filter(gatherer => gatherer.id === user.id)
.pop() || null;
} }
}, return null;
componentDidMount() {
var self = this;
socket.on("users:update", data => self.setProps({user: data.currentUser}));
socket.on("gather:refresh", (data) => {
self.checkForStateChange(data);
self.setProps(data)
});
}, },
render() { render() {
if (this.props.gather.state === 'done') { let gather = this.props.gather;
return (<CompletedGather show={true} {...this.props} />); let thisGatherer = this.thisGatherer();
let servers = this.props.servers;
let maps = this.props.maps;
let user = this.props.user;
if (gather === null) return;
if (gather.state === 'done') {
return <CompletedGather maps={maps} servers={servers} show={true}
gather={this.props.previousGather} />;
} }
var voting; let voting;
if (this.props.currentGatherer) { if (thisGatherer) {
let state = this.props.gather.state; let state = gather.state;
if (state === 'gathering' || state === 'election') { if (state === 'gathering' || state === 'election') {
voting = ( voting = (
<div className="row add-top"> <div className="row add-top">
<div className="col-sm-6"> <div className="col-sm-6">
<MapVoting {...this.props} /> <MapVoting gather={gather} maps={maps}
thisGatherer={thisGatherer} />
</div> </div>
<div className="col-sm-6"> <div className="col-sm-6">
<ServerVoting {...this.props} /> <ServerVoting gather={gather} servers={servers}
thisGatherer={thisGatherer} />
</div> </div>
</div> </div>
); );
} else { } else {
voting = <GatherVotingResults gather={this.props.gather} servers={this.props.servers} maps={this.props.maps} />; voting = <GatherVotingResults gather={gather}
servers={servers}
maps={maps} />;
} }
} }
var gatherTeams; let gatherTeams;
if (this.props.gather.state === 'selection') { if (gather.state === 'selection') {
gatherTeams = <GatherTeams gather={this.props.gather} /> gatherTeams = <GatherTeams gather={gather} />;
} }
var previousGather; let previousGather;
if (this.props.previousGather) { if (this.props.previousGather) {
previousGather = ( previousGather = (
<div className="panel panel-primary"> <div className="panel panel-primary">
@ -655,9 +679,8 @@ var Gather = React.createClass({
Previous Gather Previous Gather
</div> </div>
<div className="panel-body"> <div className="panel-body">
<CompletedGather {...this.props} <CompletedGather maps={maps} servers={servers} show={true}
gather={this.props.previousGather} gather={this.props.previousGather} />
show={true} />
</div> </div>
</div> </div>
); );
@ -667,13 +690,13 @@ var Gather = React.createClass({
<div className="panel panel-primary add-bottom"> <div className="panel panel-primary add-bottom">
<div className="panel-heading">Current Gather</div> <div className="panel-heading">Current Gather</div>
<div className="panel-body"> <div className="panel-body">
<GatherProgress {...this.props} /> <GatherProgress gather={gather} />
</div> </div>
</div> </div>
<Gatherers {...this.props} /> <Gatherers gather={gather} user={user} thisGatherer={thisGatherer} />
{gatherTeams} {gatherTeams}
{voting} {voting}
<GatherActions {...this.props} /> <GatherActions gather={gather} user={user} thisGatherer={thisGatherer} />
{previousGather} {previousGather}
</div> </div>
); );
@ -688,8 +711,9 @@ var LifeformIcons = React.createClass({
gathererLifeforms() { gathererLifeforms() {
let lifeforms = []; let lifeforms = [];
let gatherer = this.props.gatherer; let gatherer = this.props.gatherer;
for (let attr in gatherer.user.profile.abilities) { let abilities = gatherer.user.profile.abilities;
if (gatherer.user.profile.abilities[attr]) lifeforms.push(_.capitalize(attr)); for (let attr in abilities) {
if (abilities[attr]) lifeforms.push(_.capitalize(attr));
} }
return lifeforms; return lifeforms;
}, },
@ -732,18 +756,22 @@ var Gatherers = React.createClass({
}, },
render() { render() {
var self = this; let self = this;
var user = this.props.user; let user = this.props.user;
var admin = (user && user.admin); let gather = this.props.gather;
var gatherers = this.props.gather.gatherers let admin = (user && user.admin);
let thisGatherer = this.props.thisGatherer;
let gatherers = gather.gatherers
.sort((a, b) => { .sort((a, b) => {
return (b.user.hive.skill || 1000) - (a.user.hive.skill || 1000); return (b.user.hive.skill || 1000) - (a.user.hive.skill || 1000);
}) })
.map(gatherer => { .map(gatherer => {
if (gatherer.user.country) { if (gatherer.user.country) {
var country = (<img src="images/blank.gif" var country = (
className={"flag flag-" + gatherer.user.country.toLowerCase()} <img src="images/blank.gif"
alt={gatherer.user.country} />); className={"flag flag-" + gatherer.user.country.toLowerCase()}
alt={gatherer.user.country} />
);
}; };
let skill = gatherer.user.profile.skill || "Not Available"; let skill = gatherer.user.profile.skill || "Not Available";
@ -760,23 +788,25 @@ var Gatherers = React.createClass({
let team = (gatherer.user.team) ? gatherer.user.team.name : "None"; let team = (gatherer.user.team) ? gatherer.user.team.name : "None";
let action; let action;
if (self.props.gather.state === "election") { if (gather.state === "election") {
var votes = self.props.gather.gatherers.reduce((acc, voter) => { let votes = gather.gatherers.reduce((acc, voter) => {
if (voter.leaderVote === gatherer.id) acc++; if (voter.leaderVote === gatherer.id) acc++;
return acc; return acc;
}, 0) }, 0)
action = ( action = (
<span> <span>
<span className="badge add-right">{votes + " votes"}</span> <span className="badge add-right">{votes + " votes"}</span>
<VoteButton currentGatherer={self.props.currentGatherer} candidate={gatherer} /> <VoteButton
thisGatherer={thisGatherer}
candidate={gatherer} />
</span> </span>
); );
} }
if (self.props.gather.state === 'selection') { if (gather.state === 'selection') {
if (self.props.currentGatherer && if (thisGatherer &&
self.props.currentGatherer.leader && thisGatherer.leader &&
self.props.currentGatherer.team === self.props.gather.pickingTurn) { thisGatherer.team === gather.pickingTurn) {
action = ( action = (
<span> <span>
<SelectPlayerButton gatherer={gatherer} /> <SelectPlayerButton gatherer={gatherer} />
@ -784,16 +814,21 @@ var Gatherers = React.createClass({
); );
} else { } else {
if (gatherer.leader) { if (gatherer.leader) {
action = (<span className={`label label-padding label-${gatherer.team} team-label`}>Leader</span>); action = (<span className={`label label-padding
label-${gatherer.team}
team-label`}>Leader</span>);
} else if (gatherer.team !== "lobby") { } else if (gatherer.team !== "lobby") {
action = (<span className={`label label-padding label-${gatherer.team} team-label`}>{_.capitalize(gatherer.team)}</span>); action = (<span className={`label label-padding
label-${gatherer.team}
team-label`}>{_.capitalize(gatherer.team)}</span>);
} else { } else {
action = (<span className="label label-padding label-default team-label">Lobby</span>); action = (<span className="label label-padding label-default team-label">
Lobby</span>);
} }
} }
} }
var adminOptions; let adminOptions;
if (admin) { if (admin) {
adminOptions = [ adminOptions = [
<dt>Admin</dt>, <dt>Admin</dt>,
@ -806,14 +841,15 @@ var Gatherers = React.createClass({
</button>&nbsp; </button>&nbsp;
<AssumeUserIdButton <AssumeUserIdButton
gatherer={gatherer} gatherer={gatherer}
currentUser={this.props.user} /> currentUser={user} />
</dd> </dd>
] ]
} }
let tabColor = gatherer.team !== "lobby" ? `panel-${gatherer.team}` : "panel-info"; let tabColor = gatherer.team !== "lobby" ? `panel-${gatherer.team}` : "panel-info";
return ( return (
<div className={`panel ${tabColor} gatherer-panel`} key={gatherer.user.id} data-userid={gatherer.user.id}> <div className={`panel ${tabColor} gatherer-panel`}
key={gatherer.user.id} data-userid={gatherer.user.id}>
<div className="panel-heading"> <div className="panel-heading">
<h4 className="panel-title"> <h4 className="panel-title">
{country} {gatherer.user.username} {country} {gatherer.user.username}
@ -846,9 +882,12 @@ var Gatherers = React.createClass({
</div> </div>
); );
}) })
if (this.props.gather.gatherers.length) { if (gather.gatherers.length) {
return ( return (
<div class="panel-group" role="tablist" aria-multiselectable="true" id="gatherers-panel"> <div class="panel-group"
role="tablist"
aria-multiselectable="true"
id="gatherers-panel">
{gatherers} {gatherers}
</div> </div>
); );
@ -887,11 +926,14 @@ var CompletedGather = React.createClass({
render() { render() {
let gatherInfo = []; let gatherInfo = [];
let gather = this.props.gather;
let maps = this.props.maps;
let servers = this.props.servers;
if (this.state.show) { if (this.state.show) {
gatherInfo.push(<GatherTeams gather={this.props.gather} />); gatherInfo.push(<GatherTeams gather={gather} />);
gatherInfo.push(<GatherVotingResults gather={this.props.gather} gatherInfo.push(<GatherVotingResults gather={gather}
maps={this.props.maps} maps={maps}
servers={this.props.servers}/>); servers={servers}/>);
} }
return ( return (
<div> <div>
@ -947,7 +989,8 @@ var GatherVotingResults = React.createClass({
{password} {password}
</dl> </dl>
<p> <p>
<a href={["steam://connect", server.ip +":"+server.port, server.password].join("/")} <a href={`steam://connect/${server.ip}:${server.port}/
${server.password}`}
className="btn btn-primary max-width">Join Server</a> className="btn btn-primary max-width">Join Server</a>
</p> </p>
</div> </div>
@ -957,25 +1000,6 @@ var GatherVotingResults = React.createClass({
}); });
var ArchivedGathers = React.createClass({ var ArchivedGathers = React.createClass({
componentDidMount() {
let self = this;
socket.on("gather:archive:refresh", data => {
self.setProps({
archive: data.archive,
maps: data.maps,
servers: data.servers
});
});
},
getDefaultProps() {
return {
archive: [],
maps: [],
servers: []
}
},
render() { render() {
let archive = this.props.archive let archive = this.props.archive
.sort((a, b) => { .sort((a, b) => {
@ -983,6 +1007,7 @@ var ArchivedGathers = React.createClass({
}) })
.map(archivedGather => { .map(archivedGather => {
return <CompletedGather return <CompletedGather
id={archivedGather.gather.done.time}
show={false} show={false}
gather={archivedGather.gather} gather={archivedGather.gather}
maps={this.props.maps} maps={this.props.maps}
@ -999,5 +1024,3 @@ var ArchivedGathers = React.createClass({
); );
} }
}); });

View file

@ -1,7 +1,6 @@
"use strict"; "use strict";
var socket; var socket, soundController;
var soundController;
var initialiseVisibilityMonitoring = (socket) => { var initialiseVisibilityMonitoring = (socket) => {
let hidden, visibilityChange; let hidden, visibilityChange;
@ -28,29 +27,11 @@ var initialiseVisibilityMonitoring = (socket) => {
}, false); }, false);
} }
var removeAuthWidget = () => { var removeAuthWidget = () => $("#authenticating").remove();
$("#authenticating").remove();
};
var showAuthenticationNotice = () => { var showAuthenticationNotice = () => $("#auth-required").show();
$("#auth-required").show();
};
var showGatherBanNotice = () => { var showGatherBanNotice = () => $("#gather-banned").show();
$("#gather-banned").show();
};
var renderPage = (socket) => {
// initialiseVisibilityMonitoring(socket);
soundController = new SoundController();
// React.render(<UserMenu />, document.getElementById('side-menu'));
// React.render(<Chatroom />, document.getElementById('chatroom'));
// React.render(<Gather />, document.getElementById('gathers'));
// React.render(<CurrentUser />, document.getElementById('currentuser'));
// React.render(<SoundPanel />, document.getElementById('soundcontroller'));
// React.render(<ArchivedGathers />, document.getElementById('archived-gathers'));
React.render(<App />, document.getElementById("body_content"));
};
var initialiseComponents = () => { var initialiseComponents = () => {
let socketUrl = window.location.protocol + "//" + window.location.host; let socketUrl = window.location.protocol + "//" + window.location.host;
@ -58,12 +39,16 @@ var initialiseComponents = () => {
.on("connect", () => { .on("connect", () => {
console.log("Connected"); console.log("Connected");
removeAuthWidget(); removeAuthWidget();
renderPage(socket); soundController = new SoundController({
socket: socket
});
React.render(<App socket={socket} soundController={soundController}/>,
document.getElementById("body_content"));
socket.on("reconnect", () => { socket.on("reconnect", () => {
console.log("Reconnected");
socket.emit("message:refresh"); socket.emit("message:refresh");
socket.emit("gather:refresh"); socket.emit("gather:refresh");
socket.emit("users:refresh"); socket.emit("users:refresh");
console.log("Reconnected");
}) })
.on("disconnect", () => { .on("disconnect", () => {
console.log("Disconnected") console.log("Disconnected")

View file

@ -7,33 +7,54 @@ var App = React.createClass({
gatherers: [] gatherers: []
}, },
users: [], users: [],
messages: [] messages: [],
maps: [],
servers: [],
archive: [],
soundController: null
} }
}, },
componentDidMount() { componentDidMount() {
let self = this; let self = this;
let socket = this.props.socket;
socket.on("users:update",
data => self.setProps({user: data.currentUser}));
socket.on('users:update', socket.on('users:update',
data => self.setProps({users: data.users})); data => self.setProps({
users: data.users,
user: data.currentUser
})
);
socket.on("message:append", data => { socket.on("message:append", data => {
self.setProps({ self.setProps({
messages: self.props.messages messages: self.props.messages.concat(data.messages)
.concat(data.chatHistory)
.sort((a, b) => { .sort((a, b) => {
return new Date(a.createdAt) - new Date(b.createdAt); return new Date(a.createdAt) - new Date(b.createdAt);
}) })
}); });
}); });
// Message History Retrieved
socket.on("message:refresh", data => { socket.on("message:refresh", data => {
self.setProps({ self.setProps({
messages: data.chatHistory messages: data.messages
});
});
socket.on("gather:refresh", (data) => {
self.setProps({
gather: data.gather,
maps: data.maps,
servers: data.servers,
previousGather: data.previousGather
});
});
socket.on("gather:archive:refresh", data => {
self.setProps({
archive: data.archive,
maps: data.maps,
servers: data.servers
}); });
}); });
@ -53,7 +74,7 @@ var App = React.createClass({
<CurrentUser user={this.props.user} /> <CurrentUser user={this.props.user} />
</ul> </ul>
<ul className="nav navbar-top-links navbar-right" id="soundcontroller"> <ul className="nav navbar-top-links navbar-right" id="soundcontroller">
{/*<SoundPanel />*/} <SoundPanel soundController={this.props.soundController} />
</ul> </ul>
<ul className="nav navbar-top-links navbar-right"> <ul className="nav navbar-top-links navbar-right">
<li className="dropdown"> <li className="dropdown">
@ -96,10 +117,17 @@ var App = React.createClass({
user={this.props.user} /> user={this.props.user} />
</div> </div>
<div className="col-md-6" id="gathers"> <div className="col-md-6" id="gathers">
{/*<Gather />*/} <Gather
gather={this.props.gather}
user={this.props.user}
maps={this.props.maps}
servers={this.props.servers}
previousGather={this.props.previousGather}/>
</div> </div>
<div className="col-md-6 col-md-offset-6" id="archived-gathers"> <div className="col-md-6 col-md-offset-6" id="archived-gathers">
{/*<ArchivedGathers />*/} <ArchivedGathers archive={this.props.archive}
maps={this.props.maps}
servers={this.props.servers} />
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,98 +1,16 @@
"use strict";
class SoundController {
constructor () {
if (Howl === undefined) {
throw new Error("Howl.js required to created sound controller");
}
this.minPlayInterval = 180000; // 5 minutes
this.isMuted = Howler._muted;
this.volume = Howler._volume;
this.tunes = {
"classic": {
description: "Classic",
url: 'http://www.ensl.org/sounds/gather-1.mp3'
},
"eyeofthegorgie": {
description: "Eye of the Gorgie",
url: 'http://www.ensl.org/files/audio/eyeofthegorgie.mp3'
}
}
this.setupGatherMusic("classic");
}
volume(val) {
if (typeof val === 'number' && Math.abs(val) <= 1) {
this.volume = val;
return Howler.volume(val)
}
}
mute() {
this.isMuted = true;
return Howler.mute();
}
unMute() {
this.isMuted = false;
return Howler.unmute();
}
play(music) {
if (this.gather && this.gather.music) return this.gather.music.play();
}
stop(music) {
if (this.gather && this.gather.music) return this.gather.music.stop();
}
setupGatherMusic (musicName) {
let self = this;
let gatherMusic = this.tunes[musicName];
if (!gatherMusic) return;
if (self.gather && self.gather.name === musicName) return;
// Stop if already playing
if (self.gather && self.gather.music) {
self.gather.music.stop();
}
let tune = self.tunes[musicName];
self.gather = {
name: musicName,
description: tune.description,
url: tune.url,
music: new Howl({
urls: [tune.url]
}),
playable: true
};
}
playGatherMusic () {
var self = this;
if (!self.gather.playable) return;
self.gather.music.play();
self.gather.playable = false;
setTimeout(function () {
self.gather.playable = true;
}, self.minPlayInterval);
}
}
var SoundPanel = React.createClass({ var SoundPanel = React.createClass({
mute() { mute() {
soundController.mute(); this.props.soundController.mute();
this.forceUpdate(); this.forceUpdate();
}, },
unMute() { unMute() {
soundController.unMute(); this.props.soundController.unMute();
this.forceUpdate(); this.forceUpdate();
}, },
render() { render() {
let soundController = this.props.soundController;
if (soundController.isMuted) { if (soundController.isMuted) {
return ( return (
<li> <li>
@ -111,4 +29,4 @@ var SoundPanel = React.createClass({
); );
} }
} }
}) });

View file

@ -5,9 +5,6 @@ var UserLogin = React.createClass({
socket.emit("users:authorize", { socket.emit("users:authorize", {
id: parseInt(id, 10) id: parseInt(id, 10)
}); });
setTimeout(function () {
socket.emit("gather:refresh");
}, 1000);
}, },
handleSubmit(e) { handleSubmit(e) {
@ -250,5 +247,3 @@ var AssumeUserIdButton = React.createClass({
} }
} }
}); });
$(function () { initialiseComponents(); });

View file

@ -1,7 +1,5 @@
"use strict"; "use strict";
// Helper Methods
var rankVotes = function (votes, candidates) { var rankVotes = function (votes, candidates) {
var initial = candidates.reduce(function (acc, candidate) { var initial = candidates.reduce(function (acc, candidate) {
acc[candidate.id] = 0; acc[candidate.id] = 0;
@ -37,3 +35,90 @@ var rankVotes = function (votes, candidates) {
}); });
}); });
}; };
class SoundController {
constructor (options) {
if (Howl === undefined) {
throw new Error("Howl.js required to created sound controller");
}
this.MINIMUM_PLAY_INTERVAL = 120000;
this.playGatherMusic = _.throttle(() => {
this.gather.music.play();
}, this.MINIMUM_PLAY_INTERVAL);
if (options && options.socket) {
socket.on("notification", data => {
if (data && data.sound === "gather_starting") {
this.playGatherMusic();
}
});
}
this.isMuted = Howler._muted;
this.volume = Howler._volume;
this.tunes = {
"classic": {
description: "Classic",
url: 'http://www.ensl.org/sounds/gather-1.mp3'
},
"eyeofthegorgie": {
description: "Eye of the Gorgie",
url: 'http://www.ensl.org/files/audio/eyeofthegorgie.mp3'
}
}
this.setupGatherMusic("classic");
}
volume(val) {
if (typeof val === 'number' && Math.abs(val) <= 1) {
this.volume = val;
return Howler.volume(val)
}
}
mute() {
this.isMuted = true;
return Howler.mute();
}
unMute() {
this.isMuted = false;
return Howler.unmute();
}
play(music) {
if (this.gather && this.gather.music) return this.gather.music.play();
}
stop(music) {
if (this.gather && this.gather.music) return this.gather.music.stop();
}
setupGatherMusic (musicName) {
let self = this;
let gatherMusic = this.tunes[musicName];
if (!gatherMusic) return;
if (self.gather && self.gather.name === musicName) return;
// Stop if already playing
if (self.gather && self.gather.music) {
self.gather.music.stop();
}
let tune = self.tunes[musicName];
self.gather = {
name: musicName,
description: tune.description,
url: tune.url,
music: new Howl({
urls: [tune.url]
})
};
}
}

View file

@ -1 +1,5 @@
<script src="/js/app.js"></script> <script>
$(function () {
initialiseComponents();
})
</script>

View file

@ -23,4 +23,5 @@
<script src="/js/autolinker.min.js"></script> <script src="/js/autolinker.min.js"></script>
<script src="/js/emoji.min.js"></script> <script src="/js/emoji.min.js"></script>
<script src="/js/helper.js"></script> <script src="/js/helper.js"></script>
<script src="/js/app.js"></script>
</head> </head>