Files
2021-02-16 23:07:41 +01:00

363 lines
13 KiB
JavaScript

/*
* Copyright (C) 2016-2020 phantombot.github.io/PhantomBot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* pollSystem.js
*
* This module enables the channel owner to start/manage polls
* Start/stop polls is exported to $.poll for use in other scripts
*/
(function() {
var poll = {
pollId: 0,
options: [],
votes: [],
voters: [],
callback: function() {},
pollRunning: false,
pollMaster: '',
time: 0,
question: '',
minVotes: 0,
result: '',
hasTie: 0,
counts: [],
},
timeout;
var objOBS = [];
/**
* @function hasKey
* @param {Array} list
* @param {*} value
* @param {Number} [subIndex]
* @returns {boolean}
*/
function hasKey(list, value, subIndex) {
var i;
if (subIndex > -1) {
for (i in list) {
if (list[i][subIndex].equalsIgnoreCase(value)) {
return true;
}
}
} else {
for (i in list) {
if (list[i].equalsIgnoreCase(value)) {
return true;
}
}
}
return false;
};
// Compile regular expressions.
var rePollOpenFourOptions = new RegExp(/"([\w\W]+)"\s+"([\w\W]+)"\s+(\d+)\s+(\d+)/),
rePollOpenThreeOptions = new RegExp(/"([\w\W]+)"\s+"([\w\W]+)"\s+(\d+)/),
rePollOpenTwoOptions = new RegExp(/"([\w\W]+)"\s+"([\w\W]+)"/);
/**
* @function runPoll
* @export $.poll
* @param {string} question
* @param {Array} options
* @param {Number} time
* @param {string} pollMaster
* @param {Number} [minVotes]
* @param {Function} callback
* @param {string} [initialVote]
* @returns {boolean}
*/
function runPoll(question, options, time, pollMaster, minVotes, callback) {
var optionsStr = "";
if (poll.pollRunning) {
return false
}
objOBS = [];
poll.pollRunning = true;
poll.pollMaster = pollMaster;
poll.time = (parseInt(time) * 1000);
poll.callback = callback;
poll.question = question;
poll.options = options;
poll.minVotes = (minVotes ? minVotes : 1);
poll.votes = [];
poll.voters = [];
poll.counts = [];
poll.hasTie = 0;
// Remove the old files.
$.inidb.RemoveFile('pollPanel');
$.inidb.RemoveFile('pollVotes');
for (var i = 0; i < poll.options.length; i++) {
optionsStr += (i + 1) + ") " + poll.options[i] + " ";
$.inidb.set('pollVotes', poll.options[i], 0);
objOBS.push({
'label': poll.options[i],
'votes': 0
});
}
if (poll.time > 0) {
$.say($.lang.get('pollsystem.poll.started', $.resolveRank(pollMaster), time, poll.minVotes, poll.question, optionsStr));
timeout = setTimeout(function() {
endPoll();
}, poll.time);
} else {
$.say($.lang.get('pollsystem.poll.started.nottime', $.resolveRank(pollMaster), poll.minVotes, poll.question, optionsStr));
}
var msg = JSON.stringify({
'start_poll': 'true',
'data': JSON.stringify(objOBS)
});
$.alertspollssocket.sendJSONToAll(msg);
$.inidb.set('pollPanel', 'title', question);
$.inidb.set('pollPanel', 'options', options.join(','));
$.inidb.set('pollPanel', 'isActive', 'true');
return true;
};
/**
* @function vote
* @param {string} sender
* @param {string} voteText
*/
function vote(sender, voteText) {
var optionIndex;
if (!poll.pollRunning) {
return;
}
if (hasKey(poll.voters, sender.toLowerCase())) {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.vote.already'));
return;
}
optionIndex = parseInt(voteText);
if (isNaN(optionIndex) || optionIndex < 1 || optionIndex > poll.options.length) {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.vote.invalid', voteText));
return;
}
optionIndex--;
poll.voters.push(sender);
poll.votes.push(optionIndex);
for (var i = 0; i < objOBS.length; i++) {
if (objOBS[i].label == poll.options[optionIndex])
objOBS[i].votes++;
}
var msg = JSON.stringify({
'new_vote': 'true',
'data': JSON.stringify(objOBS)
});
$.alertspollssocket.sendJSONToAll(msg);
$.inidb.incr('pollVotes', poll.options[optionIndex], 1);
};
/**
* @function endPoll
* @export $.poll
*/
function endPoll() {
var mostVotes = -1,
i;
if (!poll.pollRunning) {
return;
}
clearTimeout(timeout);
$.inidb.set('pollPanel', 'isActive', 'false');
var msg = JSON.stringify({
'end_poll': 'true'
});
$.alertspollssocket.sendJSONToAll(msg);
if (poll.minVotes > 0 && poll.votes.length < poll.minVotes) {
poll.result = '';
poll.pollMaster = '';
poll.pollRunning = false;
poll.callback(false);
return;
}
for (i = 0; i < poll.options.length; poll.counts.push(0), i++);
for (i = 0; i < poll.votes.length; poll.counts[poll.votes[i++]] += 1);
for (i = 0; i < poll.counts.length; winner = ((poll.counts[i] > mostVotes) ? i : winner), mostVotes = ((poll.counts[i] > mostVotes) ? poll.counts[i] : mostVotes), i++);
for (i = 0; i < poll.counts.length;
(i != winner && poll.counts[i] == poll.counts[winner] ? poll.hasTie = 1 : 0), (poll.hasTie == 1 ? i = poll.counts.length : 0), i++);
poll.result = poll.options[winner];
poll.pollMaster = '';
poll.pollRunning = false;
// Store the results for the Panel to read.
$.inidb.set('pollresults', 'question', poll.question);
$.inidb.set('pollresults', 'result', poll.result);
$.inidb.set('pollresults', 'votes', poll.votes.length);
$.inidb.set('pollresults', 'options', poll.options.join(','));
$.inidb.set('pollresults', 'counts', poll.counts.join(','));
$.inidb.set('pollresults', 'istie', poll.hasTie);
poll.callback(poll.result);
};
/**
* @event command
*/
$.bind('command', function(event) {
var sender = event.getSender().toLowerCase(),
command = event.getCommand(),
argsString = event.getArguments().trim(),
args = event.getArgs(),
action = args[0];
if (command.equalsIgnoreCase('vote') && action !== undefined) {
if (poll.pollRunning) {
vote(sender, action);
}
}
/**
* @commandpath poll - Announce information about a poll, if one is running.
*/
if (command.equalsIgnoreCase('poll')) {
if (!action) {
if (poll.pollRunning) {
var optionsStr = "";
for (var i = 0; i < poll.options.length; i++) {
optionsStr += (i + 1) + ") " + poll.options[i] + (i == poll.options.length - 1 ? "" : " ");
}
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.poll.running', poll.question, optionsStr));
} else {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.poll.usage'));
}
return;
}
/**
* @commandpath poll results - Announce result information about the last run poll (Poll information is retained until shutdown)
*/
if (action.equalsIgnoreCase('results')) {
if (poll.pollRunning) {
$.say($.lang.get('pollsystem.results.running'));
} else if (poll.result != '') {
if (poll.hasTie) {
$.say($.lang.get('pollsystem.results.lastpoll', poll.question, poll.votes.length, "Tie!", poll.options.join(', '), poll.counts.join(', ')));
} else {
$.say($.lang.get('pollsystem.results.lastpoll', poll.question, poll.votes.length, poll.result, poll.options.join(', '), poll.counts.join(', ')));
}
} else {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.results.404'));
}
}
/**
* @commandpath poll open ["poll question"] ["option1, option2, ..."] [seconds] [min votes] - Starts a poll with question and options. Optionally provide seconds and min votes.
*/
if (action.equalsIgnoreCase('open')) {
var time = 0,
question = '',
options = [],
minVotes = 1;
argsString = argsString + ""; // Cast as a JavaScript string.
if (argsString.match(rePollOpenFourOptions)) {
question = argsString.match(rePollOpenFourOptions)[1];
options = argsString.match(rePollOpenFourOptions)[2].split(/,\s*/);
time = parseInt(argsString.match(rePollOpenFourOptions)[3]);
minVotes = parseInt(argsString.match(rePollOpenFourOptions)[4]);
} else if (argsString.match(rePollOpenThreeOptions)) {
question = argsString.match(rePollOpenThreeOptions)[1];
options = argsString.match(rePollOpenThreeOptions)[2].split(/,\s*/);
time = parseInt(argsString.match(rePollOpenThreeOptions)[3]);
} else if (argsString.match(rePollOpenTwoOptions)) {
question = argsString.match(rePollOpenTwoOptions)[1];
options = argsString.match(rePollOpenTwoOptions)[2].split(/,\s*/);
} else {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.open.usage'));
return;
}
if (!question || !options || options.length === 0 || isNaN(minVotes) || minVotes < 1) {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.open.usage'));
return;
}
if (options.length === 1) {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.open.moreoptions'));
return;
}
if (runPoll(question, options, parseInt(time), sender, minVotes, function(winner) {
if (winner === false) {
$.say($.lang.get('pollsystem.runpoll.novotes', question));
return;
}
if (poll.hasTie) {
$.say($.lang.get('pollsystem.runpoll.tie', question));
} else {
$.say($.lang.get('pollsystem.runpoll.winner', question, winner));
}
})) {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.runpoll.started'));
} else {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.results.running'));
}
}
/**
* @commandpath poll close - Close the current poll and tally the votes
*/
if (action.equalsIgnoreCase('close')) {
if (!poll.pollRunning) {
$.say($.whisperPrefix(sender) + $.lang.get('pollsystem.close.nopoll'));
return;
}
endPoll();
}
}
});
/**
* @event initReady
*/
$.bind('initReady', function() {
$.registerChatCommand('./systems/pollSystem.js', 'poll', 2);
$.registerChatCommand('./systems/pollSystem.js', 'vote', 7);
$.registerChatSubcommand('poll', 'results', 2);
$.registerChatSubcommand('poll', 'open', 2);
$.registerChatSubcommand('poll', 'close', 2);
});
/** Export functions to API */
$.poll = {
runPoll: runPoll,
endPoll: endPoll
};
})();