2015-07-22 00:00:05 +00:00
$ ( function ( ) {
"use strict" ;
2015-07-22 15:49:20 +00:00
var UserCounter = React . createClass ( { displayName : "UserCounter" ,
2015-07-21 14:10:24 +00:00
render : function ( ) {
return (
React . createElement ( "li" , null ,
React . createElement ( "a" , { href : "#" } ,
2015-07-22 15:49:20 +00:00
React . createElement ( "i" , { className : "fa fa-users fa-fw" } ) , " Online" ,
2015-07-21 14:10:24 +00:00
React . createElement ( "span" , { className : "badge add-left" } , " " , this . props . count , " " )
)
)
) ;
}
2015-07-21 00:24:14 +00:00
} ) ;
2015-07-22 00:00:05 +00:00
var UserLogin = React . createClass ( { displayName : "UserLogin" ,
2015-07-22 15:35:40 +00:00
authorizeId : function ( id ) {
id = parseInt ( id , 10 ) ;
2015-07-22 16:38:58 +00:00
socket . emit ( "users:authorize" , {
2015-07-22 15:35:40 +00:00
id : id
} ) ;
} ,
handleSubmit : function ( e ) {
e . preventDefault ( ) ;
var id = React . findDOMNode ( this . refs . authorize _id ) . value . trim ( ) ;
if ( ! id ) return ;
React . findDOMNode ( this . refs . authorize _id ) . value = '' ;
this . authorizeId ( id ) ;
return ;
2015-07-22 00:00:05 +00:00
} ,
render : function ( ) {
return (
React . createElement ( "form" , { onSubmit : this . handleSubmit } ,
2015-07-22 15:57:15 +00:00
React . createElement ( "div" , { className : "input-group signin" } ,
2015-07-22 00:00:05 +00:00
React . createElement ( "input" , {
id : "btn-input" ,
type : "text" ,
className : "form-control" ,
2015-07-22 15:35:40 +00:00
ref : "authorize_id" ,
2015-07-22 00:00:05 +00:00
placeholder : "Choose an ID..." } ) ,
React . createElement ( "span" , { className : "input-group-btn" } ,
React . createElement ( "input" , {
type : "submit" ,
className : "btn btn-primary" ,
id : "btn-chat" ,
value : "Login" } )
)
2015-07-22 15:57:15 +00:00
) ,
React . createElement ( "div" , { className : "signin" } ,
React . createElement ( "p" , { className : "text-center" } , React . createElement ( "small" , null , "Just a temporary measure until genuine authentication is implemented" ) )
2015-07-22 00:00:05 +00:00
)
)
) ;
}
} )
2015-07-22 15:49:20 +00:00
var UserMenu = React . createClass ( { displayName : "UserMenu" ,
2015-07-24 15:01:56 +00:00
getDefaultProps : function ( ) {
return {
count : 0 ,
users : [ ]
} ;
} ,
2015-07-21 14:10:24 +00:00
componentDidMount : function ( ) {
2015-07-22 15:49:20 +00:00
socket . on ( 'userCount' , this . updateUsers ) ;
2015-07-21 14:10:24 +00:00
} ,
2015-07-22 15:49:20 +00:00
updateUsers : function ( data ) {
2015-07-21 14:10:24 +00:00
this . setProps ( {
count : data . count ,
2015-07-22 15:49:20 +00:00
users : data . users
2015-07-21 14:10:24 +00:00
} ) ;
} ,
render : function ( ) {
2015-07-22 15:49:20 +00:00
var users = this . props . users . map ( function ( user ) {
2015-07-21 14:10:24 +00:00
return (
2015-07-26 11:54:35 +00:00
React . createElement ( "li" , { key : user . id } , React . createElement ( "a" , { href : "#" } , user . username ) )
2015-07-21 14:10:24 +00:00
) ;
} ) ;
return (
React . createElement ( "ul" , { className : "nav" , id : "side-menu" } ,
2015-07-22 15:49:20 +00:00
React . createElement ( UserCounter , React . _ _spread ( { } , this . props ) ) ,
2015-07-22 15:57:15 +00:00
users ,
React . createElement ( "li" , null , React . createElement ( "br" , null ) , React . createElement ( UserLogin , null ) , React . createElement ( "br" , null ) )
2015-07-21 14:10:24 +00:00
)
) ;
}
2015-07-20 22:47:18 +00:00
} ) ;
2015-07-21 14:10:24 +00:00
var Chatroom = React . createClass ( { displayName : "Chatroom" ,
2015-07-24 15:01:56 +00:00
getDefaultProps : function ( ) {
return {
history : [ ]
} ;
} ,
2015-07-21 14:10:24 +00:00
componentDidMount : function ( ) {
var self = this ;
var TIMER _INTERVAL = 60000 ; // Every minute
2015-07-21 00:24:14 +00:00
2015-07-21 14:10:24 +00:00
socket . on ( "message:new" , function ( data ) {
var history = self . props . history ;
history . push ( data ) ;
self . setProps ( {
history : history
} ) ;
self . scrollToBottom ( ) ;
} ) ;
2015-07-21 00:24:14 +00:00
2015-07-21 14:10:24 +00:00
// Message History Retrieved
socket . on ( "message:refresh" , function ( data ) {
self . setProps ( {
history : data . chatHistory
} ) ;
self . scrollToBottom ( ) ;
} ) ;
socket . emit ( "message:refresh" , { } ) ;
self . timer = setInterval ( function ( ) {
2015-07-26 11:54:35 +00:00
if ( self . refs . messages ) self . refs . messages . refreshTime ( ) ;
2015-07-21 14:10:24 +00:00
} , TIMER _INTERVAL ) ;
} ,
componentDidUnmount : function ( ) {
clearInterval ( this . timer ) ;
} ,
sendMessage : function ( message ) {
socket . emit ( "newMessage" , { message : message } ) ;
} ,
scrollToBottom : function ( ) {
var node = React . findDOMNode ( this . refs . messageContainer ) ;
node . scrollTop = node . scrollHeight ;
} ,
render : function ( ) {
var messages = this . props . history . map ( function ( message ) {
return (
React . createElement ( ChatMessage , {
avatar : message . author . avatar ,
username : message . author . username ,
content : message . content ,
ref : "messages" ,
createdAt : message . createdAt } )
) ;
} ) ;
return (
React . createElement ( "div" , { className : "panel panel-default" } ,
React . createElement ( "div" , { className : "panel-heading" } , "Gather Chat" ) ,
React . createElement ( "div" , { className : "panel-body" } ,
React . createElement ( "ul" , { className : "chat" , id : "chatmessages" , ref : "messageContainer" } ,
messages
)
) ,
React . createElement ( "div" , { className : "panel-footer" } ,
React . createElement ( MessageBar , null )
)
)
) ;
}
} ) ;
var ChatMessage = React . createClass ( { displayName : "ChatMessage" ,
getInitialState : function ( ) {
return {
timeAgo : $ . timeago ( this . props . createdAt )
}
} ,
refreshTime : function ( ) {
var self = this ;
self . setState ( {
timeAgo : $ . timeago ( self . props . createdAt )
} ) ;
} ,
render : function ( ) {
return (
React . createElement ( "li" , { className : "left clearfix" } ,
React . createElement ( "span" , { className : "chat-img pull-left" } ,
React . createElement ( "img" , {
2015-07-22 23:30:14 +00:00
src : this . props . avatar ,
2015-07-21 14:10:24 +00:00
alt : "User Avatar" ,
height : "40" ,
2015-07-22 15:20:28 +00:00
width : "40" ,
2015-07-21 14:10:24 +00:00
className : "img-circle" } )
) ,
React . createElement ( "div" , { className : "chat-body clearfix" } ,
React . createElement ( "div" , { className : "header" } ,
React . createElement ( "strong" , { className : "primary-font" } , this . props . username ) ,
React . createElement ( "small" , { className : "pull-right text-muted" } ,
React . createElement ( "i" , { className : "fa fa-clock-o fa-fw" } ) , " " , this . state . timeAgo
)
) ,
React . createElement ( "p" , null , this . props . content )
)
)
) ;
}
} ) ;
2015-07-27 00:09:02 +00:00
var CurrentUser = React . createClass ( { displayName : "CurrentUser" ,
getDefaultProps : function ( ) {
return {
username : "" ,
avatar : ""
}
} ,
componentDidMount : function ( ) {
} ,
render : function ( ) {
return (
React . createElement ( "a" , { href : "#" } , this . props . user . username , " Â " , React . createElement ( "img" , { src : this . props . user . avatar ,
alt : "User Avatar" ,
height : "20" ,
width : "20" } ) )
) ;
}
} ) ;
2015-07-21 14:10:24 +00:00
var MessageBar = React . createClass ( { displayName : "MessageBar" ,
sendMessage : function ( content ) {
socket . emit ( "message:new" , {
content : content
} ) ;
} ,
handleSubmit : function ( e ) {
e . preventDefault ( ) ;
var content = React . findDOMNode ( this . refs . content ) . value . trim ( ) ;
if ( ! content ) return ;
React . findDOMNode ( this . refs . content ) . value = '' ;
this . sendMessage ( content ) ;
return ;
} ,
render : function ( ) {
return (
React . createElement ( "form" , { onSubmit : this . handleSubmit } ,
React . createElement ( "div" , { className : "input-group" } ,
React . createElement ( "input" , {
id : "btn-input" ,
type : "text" ,
className : "form-control" ,
ref : "content" ,
placeholder : "Be polite please..." } ) ,
React . createElement ( "span" , { className : "input-group-btn" } ,
React . createElement ( "input" , {
type : "submit" ,
className : "btn btn-primary" ,
id : "btn-chat" ,
value : "Send" } )
)
)
)
) ;
}
} ) ;
2015-07-26 11:54:35 +00:00
var JoinGatherButton = React . createClass ( { displayName : "JoinGatherButton" ,
joinGather : function ( e ) {
e . preventDefault ( ) ;
socket . emit ( "gather:join" , { } ) ;
} ,
render : function ( ) {
var message = this . props . buttonName || "Join Gather" ;
var buttonClass = "btn btn-primary" ;
if ( this . props . buttonClass ) {
buttonClass += " " + this . props . buttonClass ;
}
return ( React . createElement ( "button" , {
onClick : this . joinGather ,
className : buttonClass } , message ) )
}
} ) ;
var GatherProgress = React . createClass ( { displayName : "GatherProgress" ,
gatheringProgress : function ( ) {
var num = this . props . gather . gatherers . length ;
var den = 12 ;
return {
num : num ,
den : den ,
message : num + " / " + den
} ;
} ,
electionProgress : function ( ) {
var num = this . props . gather . gatherers . reduce ( function ( acc , gatherer ) {
if ( gatherer . leaderVote ) acc ++ ;
return acc ;
} , 0 ) ;
var den = 12 ;
return {
num : num ,
den : den ,
message : den - num + " more votes required"
} ;
} ,
selectionProgress : function ( ) {
var num = this . props . gather . gatherers . reduce ( function ( acc , gatherer ) {
if ( gatherer . team !== "lobby" ) acc ++ ;
return acc ;
} , 0 ) ;
var den = 12 ;
return {
num : num ,
den : den ,
message : num + " out of " + den + " players assigned"
} ;
} ,
render : function ( ) {
var progress ;
var gatherState = this . props . gather . state ;
if ( gatherState === 'gathering' && this . props . gather . gatherers . length ) {
progress = this . gatheringProgress ( ) ;
} else if ( gatherState === 'election' ) {
progress = this . electionProgress ( ) ;
} else if ( gatherState === 'selection' ) {
progress = this . selectionProgress ( ) ;
}
if ( progress ) {
var style = {
width : Math . round ( ( progress . num / progress . den * 100 ) ) + "%"
} ;
return (
React . createElement ( "div" , { className : "panel-body" } ,
React . createElement ( "p" , null , "Gather Progress" ) ,
React . createElement ( "div" , { className : "progress" } ,
React . createElement ( "div" , { className : "progress-bar progress-bar-striped active" ,
"data-role" : "progressbar" ,
"data-aria-valuenow" : progress . num ,
"data-aria-valuemin" : "0" ,
"data-aria-valuemax" : progress . den ,
style : style } ,
progress . message
)
)
)
) ;
} else {
return false ;
}
}
} ) ;
2015-07-22 22:34:57 +00:00
var Gather = React . createClass ( { displayName : "Gather" ,
2015-07-24 15:01:56 +00:00
getDefaultProps : function ( ) {
return {
gather : {
gatherers : [ ]
}
}
} ,
2015-07-24 17:05:12 +00:00
joinedGather : function ( ) {
var self = this ;
return this . props . gather . gatherers . some ( function ( gatherer ) {
return gatherer . user . id === self . props . user . id ;
} ) ;
} ,
2015-07-24 15:01:56 +00:00
componentDidMount : function ( ) {
var self = this ;
socket . on ( "gather:refresh" , function ( data ) {
self . setProps ( {
2015-07-24 17:05:12 +00:00
gather : data . gather ,
user : data . user
2015-07-24 15:01:56 +00:00
} ) ;
} ) ;
} ,
2015-07-26 11:54:35 +00:00
stateDescription : function ( ) {
switch ( this . props . gather . state ) {
case "gathering" :
return "Waiting for more gatherers" ;
case "election" :
return "Currently voting for team leaders" ;
case "selection" :
return "Waiting for leaders to picking teams" ;
case "done" :
return "Gather completed" ;
default :
return "Initialising gather" ;
}
2015-07-22 22:34:57 +00:00
} ,
2015-07-24 17:05:12 +00:00
leaveGather : function ( e ) {
e . preventDefault ( ) ;
socket . emit ( "gather:leave" , { } ) ;
} ,
2015-07-26 11:54:35 +00:00
inviteToGather : function ( e ) {
e . preventDefault ( ) ;
} ,
2015-07-22 22:34:57 +00:00
render : function ( ) {
2015-07-24 17:05:12 +00:00
var joinButton ;
if ( this . joinedGather ( ) ) {
2015-07-26 11:54:35 +00:00
joinButton = ( React . createElement ( "li" , null , React . createElement ( "button" , {
2015-07-24 17:05:12 +00:00
onClick : this . leaveGather ,
2015-07-26 11:54:35 +00:00
className : "btn btn-danger" } , "Leave Gather" ) ) ) ;
2015-07-24 17:05:12 +00:00
} else {
2015-07-26 11:54:35 +00:00
joinButton = ( React . createElement ( "li" , null , React . createElement ( JoinGatherButton , null ) ) ) ;
}
var inviteButton ;
if ( this . props . gather . state === 'gathering' ) {
inviteButton = ( React . createElement ( "li" , null , React . createElement ( "button" , {
onClick : this . inviteToGather ,
className : "btn btn-primary" } , "Invite to Gather" ) ) ) ;
2015-07-24 17:05:12 +00:00
}
2015-07-22 22:34:57 +00:00
return (
React . createElement ( "div" , { className : "panel panel-default" } ,
React . createElement ( "div" , { className : "panel-heading" } ,
2015-07-26 11:54:35 +00:00
React . createElement ( "strong" , null , "NS2 Gather " ) ,
React . createElement ( "span" , { className : "badge add-left" } , this . props . gather . gatherers . length ) ,
React . createElement ( "br" , null ) ,
this . stateDescription ( )
2015-07-24 15:01:56 +00:00
) ,
2015-07-24 17:05:12 +00:00
React . createElement ( Gatherers , { gatherers : this . props . gather . gatherers } ) ,
2015-07-26 11:54:35 +00:00
React . createElement ( GatherProgress , { gather : this . props . gather } ) ,
2015-07-24 17:05:12 +00:00
React . createElement ( "div" , { className : "panel-footer text-right" } ,
2015-07-26 11:54:35 +00:00
React . createElement ( "ul" , { className : "list-inline" } ,
inviteButton ,
joinButton
)
2015-07-22 22:34:57 +00:00
)
)
) ;
}
} ) ;
2015-07-26 11:54:35 +00:00
var LeaderPoll = React . createClass ( { displayName : "LeaderPoll" ,
render : function ( ) {
return (
React . createElement ( "div" , { className : "panel-body" }
)
) ;
}
} ) ;
2015-07-24 17:05:12 +00:00
var Gatherers = React . createClass ( { displayName : "Gatherers" ,
2015-07-24 15:01:56 +00:00
render : function ( ) {
2015-07-24 17:05:12 +00:00
var gatherers = this . props . gatherers . map ( function ( gatherer ) {
2015-07-25 12:00:56 +00:00
var lifeforms = (
gatherer . user . ability . lifeforms . map ( function ( lifeform ) {
2015-07-26 11:54:35 +00:00
return ( React . createElement ( "span" , { className : "label label-default" } , lifeform ) ) ;
2015-07-25 12:00:56 +00:00
} )
) ;
2015-07-26 11:54:35 +00:00
var division = ( React . createElement ( "span" , { className : "label label-primary" } , gatherer . user . ability . division ) ) ;
var commBadge ;
if ( gatherer . user . ability . commander ) {
commBadge = ( React . createElement ( "img" , { src : "/images/commander.png" ,
alt : "Commander" ,
height : "20" ,
2015-07-27 00:09:02 +00:00
width : "20" } ) ) ;
2015-07-26 11:54:35 +00:00
}
2015-07-25 12:00:56 +00:00
2015-07-24 17:05:12 +00:00
return (
2015-07-26 11:54:35 +00:00
React . createElement ( "tr" , { key : gatherer . user . id } ,
React . createElement ( "td" , { className : "col-md-1" } , commBadge ) ,
React . createElement ( "td" , { className : "col-md-5" } , gatherer . user . username ) ,
React . createElement ( "td" , { className : "col-md-3" } , division , "Â " ) ,
React . createElement ( "td" , { className : "col-md-3" } , lifeforms , "Â " )
2015-07-24 17:05:12 +00:00
)
) ;
} )
2015-07-26 11:54:35 +00:00
if ( this . props . gatherers . length ) {
return (
React . createElement ( "div" , { className : "panel-body" } ,
React . createElement ( "div" , { className : "panel panel-default" } ,
React . createElement ( "div" , { className : "panel-heading" } ,
React . createElement ( "h5" , { className : "panel-title" } , "Roster" )
) ,
React . createElement ( "table" , { className : "table roster-table" } ,
React . createElement ( "tbody" , null ,
gatherers
)
)
2015-07-24 17:05:12 +00:00
)
)
2015-07-26 11:54:35 +00:00
) ;
} else {
return ( React . createElement ( "div" , { className : "panel-body text-center" } , React . createElement ( JoinGatherButton , { buttonClass : "btn-lg" , buttonName : "Start a Gather" } ) ) ) ;
}
2015-07-24 15:01:56 +00:00
}
} ) ;
2015-07-22 00:00:05 +00:00
var socket ;
function initialiseComponents ( ) {
2015-07-22 14:13:08 +00:00
var socketUrl = window . location . protocol + "//" + window . location . host ;
socket = io ( socketUrl )
2015-07-22 00:00:05 +00:00
. on ( "connect" , function ( ) {
console . log ( "Connected" ) ;
} )
. on ( "reconnect" , function ( ) {
console . log ( "Reconnected" ) ;
} )
. on ( "disconnect" , function ( ) {
console . log ( "Disconnected" )
} ) ;
2015-07-24 15:01:56 +00:00
React . render ( React . createElement ( UserMenu , null ) , document . getElementById ( 'side-menu' ) ) ;
React . render ( React . createElement ( Chatroom , null ) , document . getElementById ( 'chatroom' ) ) ;
React . render ( React . createElement ( Gather , null ) , document . getElementById ( 'gathers' ) ) ;
2015-07-27 00:09:02 +00:00
React . render ( React . createElement ( CurrentUser , null ) , document . getElementById ( 'currentuser' ) ) ;
2015-07-22 00:00:05 +00:00
} ;
initialiseComponents ( ) ;
} ) ;
2015-07-22 14:13:08 +00:00
2015-07-27 00:09:02 +00:00
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNmb3JtZWQuanMiLCJzb3VyY2VzIjpbbnVsbF0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLENBQUMsQ0FBQyxZQUFZOztBQUVkLFlBQVksQ0FBQzs7QUFFYixJQUFJLGlDQUFpQywyQkFBQTtDQUNwQyxNQUFNLEVBQUUsWUFBWTtFQUNuQjtHQUNDLG9CQUFBLElBQUcsRUFBQSxJQUFDLEVBQUE7SUFDSCxvQkFBQSxHQUFFLEVBQUEsQ0FBQSxDQUFDLElBQUEsRUFBSSxDQUFDLEdBQUksQ0FBQSxFQUFBO0tBQ1gsb0JBQUEsR0FBRSxFQUFBLENBQUEsQ0FBQyxTQUFBLEVBQVMsQ0FBQyxtQkFBb0IsQ0FBSSxDQUFBLEVBQUEsU0FBQSxFQUFBLENBQUE7QUFBQSxLQUNyQyxvQkFBQSxNQUFLLEVBQUEsQ0FBQSxDQUFDLFNBQUEsRUFBUyxDQUFDLGdCQUFpQixDQUFBLEVBQUEsR0FBQSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFDLEdBQVEsQ0FBQTtJQUN6RCxDQUFBO0dBQ0EsQ0FBQTtJQUNKO0VBQ0Y7QUFDRixDQUFDLENBQUMsQ0FBQzs7QUFFSCxJQUFJLCtCQUErQix5QkFBQTtDQUNsQyxXQUFXLEVBQUUsVUFBVSxFQUFFLEVBQUU7RUFDMUIsRUFBRSxHQUFHLFFBQVEsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7RUFDdEIsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRTtHQUM5QixFQUFFLEVBQUUsRUFBRTtHQUNOLENBQUMsQ0FBQztFQUNIO0NBQ0QsWUFBWSxFQUFFLFVBQVUsQ0FBQyxFQUFFO0VBQzFCLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztFQUNuQixJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO0VBQ2hFLElBQUksQ0FBQyxFQUFFLEVBQUUsT0FBTztFQUNoQixLQUFLLENB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