nodebb-plugin-poll 3.2.1 → 3.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/languages/en_GB/poll.json +3 -0
- package/languages/en_US/poll.json +3 -0
- package/lib/config.js +1 -0
- package/lib/sockets.js +33 -1
- package/lib/vote.js +16 -3
- package/package.json +1 -1
- package/plugin.json +0 -1
- package/public/js/poll/creator.js +7 -4
- package/public/js/poll/main.js +9 -1
- package/public/js/poll/serializer.js +8 -0
- package/public/js/poll/view.js +71 -36
- package/templates/poll/creator.tpl +8 -5
- package/templates/poll/view/details.tpl +1 -1
- package/templates/poll/view.tpl +6 -5
- package/public/js/poll/sockets.js +0 -61
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Currently supported settings:
|
|
|
11
11
|
|
|
12
12
|
maxvotes="1" //Max number of votes per user. If larger than 1, a multiple choice poll will be created
|
|
13
13
|
disallowVoteUpdate="0" //if set, users won't be able to update/remove their vote
|
|
14
|
+
allowAnonVoting="0" // if set to 1, users will be able to vote anonymously
|
|
14
15
|
title="Poll title" //Poll title
|
|
15
16
|
|
|
16
17
|
There's also a helpful modal available that will allow you to easily create a poll:
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"default_title": "Default poll title",
|
|
9
9
|
"max_votes": "Maximum number of votes per user",
|
|
10
10
|
"disallow_vote_update": "Don't allow users to update their vote",
|
|
11
|
+
"allow_anon_voting": "Allow anonymous voting",
|
|
11
12
|
"info_choices": "A number greater than 1 will enable multiple choice polls.",
|
|
12
13
|
"settings": "Settings",
|
|
13
14
|
"save": "Save",
|
|
@@ -29,10 +30,12 @@
|
|
|
29
30
|
|
|
30
31
|
"error.not_main": "Can only add poll in main post.",
|
|
31
32
|
"error.privilege.create": "You're not allowed to create a poll",
|
|
33
|
+
"error.anon-voting-not-allowed": "This poll does not allow voting anonymously",
|
|
32
34
|
|
|
33
35
|
"warning.redactor": "You're using Redactor. Do <strong>not</strong> edit the markup manually. Instead, re-open the poll creator.",
|
|
34
36
|
|
|
35
37
|
"vote": "Vote",
|
|
38
|
+
"vote_anonymously": "Vote anonymously",
|
|
36
39
|
"update_vote": "Update vote",
|
|
37
40
|
"remove_vote": "Remove vote",
|
|
38
41
|
"to_voting": "To Voting",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"default_title": "Default poll title",
|
|
9
9
|
"max_votes": "Maximum number of votes per user",
|
|
10
10
|
"disallow_vote_update": "Don't allow users to update their vote",
|
|
11
|
+
"allow_anon_voting": "Allow anonymous voting",
|
|
11
12
|
"info_choices": "A number greater than 1 will enable multiple choice polls.",
|
|
12
13
|
"settings": "Settings",
|
|
13
14
|
"save": "Save",
|
|
@@ -29,10 +30,12 @@
|
|
|
29
30
|
|
|
30
31
|
"error.not_main": "Can only add poll in main post.",
|
|
31
32
|
"error.privilege.create": "You're not allowed to create a poll",
|
|
33
|
+
"error.anon-voting-not-allowed": "This poll does not allow voting anonymously",
|
|
32
34
|
|
|
33
35
|
"warning.redactor": "You're using Redactor. Do <strong>not</strong> edit the markup manually. Instead, re-open the poll creator.",
|
|
34
36
|
|
|
35
37
|
"vote": "Vote",
|
|
38
|
+
"vote_anonymously": "Vote anonymously",
|
|
36
39
|
"update_vote": "Update vote",
|
|
37
40
|
"remove_vote": "Remove vote",
|
|
38
41
|
"to_voting": "To Voting",
|
package/lib/config.js
CHANGED
package/lib/sockets.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const _ = require.main.require('lodash');
|
|
3
4
|
const NodeBB = require('./nodebb');
|
|
4
5
|
|
|
5
6
|
const Config = require('./config');
|
|
@@ -31,6 +32,10 @@ Sockets.get = async function (socket, data) {
|
|
|
31
32
|
throw new Error('Legacy polls are not supported');
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
if (parseInt(pollData.settings.allowAnonVoting, 10) === 1) {
|
|
36
|
+
await anonymizeVoters(socket.uid, data.pollId, pollData.options);
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
pollData.optionType = parseInt(pollData.settings.maxvotes, 10) > 1 ? 'checkbox' : 'radio';
|
|
35
40
|
return pollData;
|
|
36
41
|
};
|
|
@@ -59,6 +64,10 @@ Sockets.vote = async function (socket, data) {
|
|
|
59
64
|
throw new Error(`You can only vote for ${settings.maxvotes} options on this poll.`);
|
|
60
65
|
}
|
|
61
66
|
|
|
67
|
+
if (data.voteAnon && parseInt(settings.allowAnonVoting, 10) !== 1) {
|
|
68
|
+
throw new Error('[[poll:error.anon-voting-not-allowed]]');
|
|
69
|
+
}
|
|
70
|
+
|
|
62
71
|
if (!canVote || !data.options.length) {
|
|
63
72
|
throw new Error('Already voted or invalid option');
|
|
64
73
|
}
|
|
@@ -128,14 +137,20 @@ Sockets.getOptionDetails = async function (socket, data) {
|
|
|
128
137
|
if (!socket.uid || !data || isNaN(parseInt(data.pollId, 10)) || isNaN(parseInt(data.optionId, 10))) {
|
|
129
138
|
throw new Error('Invalid request');
|
|
130
139
|
}
|
|
131
|
-
const [poll, option] = await Promise.all([
|
|
140
|
+
const [poll, settings, option] = await Promise.all([
|
|
132
141
|
Poll.getInfo(data.pollId),
|
|
142
|
+
Poll.getSettings(data.pollId),
|
|
133
143
|
Poll.getOption(data.pollId, data.optionId, true),
|
|
134
144
|
]);
|
|
135
145
|
|
|
136
146
|
if (!option.votes || !option.votes.length) {
|
|
137
147
|
return option;
|
|
138
148
|
}
|
|
149
|
+
|
|
150
|
+
if (parseInt(settings.allowAnonVoting, 10) === 1) {
|
|
151
|
+
await anonymizeVoters(socket.uid, data.pollId, [option]);
|
|
152
|
+
}
|
|
153
|
+
|
|
139
154
|
const userData = await NodeBB.User.getUsersFields(option.votes, [
|
|
140
155
|
'uid', 'username', 'userslug', 'picture',
|
|
141
156
|
]);
|
|
@@ -160,6 +175,23 @@ Sockets.canCreate = async function (socket, data) {
|
|
|
160
175
|
return await checkPrivs(data.cid, socket.uid);
|
|
161
176
|
};
|
|
162
177
|
|
|
178
|
+
async function anonymizeVoters(callerUid, pollId, options) {
|
|
179
|
+
const uids = _.uniq(options.map(opt => opt.votes).flat());
|
|
180
|
+
const [isAnon, isPrivileged] = await Promise.all([
|
|
181
|
+
NodeBB.db.isSortedSetMembers(`poll:${pollId}:anon:voters`, uids),
|
|
182
|
+
NodeBB.User.isPrivileged(callerUid),
|
|
183
|
+
]);
|
|
184
|
+
if (isPrivileged) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const uidToIsAnon = _.zipObject(uids, isAnon);
|
|
188
|
+
options.forEach((opt) => {
|
|
189
|
+
opt.votes = opt.votes.map(
|
|
190
|
+
uid => (uidToIsAnon[uid] && String(callerUid) !== uid ? 0 : uid)
|
|
191
|
+
);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
163
195
|
async function checkPrivs(cid, socketUid) {
|
|
164
196
|
const can = await NodeBB.Privileges.categories.can('poll:create', cid, socketUid);
|
|
165
197
|
if (!can) {
|
package/lib/vote.js
CHANGED
|
@@ -9,12 +9,19 @@ Vote.add = async function (voteData) {
|
|
|
9
9
|
const { pollId, options, uid } = voteData;
|
|
10
10
|
const timestamp = +new Date();
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const promises = [
|
|
13
13
|
NodeBB.db.sortedSetAdd(`poll:${pollId}:voters`, timestamp, uid),
|
|
14
14
|
NodeBB.db.sortedSetAddBulk(
|
|
15
15
|
options.map(option => ([`poll:${pollId}:options:${option}:votes`, timestamp, uid]))
|
|
16
16
|
),
|
|
17
|
-
]
|
|
17
|
+
];
|
|
18
|
+
if (voteData.voteAnon) {
|
|
19
|
+
promises.push(
|
|
20
|
+
NodeBB.db.sortedSetAdd(`poll:${pollId}:anon:voters`, timestamp, uid)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
await Promise.all(promises);
|
|
18
25
|
};
|
|
19
26
|
|
|
20
27
|
Vote.remove = async function (voteData) {
|
|
@@ -29,7 +36,10 @@ Vote.removeUidVote = async function (uid, pollId) {
|
|
|
29
36
|
const vote = await Vote.getUidVote(uid, pollId);
|
|
30
37
|
const options = vote.options || [];
|
|
31
38
|
await Promise.all([
|
|
32
|
-
NodeBB.db.
|
|
39
|
+
NodeBB.db.sortedSetsRemove([
|
|
40
|
+
`poll:${pollId}:voters`,
|
|
41
|
+
`poll:${pollId}:anon:voters`,
|
|
42
|
+
], uid),
|
|
33
43
|
NodeBB.db.sortedSetsRemove(
|
|
34
44
|
options.map(option => `poll:${pollId}:options:${option}:votes`),
|
|
35
45
|
uid,
|
|
@@ -49,7 +59,10 @@ Vote.getUidVote = async function (uid, pollId) {
|
|
|
49
59
|
};
|
|
50
60
|
|
|
51
61
|
Vote.update = async function (voteData) {
|
|
62
|
+
const { uid, pollId } = voteData;
|
|
63
|
+
const isVotedAnon = await NodeBB.db.isSortedSetMember(`poll:${pollId}:anon:voters`, uid);
|
|
52
64
|
await Vote.remove(voteData);
|
|
65
|
+
voteData.voteAnon = isVotedAnon;
|
|
53
66
|
await Vote.add(voteData);
|
|
54
67
|
};
|
|
55
68
|
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -70,15 +70,17 @@
|
|
|
70
70
|
return alerts.error('[[error:category-not-selected]]');
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
socket.emit('plugins.poll.canCreate', {
|
|
74
|
+
cid: post.cid,
|
|
75
|
+
pid: post.pid,
|
|
76
|
+
}, function (err, canCreate) {
|
|
74
77
|
if (err) {
|
|
75
|
-
return alerts.error(err
|
|
78
|
+
return alerts.error(err);
|
|
76
79
|
}
|
|
77
80
|
if (!canCreate) {
|
|
78
81
|
return alerts.error('[[error:no-privileges]]');
|
|
79
82
|
}
|
|
80
|
-
|
|
81
|
-
Poll.sockets.getConfig(null, function (err, config) {
|
|
83
|
+
socket.emit('plugins.poll.getConfig', null, function (err, config) {
|
|
82
84
|
if (err) {
|
|
83
85
|
return alerts.error(err);
|
|
84
86
|
}
|
|
@@ -217,6 +219,7 @@
|
|
|
217
219
|
title: obj['settings.title'],
|
|
218
220
|
maxvotes: obj['settings.maxvotes'],
|
|
219
221
|
disallowVoteUpdate: obj['settings.disallowVoteUpdate'] === 'on' ? 'true' : 'false',
|
|
222
|
+
allowAnonVoting: obj['settings.allowAnonVoting'] === 'on' ? 'true' : 'false',
|
|
220
223
|
end: obj['settings.end'],
|
|
221
224
|
},
|
|
222
225
|
};
|
package/public/js/poll/main.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
/* global Poll */
|
|
4
|
+
|
|
3
5
|
window.Poll = {};
|
|
4
6
|
|
|
5
7
|
(function () {
|
|
@@ -9,7 +11,9 @@ window.Poll = {};
|
|
|
9
11
|
});
|
|
10
12
|
};
|
|
11
13
|
|
|
14
|
+
// eslint-disable-next-line import/no-unresolved
|
|
12
15
|
require('poll/serializer')(window.utils);
|
|
16
|
+
|
|
13
17
|
$(window).on('action:topic.loading', function () {
|
|
14
18
|
if (ajaxify.data.posts.length > 0 && ajaxify.data.posts[0].hasOwnProperty('pollId')) {
|
|
15
19
|
getPoll(ajaxify.data.posts[0].pollId);
|
|
@@ -30,11 +34,15 @@ window.Poll = {};
|
|
|
30
34
|
}
|
|
31
35
|
});
|
|
32
36
|
|
|
37
|
+
socket.on('event:poll.voteChange', function (data) {
|
|
38
|
+
Poll.view.update(data);
|
|
39
|
+
});
|
|
40
|
+
|
|
33
41
|
function getPoll(pollId) {
|
|
34
42
|
pollId = parseInt(pollId, 10);
|
|
35
43
|
|
|
36
44
|
if (!isNaN(pollId)) {
|
|
37
|
-
|
|
45
|
+
socket.emit('plugins.poll.get', { pollId }, function (err, pollData) {
|
|
38
46
|
if (err) {
|
|
39
47
|
return Poll.alertError(err.message);
|
|
40
48
|
}
|
|
@@ -30,6 +30,14 @@ module.exports = function (utils) {
|
|
|
30
30
|
return value === 'true' || value === true ? 1 : 0;
|
|
31
31
|
},
|
|
32
32
|
},
|
|
33
|
+
allowAnonVoting: {
|
|
34
|
+
test: function (value) {
|
|
35
|
+
return /true|false/.test(value);
|
|
36
|
+
},
|
|
37
|
+
parse: function (value) {
|
|
38
|
+
return value === 'true' || value === true ? 1 : 0;
|
|
39
|
+
},
|
|
40
|
+
},
|
|
33
41
|
end: {
|
|
34
42
|
test: function (value) {
|
|
35
43
|
return (!isNaN(value) && parseInt(value, 10) > Date.now());
|
package/public/js/poll/view.js
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
(function (Poll) {
|
|
4
|
+
function vote(view, options) {
|
|
5
|
+
var form = view.dom.votingPanel.find('form');
|
|
6
|
+
var votes = form.serializeArray().map(function (option) {
|
|
7
|
+
return parseInt(option.value, 10);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
if (votes.length > 0) {
|
|
11
|
+
var voteData = {
|
|
12
|
+
pollId: view.pollData.info.pollId,
|
|
13
|
+
options: votes,
|
|
14
|
+
voteAnon: options.voteAnon,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
socket.emit('plugins.poll.vote', voteData, function (err) {
|
|
18
|
+
if (!config.loggedIn) {
|
|
19
|
+
$(window).trigger('action:poll.vote.notloggedin');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (err) {
|
|
23
|
+
return Poll.alertError(err.message);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
view.showResultsPanel();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
4
31
|
var Actions = [
|
|
5
32
|
{
|
|
6
33
|
// Voting
|
|
@@ -11,33 +38,27 @@
|
|
|
11
38
|
});
|
|
12
39
|
},
|
|
13
40
|
handle: function (view) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return parseInt(option.value, 10);
|
|
41
|
+
vote(view, {
|
|
42
|
+
voteAnon: false,
|
|
17
43
|
});
|
|
18
|
-
|
|
19
|
-
if (votes.length > 0) {
|
|
20
|
-
var voteData = {
|
|
21
|
-
pollId: view.pollData.info.pollId,
|
|
22
|
-
options: votes,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
Poll.sockets.vote(voteData, function (err) {
|
|
26
|
-
if (!config.loggedIn) {
|
|
27
|
-
$(window).trigger('action:poll.vote.notloggedin');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (err) {
|
|
31
|
-
return Poll.alertError(err.message);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
view.showResultsPanel();
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
44
|
},
|
|
38
45
|
},
|
|
39
46
|
{
|
|
40
|
-
//
|
|
47
|
+
// vote anon
|
|
48
|
+
register: function (view) {
|
|
49
|
+
var self = this;
|
|
50
|
+
view.dom.voteAnonButton.off('click').on('click', function () {
|
|
51
|
+
self.handle(view);
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
handle: function (view) {
|
|
55
|
+
vote(view, {
|
|
56
|
+
voteAnon: true,
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
// update voting
|
|
41
62
|
register: function (view) {
|
|
42
63
|
var self = this;
|
|
43
64
|
view.dom.updateVoteButton.off('click').on('click', function () {
|
|
@@ -55,8 +76,7 @@
|
|
|
55
76
|
pollId: view.pollData.info.pollId,
|
|
56
77
|
options: votes,
|
|
57
78
|
};
|
|
58
|
-
|
|
59
|
-
Poll.sockets.updateVote(voteData, function (err) {
|
|
79
|
+
socket.emit('plugins.poll.updateVote', voteData, function (err) {
|
|
60
80
|
if (err) {
|
|
61
81
|
return Poll.alertError(err.message);
|
|
62
82
|
}
|
|
@@ -76,7 +96,7 @@
|
|
|
76
96
|
handle: function (view) {
|
|
77
97
|
var voteData = { pollId: view.pollData.info.pollId };
|
|
78
98
|
|
|
79
|
-
|
|
99
|
+
socket.emit('plugins.poll.removeVote', voteData, function (err) {
|
|
80
100
|
if (err) {
|
|
81
101
|
return Poll.alertError(err.message);
|
|
82
102
|
}
|
|
@@ -119,7 +139,7 @@
|
|
|
119
139
|
handle: function (view, e) {
|
|
120
140
|
var optionId = $(e.currentTarget).parents('[data-poll-option-id]').data('poll-option-id');
|
|
121
141
|
|
|
122
|
-
|
|
142
|
+
socket.emit('plugins.poll.getOptionDetails', {
|
|
123
143
|
pollId: view.pollData.info.pollId,
|
|
124
144
|
optionId: optionId,
|
|
125
145
|
}, function (err, details) {
|
|
@@ -140,7 +160,7 @@
|
|
|
140
160
|
});
|
|
141
161
|
},
|
|
142
162
|
handle: function (view) {
|
|
143
|
-
|
|
163
|
+
socket.emit('plugins.poll.getConfig', null, function (err, config) {
|
|
144
164
|
if (err) {
|
|
145
165
|
console.error(err);
|
|
146
166
|
}
|
|
@@ -170,6 +190,7 @@
|
|
|
170
190
|
votingPanel: panel.find('.poll-view-voting'),
|
|
171
191
|
resultsPanel: panel.find('.poll-view-results'),
|
|
172
192
|
voteButton: panel.find('.poll-button-vote'),
|
|
193
|
+
voteAnonButton: panel.find('.poll-button-vote-anon'),
|
|
173
194
|
updateVoteButton: panel.find('.poll-button-update-vote'),
|
|
174
195
|
removeVoteButton: panel.find('.poll-button-remove-vote'),
|
|
175
196
|
votingPanelButton: panel.find('.poll-button-voting'),
|
|
@@ -250,15 +271,17 @@
|
|
|
250
271
|
};
|
|
251
272
|
|
|
252
273
|
View.prototype.showOptionDetails = function (details) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
274
|
+
require(['bootbox'], function (bootbox) {
|
|
275
|
+
app.parseAndTranslate('poll/view/details', details, function (html) {
|
|
276
|
+
bootbox.dialog({
|
|
277
|
+
message: html,
|
|
278
|
+
backdrop: true,
|
|
279
|
+
buttons: {
|
|
280
|
+
close: {
|
|
281
|
+
label: 'Close',
|
|
282
|
+
},
|
|
260
283
|
},
|
|
261
|
-
}
|
|
284
|
+
});
|
|
262
285
|
});
|
|
263
286
|
});
|
|
264
287
|
};
|
|
@@ -290,6 +313,9 @@
|
|
|
290
313
|
}
|
|
291
314
|
} else {
|
|
292
315
|
this.showVoteButton();
|
|
316
|
+
if (this.pollData.settings.allowAnonVoting) {
|
|
317
|
+
this.showVoteAnonButton();
|
|
318
|
+
}
|
|
293
319
|
}
|
|
294
320
|
this.dom.votingPanel.removeClass('hidden');
|
|
295
321
|
};
|
|
@@ -300,6 +326,7 @@
|
|
|
300
326
|
this.hideRemoveVoteButton();
|
|
301
327
|
this.resetVotingForm();
|
|
302
328
|
this.hideVoteButton();
|
|
329
|
+
this.hideVoteAnonButton();
|
|
303
330
|
this.dom.votingPanel.addClass('hidden');
|
|
304
331
|
};
|
|
305
332
|
|
|
@@ -326,6 +353,14 @@
|
|
|
326
353
|
this.dom.voteButton.addClass('hidden');
|
|
327
354
|
};
|
|
328
355
|
|
|
356
|
+
View.prototype.showVoteAnonButton = function () {
|
|
357
|
+
this.dom.voteAnonButton.removeClass('hidden');
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
View.prototype.hideVoteAnonButton = function () {
|
|
361
|
+
this.dom.voteAnonButton.addClass('hidden');
|
|
362
|
+
};
|
|
363
|
+
|
|
329
364
|
View.prototype.showUpdateVoteButton = function () {
|
|
330
365
|
this.dom.updateVoteButton.removeClass('hidden');
|
|
331
366
|
};
|
|
@@ -26,11 +26,14 @@
|
|
|
26
26
|
min="1" max="10" step="1" placeholder="[[poll:max_votes_placeholder]]" class="form-control">
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
|
-
<div class="mb-3">
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
<div class="form-check mb-3">
|
|
30
|
+
<label class="form-check-label" for="pollDisallowVoteUpdate">[[poll:disallow_vote_update]]</label>
|
|
31
|
+
<input class="form-check-input" type="checkbox" name="settings.disallowVoteUpdate" id="pollDisallowVoteUpdate" {{{if poll.settings.disallowVoteUpdate}}}checked{{{end}}}>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="form-check mb-3">
|
|
35
|
+
<label class="form-check-label" for="allowAnonVoting">[[poll:allow_anon_voting]]</label>
|
|
36
|
+
<input class="form-check-input" type="checkbox" name="settings.allowAnonVoting" id="allowAnonVoting" {{{if poll.settings.allowAnonVoting}}}checked{{{end}}}>
|
|
34
37
|
</div>
|
|
35
38
|
|
|
36
39
|
<div class="mb-3">
|
package/templates/poll/view.tpl
CHANGED
|
@@ -18,11 +18,12 @@
|
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
20
|
<div class="poll-view-buttons">
|
|
21
|
-
<button type="button" class="btn btn-primary poll-button-vote hidden">[[poll:vote]]</button>
|
|
22
|
-
<button type="button" class="btn btn-primary poll-button-
|
|
23
|
-
<button type="button" class="btn btn-
|
|
24
|
-
<button type="button" class="btn btn-
|
|
25
|
-
<button type="button" class="btn btn-link poll-button-
|
|
21
|
+
<button type="button" class="btn btn-sm btn-primary poll-button-vote hidden">[[poll:vote]]</button>
|
|
22
|
+
<button type="button" class="btn btn-sm btn-primary poll-button-vote-anon hidden">[[poll:vote_anonymously]]</button>
|
|
23
|
+
<button type="button" class="btn btn-sm btn-primary poll-button-update-vote hidden">[[poll:update_vote]]</button>
|
|
24
|
+
<button type="button" class="btn btn-sm btn-danger poll-button-remove-vote hidden">[[poll:remove_vote]]</button>
|
|
25
|
+
<button type="button" class="btn btn-sm btn-link poll-button-results hidden">[[poll:to_results]]</button>
|
|
26
|
+
<button type="button" class="btn btn-sm btn-link poll-button-voting hidden">[[poll:to_voting]]</button>
|
|
26
27
|
</div>
|
|
27
28
|
</div>
|
|
28
29
|
</div>
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
(function (Poll) {
|
|
4
|
-
var messages = [
|
|
5
|
-
{
|
|
6
|
-
method: 'getPoll',
|
|
7
|
-
message: 'plugins.poll.get',
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
method: 'vote',
|
|
11
|
-
message: 'plugins.poll.vote',
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
method: 'updateVote',
|
|
15
|
-
message: 'plugins.poll.updateVote',
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
method: 'removeVote',
|
|
19
|
-
message: 'plugins.poll.removeVote',
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
method: 'getOptionDetails',
|
|
23
|
-
message: 'plugins.poll.getOptionDetails',
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
method: 'getConfig',
|
|
27
|
-
message: 'plugins.poll.getConfig',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
method: 'canCreate',
|
|
31
|
-
message: 'plugins.poll.canCreate',
|
|
32
|
-
},
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
var handlers = [
|
|
36
|
-
{
|
|
37
|
-
event: 'event:poll.voteChange',
|
|
38
|
-
handle: function (data) {
|
|
39
|
-
Poll.view.update(data);
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
function init() {
|
|
45
|
-
handlers.forEach(function (handler) {
|
|
46
|
-
if (socket.listeners(handler.event).length === 0) {
|
|
47
|
-
socket.on(handler.event, handler.handle);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
messages.forEach(function (message) {
|
|
52
|
-
Poll.sockets[message.method] = function (data, callback) {
|
|
53
|
-
socket.emit(message.message, data, callback);
|
|
54
|
-
};
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
Poll.sockets = {};
|
|
59
|
-
|
|
60
|
-
init();
|
|
61
|
-
}(window.Poll));
|