diff --git a/.eslintrc.json b/.eslintrc.json index 9efcbc9af5..02e4d31777 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -171,6 +171,7 @@ "unread_ops": false, "upload": false, "user_events": false, + "voting_widget": false, "widgetize": false, "submessage": false, "Plotly": false, diff --git a/static/js/voting_widget.js b/static/js/voting_widget.js new file mode 100644 index 0000000000..55cd0bf48e --- /dev/null +++ b/static/js/voting_widget.js @@ -0,0 +1,168 @@ +var voting_widget = (function () { + +var exports = {}; + +var poll_data_holder = function () { + // This object just holds data for a poll, although it + // works closely with the widget's concept of how data + // should be represented for rendering, plus how the + // server sends us data. + var self = {}; + + var me = people.my_current_user_id(); + var key_to_comment = {}; + var my_idx = 1; + + self.get_widget_data = function () { + var comments = []; + + _.each(key_to_comment, function (obj, key) { + var voters = _.keys(obj.votes); + + comments.push({ + comment: obj.comment, + names: people.safe_full_names(voters), + count: voters.length, + key: key, + }); + }); + + + var widget_data = { + comments: comments, + }; + + return widget_data; + }; + + self.handle = { + new_comment: { + outbound: function (comment) { + var event = { + type: 'new_comment', + idx: my_idx, + comment: comment, + }; + + my_idx += 1; + + return event; + }, + + inbound: function (sender_id, data) { + var idx = data.idx; + var key = sender_id + ',' + idx; + var comment = data.comment; + var votes = {}; + + votes[sender_id] = 1; + + key_to_comment[key] = { + comment: comment, + user_id: sender_id, + votes: votes, + }; + + if (my_idx <= idx) { + my_idx = idx + 1; + } + }, + }, + + vote: { + outbound: function (key) { + var vote = 1; + + // toggle + if (key_to_comment[key].votes[me]) { + vote = -1; + } + + var event = { + type: 'vote', + key: key, + vote: vote, + }; + + return event; + }, + + inbound: function (sender_id, data) { + var key = data.key; + var vote = data.vote; + + var votes = key_to_comment[key].votes; + + if (vote === 1) { + votes[sender_id] = 1; + } else { + delete votes[sender_id]; + } + }, + }, + }; + + self.handle_event = function (sender_id, data) { + var type = data.type; + if (self.handle[type]) { + self.handle[type].inbound(sender_id, data); + } + }; + + return self; +}; + +exports.activate = function (opts) { + var self = {}; + + var elem = opts.elem; + var callback = opts.callback; + + var poll_data = poll_data_holder(); + + function render() { + var html = templates.render('poll-widget'); + elem.html(html); + + elem.find("button.poll-comment").on('click', function (e) { + e.stopPropagation(); + var comment = elem.find("input.poll-comment").val(); + + var data = poll_data.handle.new_comment.outbound(comment); + callback(data); + }); + } + + function render_results() { + var widget_data = poll_data.get_widget_data(); + var html = templates.render('poll-widget-results', widget_data); + elem.find('ul.poll-widget').html(html); + + elem.find("button.poll-vote").on('click', function (e) { + e.stopPropagation(); + var key = $(e.target).attr('data-key'); + + var data = poll_data.handle.vote.outbound(key); + callback(data); + }); + } + + self.handle_events = function (events) { + _.each(events, function (event) { + poll_data.handle_event(event.sender_id, event.data); + }); + render_results(); + }; + + render(); + render_results(); + + return self; +}; + +return exports; + +}()); +if (typeof module !== 'undefined') { + module.exports = voting_widget; +} diff --git a/static/js/widgetize.js b/static/js/widgetize.js index 2e78417984..11bc3c4b0d 100644 --- a/static/js/widgetize.js +++ b/static/js/widgetize.js @@ -4,6 +4,8 @@ var exports = {}; var widgets = {}; +widgets.poll = voting_widget; + exports.activate = function (in_opts) { var widget_type = in_opts.widget_type; var extra_data = in_opts.extra_data; diff --git a/static/templates/widgets/poll-widget-results.handlebars b/static/templates/widgets/poll-widget-results.handlebars new file mode 100644 index 0000000000..5b9921b1b5 --- /dev/null +++ b/static/templates/widgets/poll-widget-results.handlebars @@ -0,0 +1,11 @@ +{{#each comments}} +