Implement polls

This commit is contained in:
calzoneman 2013-03-16 16:49:58 -05:00
parent 741fe8e21f
commit bc187c99f5
9 changed files with 172 additions and 0 deletions

View File

@ -26,6 +26,7 @@ var Channel = function(name) {
this.leader = null; this.leader = null;
this.recentChat = []; this.recentChat = [];
this.qlocked = true; this.qlocked = true;
this.poll = false;
this.loadMysql(); this.loadMysql();
}; };
@ -215,6 +216,9 @@ Channel.prototype.userJoin = function(user) {
user.socket.emit('queueLock', {locked: this.qlocked}); user.socket.emit('queueLock', {locked: this.qlocked});
this.sendUserlist(user); this.sendUserlist(user);
this.sendRecentChat(user); this.sendRecentChat(user);
if(this.poll) {
user.socket.emit('newPoll', this.poll.packUpdate());
}
if(user.playerReady) if(user.playerReady)
this.sendMediaUpdate(user); this.sendMediaUpdate(user);
console.log(user.ip + " joined channel " + this.name); console.log(user.ip + " joined channel " + this.name);
@ -222,6 +226,13 @@ Channel.prototype.userJoin = function(user) {
// Called when a user leaves the channel // Called when a user leaves the channel
Channel.prototype.userLeave = function(user) { Channel.prototype.userLeave = function(user) {
if(this.poll) {
this.poll.unvote(user.ip);
this.broadcastPollUpdate();
}
if(this.leader == user) {
this.changeLeader("");
}
this.users.splice(this.users.indexOf(user), 1); this.users.splice(this.users.indexOf(user), 1);
this.updateUsercount(); this.updateUsercount();
if(user.name != "") { if(user.name != "") {
@ -564,6 +575,18 @@ Channel.prototype.broadcastRankUpdate = function(user) {
}); });
} }
Channel.prototype.broadcastPoll = function() {
this.sendAll('newPoll', this.poll.packUpdate());
}
Channel.prototype.broadcastPollUpdate = function() {
this.sendAll('updatePoll', this.poll.packUpdate());
}
Channel.prototype.broadcastPollClose = function() {
this.sendAll('closePoll');
}
// Send to ALL the clients! // Send to ALL the clients!
Channel.prototype.sendAll = function(message, data) { Channel.prototype.sendAll = function(message, data) {
for(var i = 0; i < this.users.length; i++) { for(var i = 0; i < this.users.length; i++) {

View File

@ -1,4 +1,5 @@
var Rank = require('./rank.js'); var Rank = require('./rank.js');
var Poll = require('./poll.js').Poll;
function handle(chan, user, msg) { function handle(chan, user, msg) {
if(msg.indexOf("/me ") == 0) if(msg.indexOf("/me ") == 0)
@ -8,6 +9,9 @@ function handle(chan, user, msg) {
else if(msg.indexOf("/kick ") == 0) { else if(msg.indexOf("/kick ") == 0) {
handleKick(chan, user, msg.substring(6).split(' ')); handleKick(chan, user, msg.substring(6).split(' '));
} }
else if(msg.indexOf("/poll ") == 0) {
handlePoll(chan, user, msg.substring(6));
}
} }
function handleKick(chan, user, args) { function handleKick(chan, user, args) {
@ -26,5 +30,16 @@ function handleKick(chan, user, args) {
} }
} }
function handlePoll(chan, user, msg) {
if(Rank.hasPermission(user, "poll")) {
var args = msg.split(',');
var title = args[0];
args.splice(0, 1);
var poll = new Poll(title, args);
chan.poll = poll;
chan.broadcastPoll();
}
}
exports.handle = handle; exports.handle = handle;

37
poll.js Normal file
View File

@ -0,0 +1,37 @@
var Poll = function(title, options) {
this.title = title;
this.options = options;
this.counts = new Array(options.length);
for(var i = 0; i < this.counts.length; i++) {
this.counts[i] = 0;
}
this.votes = {};
}
Poll.prototype.vote = function(ip, option) {
if(!(ip in this.votes) || this.votes[ip] == null) {
this.votes[ip] = option;
this.counts[option]++;
}
console.log(this.votes);
}
Poll.prototype.unvote = function(ip) {
console.log('unvote ' + ip + this.votes[ip]);
if(ip in this.votes && this.votes[ip] != null) {
this.counts[this.votes[ip]]--;
this.votes[ip] = null;
}
console.log(this.votes);
}
Poll.prototype.packUpdate = function() {
return {
title: this.title,
options: this.options,
counts: this.counts
}
}
exports.Poll = Poll;

View File

@ -19,6 +19,7 @@ var permissions = {
kick: exports.Moderator, kick: exports.Moderator,
promote: exports.Moderator, promote: exports.Moderator,
qlock: exports.Moderator, qlock: exports.Moderator,
poll: exports.Moderator,
search: exports.Guest, search: exports.Guest,
chat: exports.Guest, chat: exports.Guest,
}; };

16
user.js
View File

@ -149,6 +149,22 @@ User.prototype.initCallbacks = function() {
} }
}.bind(this)); }.bind(this));
this.socket.on('closePoll', function() {
if(Rank.hasPermission(this, "poll")) {
if(this.channel != null && this.channel.poll) {
this.channel.poll = null;
this.channel.broadcastPollClose();
}
}
}.bind(this));
this.socket.on('vote', function(data) {
if(this.channel != null && this.channel.poll) {
this.channel.poll.vote(this.ip, data.option);
this.channel.broadcastPollUpdate();
}
}.bind(this));
this.socket.on('adm', function(data) { this.socket.on('adm', function(data) {
if(Rank.hasPermission(this, "acp")) { if(Rank.hasPermission(this, "acp")) {
this.handleAdm(data); this.handleAdm(data);

View File

@ -91,3 +91,7 @@
.greentext { .greentext {
color: #789922; /* Color value directly from 4chan */ color: #789922; /* Color value directly from 4chan */
} }
.option button {
margin-right: 15px;
}

View File

@ -19,6 +19,14 @@ function initCallbacks() {
if(data.rank >= Rank.Moderator) { if(data.rank >= Rank.Moderator) {
$('#playlist_controls').css("display", "block"); $('#playlist_controls').css("display", "block");
$('#qlockbtn').css("display", "block"); $('#qlockbtn').css("display", "block");
var poll = $('#pollcontainer .active');
if(poll.length > 0) {
$('<button/>').addClass('btn btn-danger pull-right').text('Close Poll')
.insertAfter(poll.find('.close'))
.click(function() {
socket.emit('closePoll')
});
}
} }
RANK = data.rank; RANK = data.rank;
}); });
@ -232,4 +240,16 @@ function initCallbacks() {
$(li).appendTo(ul); $(li).appendTo(ul);
} }
}); });
socket.on('newPoll', function(data) {
addPoll(data);
});
socket.on('updatePoll', function(data) {
updatePoll(data);
});
socket.on('closePoll', function() {
closePoll();
});
} }

View File

@ -420,5 +420,57 @@ function parseVimeo(url) {
return null; return null;
} }
function closePoll() {
if($('#pollcontainer .active').length != 0) {
var poll = $('#pollcontainer .active');
poll.removeClass("active").addClass("muted");
poll.find('.option button').each(function() {
$(this).attr('disabled', 'disabled');
});
poll.find('.btn-danger').each(function() {
$(this).remove()
});
}
}
function addPoll(data) {
closePoll();
var poll = $('<div/>').addClass('well active').prependTo($('#pollcontainer'));
$('<button/>').addClass('close pull-right').text('×')
.appendTo(poll)
.click(function() { poll.remove(); });
if(RANK >= Rank.Moderator) {
$('<button/>').addClass('btn btn-danger pull-right').text('Close Poll')
.appendTo(poll)
.click(function() {
socket.emit('closePoll')
});
}
$('<h3/>').text(data.title).appendTo(poll);
for(var i = 0; i < data.options.length; i++) {
var callback = (function(i) { return function() {
console.log(i);
socket.emit('vote', {
option: i
});
poll.find('.option button').each(function() {
$(this).attr('disabled', 'disabled');
});
} })(i);
$('<button/>').addClass('btn').text(data.counts[i])
.prependTo($('<div/>').addClass('option').text(data.options[i])
.appendTo(poll))
.click(callback);
}
}
function updatePoll(data) {
var poll = $('#pollcontainer .active');
var i = 0;
poll.find('.option button').each(function() {
$(this).text(data.counts[i]);
i++;
});
}

View File

@ -67,6 +67,10 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row" style="margin-top: 50px;">
<div class="span6" id="pollcontainer">
</div>
</div>
<div class="row" style="margin-top: 50px;"> <div class="row" style="margin-top: 50px;">
<div class="span6"> <div class="span6">
<div id="playlist_controls" style="display: none;"> <div id="playlist_controls" style="display: none;">