diff --git a/channel.js b/channel.js index 94ba72b5..cf834d86 100644 --- a/channel.js +++ b/channel.js @@ -26,6 +26,7 @@ var Channel = function(name) { this.leader = null; this.recentChat = []; this.qlocked = true; + this.poll = false; this.loadMysql(); }; @@ -215,6 +216,9 @@ Channel.prototype.userJoin = function(user) { user.socket.emit('queueLock', {locked: this.qlocked}); this.sendUserlist(user); this.sendRecentChat(user); + if(this.poll) { + user.socket.emit('newPoll', this.poll.packUpdate()); + } if(user.playerReady) this.sendMediaUpdate(user); console.log(user.ip + " joined channel " + this.name); @@ -222,6 +226,13 @@ Channel.prototype.userJoin = function(user) { // Called when a user leaves the channel 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.updateUsercount(); 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! Channel.prototype.sendAll = function(message, data) { for(var i = 0; i < this.users.length; i++) { diff --git a/chatcommand.js b/chatcommand.js index 9b1d3683..50d96dea 100644 --- a/chatcommand.js +++ b/chatcommand.js @@ -1,4 +1,5 @@ var Rank = require('./rank.js'); +var Poll = require('./poll.js').Poll; function handle(chan, user, msg) { if(msg.indexOf("/me ") == 0) @@ -8,6 +9,9 @@ function handle(chan, user, msg) { else if(msg.indexOf("/kick ") == 0) { handleKick(chan, user, msg.substring(6).split(' ')); } + else if(msg.indexOf("/poll ") == 0) { + handlePoll(chan, user, msg.substring(6)); + } } 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; diff --git a/poll.js b/poll.js new file mode 100644 index 00000000..ded3e7ce --- /dev/null +++ b/poll.js @@ -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; diff --git a/rank.js b/rank.js index 82583df2..6f4ace93 100644 --- a/rank.js +++ b/rank.js @@ -19,6 +19,7 @@ var permissions = { kick: exports.Moderator, promote: exports.Moderator, qlock: exports.Moderator, + poll: exports.Moderator, search: exports.Guest, chat: exports.Guest, }; diff --git a/user.js b/user.js index 8b83c3ab..d42c450b 100644 --- a/user.js +++ b/user.js @@ -149,6 +149,22 @@ User.prototype.initCallbacks = function() { } }.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) { if(Rank.hasPermission(this, "acp")) { this.handleAdm(data); diff --git a/www/assets/css/ytsync.css b/www/assets/css/ytsync.css index c8c9731b..9846e2b8 100644 --- a/www/assets/css/ytsync.css +++ b/www/assets/css/ytsync.css @@ -91,3 +91,7 @@ .greentext { color: #789922; /* Color value directly from 4chan */ } + +.option button { + margin-right: 15px; +} diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index 0826d6b4..7518703d 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -19,6 +19,14 @@ function initCallbacks() { if(data.rank >= Rank.Moderator) { $('#playlist_controls').css("display", "block"); $('#qlockbtn').css("display", "block"); + var poll = $('#pollcontainer .active'); + if(poll.length > 0) { + $('').addClass('btn btn-danger pull-right').text('Close Poll') + .insertAfter(poll.find('.close')) + .click(function() { + socket.emit('closePoll') + }); + } } RANK = data.rank; }); @@ -232,4 +240,16 @@ function initCallbacks() { $(li).appendTo(ul); } }); + + socket.on('newPoll', function(data) { + addPoll(data); + }); + + socket.on('updatePoll', function(data) { + updatePoll(data); + }); + + socket.on('closePoll', function() { + closePoll(); + }); } diff --git a/www/assets/js/functions.js b/www/assets/js/functions.js index 0ac9ffb7..1bdddc33 100644 --- a/www/assets/js/functions.js +++ b/www/assets/js/functions.js @@ -420,5 +420,57 @@ function parseVimeo(url) { 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 = $('
').addClass('well active').prependTo($('#pollcontainer')); + $('').addClass('close pull-right').text('×') + .appendTo(poll) + .click(function() { poll.remove(); }); + if(RANK >= Rank.Moderator) { + $('').addClass('btn btn-danger pull-right').text('Close Poll') + .appendTo(poll) + .click(function() { + socket.emit('closePoll') + }); + } + $('').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); + $('').addClass('btn').text(data.counts[i]) + .prependTo($('').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++; + }); +} diff --git a/www/index.html b/www/index.html index 10bf6857..f1646754 100644 --- a/www/index.html +++ b/www/index.html @@ -67,6 +67,10 @@ +