From 58847212c9791e43dbfbe12abece4b3c02050775 Mon Sep 17 00:00:00 2001 From: CylonicRaider Date: Tue, 28 Feb 2017 01:33:40 +0100 Subject: [PATCH 1/6] Commence inline polls --- client/lib/main.less | 20 ++++++++++++++ client/lib/ui/InlineVoting.js | 52 +++++++++++++++++++++++++++++++++++ client/lib/ui/Message.js | 10 +++++++ 3 files changed, 82 insertions(+) create mode 100644 client/lib/ui/InlineVoting.js diff --git a/client/lib/main.less b/client/lib/main.less index 5b28a5c8..944b90d7 100644 --- a/client/lib/main.less +++ b/client/lib/main.less @@ -1345,6 +1345,26 @@ iframe.js { opacity: 0; margin-left: 0; } + + .inline-voting { + .approve, .disapprove { + margin-left: 0.2em; + padding: 0 0.2em; + border-radius: 2px; + } + + .approve { + background: #e0ffe0; + color: #008000; + .touchable-bg(#e0ffe0); + } + + .disapprove { + background: #ffe0e0; + color: #800000; + .touchable-bg(#ffe0e0); + } + } } .message-tall { diff --git a/client/lib/ui/InlineVoting.js b/client/lib/ui/InlineVoting.js new file mode 100644 index 00000000..5b7f2489 --- /dev/null +++ b/client/lib/ui/InlineVoting.js @@ -0,0 +1,52 @@ +import _ from 'lodash' +import React from 'react' +import twemoji from 'twemoji' + +import actions from '../actions' +import Tree from '../Tree' +import FastButton from './FastButton' +import Message from './Message' +import MessageText from './MessageText' + +export default React.createClass({ + displayName: 'InlineVoting', + + propTypes: { + message: React.PropTypes.instanceOf(Message).isRequired, + tree: React.PropTypes.instanceOf(Tree).isRequired, + className: React.PropTypes.string, + title: React.PropTypes.string, + style: React.PropTypes.string + }, + + upvote(evt) { + actions.sendMessage('+1', this.props.message.state.node.get('id')) + if (evt) evt.stopPropagation(); + }, + + downvote(evt) { + actions.sendMessage('-1', this.props.message.state.node.get('id')) + if (evt) evt.stopPropagation(); + }, + + render() { + let upvotes = 0, downvotes = 0 + + this.props.message.state.node.get('children').map(id => { + const content = this.props.tree.get(id).get('content') + + if (/\s*\+1\s*/.test(content)) upvotes++ + if (/\s*-1\s*/.test(content)) downvotes++ + }) + + return + + {upvotes} + + + {downvotes} + + + } + +}) diff --git a/client/lib/ui/Message.js b/client/lib/ui/Message.js index 463390cf..4f1dc2ec 100644 --- a/client/lib/ui/Message.js +++ b/client/lib/ui/Message.js @@ -11,6 +11,7 @@ import Tree from '../Tree' import FastButton from './FastButton' import Embed from './Embed' import MessageText from './MessageText' +import InlineVoting from './InlineVoting' import ChatEntry from './ChatEntry' import LiveTimeAgo from './LiveTimeAgo' import KeyboardActionHandler from './KeyboardActionHandler' @@ -436,6 +437,15 @@ const Message = React.createClass({ ) lineClasses['line-emote'] = true + } else if (/^\/vote/.test(content) && content.length < 240) { + content = _.trim(content.replace(/^\/vote ?/, '')) + messageRender = ( +
+ + {messageAgo} + +
+ ) } else if (this.state.contentTall && this.props.roomSettings.get('collapse') !== false) { const action = contentExpanded ? 'collapse' : 'expand' const actionMethod = action + 'Content' From 344ae4c913ee9a91bee008299c2ff8b53f117089 Mon Sep 17 00:00:00 2001 From: CylonicRaider Date: Tue, 28 Feb 2017 11:37:46 +0100 Subject: [PATCH 2/6] Add result display to voting gadget --- client/lib/main.less | 8 ++++++++ client/lib/ui/InlineVoting.js | 3 +++ 2 files changed, 11 insertions(+) diff --git a/client/lib/main.less b/client/lib/main.less index 944b90d7..bc345d68 100644 --- a/client/lib/main.less +++ b/client/lib/main.less @@ -1364,6 +1364,14 @@ iframe.js { color: #800000; .touchable-bg(#ffe0e0); } + + .approved { + color: #008000; + } + + .rejected { + color: #800000; + } } } diff --git a/client/lib/ui/InlineVoting.js b/client/lib/ui/InlineVoting.js index 5b7f2489..265b2291 100644 --- a/client/lib/ui/InlineVoting.js +++ b/client/lib/ui/InlineVoting.js @@ -39,6 +39,8 @@ export default React.createClass({ if (/\s*-1\s*/.test(content)) downvotes++ }) + const result = (upvotes > downvotes) ? "approved" : (upvotes < downvotes) ? "rejected" : "neutral"; + return {upvotes} @@ -46,6 +48,7 @@ export default React.createClass({ {downvotes} + {upvotes - downvotes} } From 0dd8497ddf16bcfb5d5b2044ad025032b14985bf Mon Sep 17 00:00:00 2001 From: CylonicRaider Date: Tue, 28 Feb 2017 11:58:38 +0100 Subject: [PATCH 3/6] Implement majority percentage display --- client/lib/main.less | 5 +++++ client/lib/ui/InlineVoting.js | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/client/lib/main.less b/client/lib/main.less index bc345d68..770ff250 100644 --- a/client/lib/main.less +++ b/client/lib/main.less @@ -1372,6 +1372,11 @@ iframe.js { .rejected { color: #800000; } + + small, small * { + vertical-align: baseline; + color: #808080; + } } } diff --git a/client/lib/ui/InlineVoting.js b/client/lib/ui/InlineVoting.js index 265b2291..8a3a48a5 100644 --- a/client/lib/ui/InlineVoting.js +++ b/client/lib/ui/InlineVoting.js @@ -39,7 +39,11 @@ export default React.createClass({ if (/\s*-1\s*/.test(content)) downvotes++ }) - const result = (upvotes > downvotes) ? "approved" : (upvotes < downvotes) ? "rejected" : "neutral"; + const result = upvotes - downvotes; + const resultClass = (result > 0) ? "approved" : (result < 0) ? "rejected" : "neutral"; + + const majorityPercent = Math.max(upvotes, downvotes) * 100 / (upvotes + downvotes); + const percentText = " (" + Math.round(majorityPercent) + "% " + ((result > 0) ? "+" : "-") + ")"; return @@ -48,7 +52,8 @@ export default React.createClass({ {downvotes} - {upvotes - downvotes} + {result} + {result != 0 && {percentText}} } From 87eefffb5181da8b5204f761675613939b997897 Mon Sep 17 00:00:00 2001 From: CylonicRaider Date: Tue, 28 Feb 2017 12:02:49 +0100 Subject: [PATCH 4/6] Make InlineVoting prop types match --- client/lib/ui/InlineVoting.js | 9 +++++---- client/lib/ui/Message.js | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/lib/ui/InlineVoting.js b/client/lib/ui/InlineVoting.js index 8a3a48a5..ca608f41 100644 --- a/client/lib/ui/InlineVoting.js +++ b/client/lib/ui/InlineVoting.js @@ -1,5 +1,6 @@ import _ from 'lodash' import React from 'react' +import Immutable from 'immutable' import twemoji from 'twemoji' import actions from '../actions' @@ -12,7 +13,7 @@ export default React.createClass({ displayName: 'InlineVoting', propTypes: { - message: React.PropTypes.instanceOf(Message).isRequired, + message: React.PropTypes.instanceOf(Immutable.Map).isRequired, tree: React.PropTypes.instanceOf(Tree).isRequired, className: React.PropTypes.string, title: React.PropTypes.string, @@ -20,19 +21,19 @@ export default React.createClass({ }, upvote(evt) { - actions.sendMessage('+1', this.props.message.state.node.get('id')) + actions.sendMessage('+1', this.props.message.get('id')) if (evt) evt.stopPropagation(); }, downvote(evt) { - actions.sendMessage('-1', this.props.message.state.node.get('id')) + actions.sendMessage('-1', this.props.message.get('id')) if (evt) evt.stopPropagation(); }, render() { let upvotes = 0, downvotes = 0 - this.props.message.state.node.get('children').map(id => { + this.props.message.get('children').map(id => { const content = this.props.tree.get(id).get('content') if (/\s*\+1\s*/.test(content)) upvotes++ diff --git a/client/lib/ui/Message.js b/client/lib/ui/Message.js index 4f1dc2ec..5ba89639 100644 --- a/client/lib/ui/Message.js +++ b/client/lib/ui/Message.js @@ -443,7 +443,7 @@ const Message = React.createClass({
{messageAgo} - +
) } else if (this.state.contentTall && this.props.roomSettings.get('collapse') !== false) { From 465f4bb43677818335b07ec90945736a330b5459 Mon Sep 17 00:00:00 2001 From: CylonicRaider Date: Tue, 28 Feb 2017 12:15:05 +0100 Subject: [PATCH 5/6] Make linter pass --- client/lib/ui/InlineVoting.js | 36 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/client/lib/ui/InlineVoting.js b/client/lib/ui/InlineVoting.js index ca608f41..79c8f212 100644 --- a/client/lib/ui/InlineVoting.js +++ b/client/lib/ui/InlineVoting.js @@ -1,12 +1,9 @@ -import _ from 'lodash' import React from 'react' import Immutable from 'immutable' -import twemoji from 'twemoji' import actions from '../actions' import Tree from '../Tree' import FastButton from './FastButton' -import Message from './Message' import MessageText from './MessageText' export default React.createClass({ @@ -17,21 +14,22 @@ export default React.createClass({ tree: React.PropTypes.instanceOf(Tree).isRequired, className: React.PropTypes.string, title: React.PropTypes.string, - style: React.PropTypes.string + style: React.PropTypes.string, }, upvote(evt) { actions.sendMessage('+1', this.props.message.get('id')) - if (evt) evt.stopPropagation(); + if (evt) evt.stopPropagation() }, downvote(evt) { actions.sendMessage('-1', this.props.message.get('id')) - if (evt) evt.stopPropagation(); + if (evt) evt.stopPropagation() }, render() { - let upvotes = 0, downvotes = 0 + let upvotes = 0 + let downvotes = 0 this.props.message.get('children').map(id => { const content = this.props.tree.get(id).get('content') @@ -40,22 +38,22 @@ export default React.createClass({ if (/\s*-1\s*/.test(content)) downvotes++ }) - const result = upvotes - downvotes; - const resultClass = (result > 0) ? "approved" : (result < 0) ? "rejected" : "neutral"; + const result = upvotes - downvotes + const resultClass = (result > 0) ? 'approved' : (result < 0) ? 'rejected' : 'neutral' // eslint-disable-line - const majorityPercent = Math.max(upvotes, downvotes) * 100 / (upvotes + downvotes); - const percentText = " (" + Math.round(majorityPercent) + "% " + ((result > 0) ? "+" : "-") + ")"; + const majorityPercent = Math.max(upvotes, downvotes) * 100 / (upvotes + downvotes) + const percentText = ' (' + Math.round(majorityPercent) + '% ' + ((result > 0) ? '+' : '-') + ')' - return - - {upvotes} + return ( + + {upvotes} - - {downvotes} + + {downvotes} {result} - {result != 0 && {percentText}} - - } + {result !== 0 && {percentText}} + ) + }, }) From f2c2a4141529c2e41de8364788ae4353f285f279 Mon Sep 17 00:00:00 2001 From: CylonicRaider Date: Tue, 1 Aug 2017 00:06:43 +0200 Subject: [PATCH 6/6] Do not send voting messages without nick set --- client/lib/ui/InlineVoting.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/client/lib/ui/InlineVoting.js b/client/lib/ui/InlineVoting.js index 79c8f212..53e39fff 100644 --- a/client/lib/ui/InlineVoting.js +++ b/client/lib/ui/InlineVoting.js @@ -1,7 +1,9 @@ import React from 'react' +import Reflux from 'reflux' import Immutable from 'immutable' import actions from '../actions' +import chat from '../stores/chat' import Tree from '../Tree' import FastButton from './FastButton' import MessageText from './MessageText' @@ -17,13 +19,23 @@ export default React.createClass({ style: React.PropTypes.string, }, + mixins: [ + Reflux.connect(chat.store, 'chat'), + ], + + sendMessageIfPossible(text) { + if (this.state.chat.joined && this.state.chat.nick) { + actions.sendMessage(text, this.props.message.get('id')) + } + }, + upvote(evt) { - actions.sendMessage('+1', this.props.message.get('id')) + this.sendMessageIfPossible('+1') if (evt) evt.stopPropagation() }, downvote(evt) { - actions.sendMessage('-1', this.props.message.get('id')) + this.sendMessageIfPossible('-1') if (evt) evt.stopPropagation() },