Commit db5c6e6d authored by Markus Hermann's avatar Markus Hermann 🏈
Browse files

WIP

parent 75ec25c2
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
/** Class representing a poll */
class Poll {
/**
* Create a poll.
* @param {object} pollContainer
*/
constructor(pollContainer) {
this.endpoint_url = "https://testwww.digll-hessen.local/wp-admin/admin-ajax.php";
this.container = pollContainer;
this.id = jQuery(this.container).attr("data-poll-id");
this.nonce = jQuery(this.container).attr("data-poll-nonce");
jQuery(this.container).removeAttr("data-poll-nonce");
}
/**
* Setup and show the initial view.
*/
init() {
jQuery(this.container).html(`
<div class="voteView panel panel-success" style="diplay: none;"></div>
<div class="resultView well" style="diplay: none;"></div>
`);
this.updateView();
}
/**
* Update the current view.
*/
updateView() {
if (this.viewMode === "result") {
this.showResult();
}
if (this.viewMode === "vote") {
this.showVote();
}
}
/**
* Get the mode the view should show.
* @return {string} The mode string
*/
get viewMode() {
return jQuery(this.container).attr("data-poll-view-mode");
}
/**
* Set the mode of the view and update it.
* @param {string} mode - The mode of the view.
*/
set viewMode(mode) {
jQuery(this.container).attr("data-poll-view-mode", mode);
this.updateView();
}
get resultView() {
return jQuery(this.container).children(".resultView")[0];
}
get voteView() {
return jQuery(this.container).children(".voteView")[0];
}
/**
* Start showing the result by fetching the result data.
*/
showResult() {
jQuery.get({
url: this.endpoint_url,
data: `action=hpolls&poll_id=${this.id}&data=results&poll_${this.id}-nonce=${this.nonce}`,
dataType: "json"
}).success(function(data) {
let pollId = data.id;
document.pollController.polls[pollId].showResultCallback(data);
}).fail(function () {
console.log("Fetching the results failed");
});
}
/**
* Show the fetched poll result
* @param {object} data - The returned data as a json object
*/
showResultCallback(data) {
this.nonce = data.nonce;
// Only add new chart if it is not shown yet
if (jQuery(this.resultView).chart === undefined) {
let attrs = {
chart: {
type: "bar",
},
title: {
text: data.results.question,
},
legend: {
enabled: false
},
xAxis: {
categories: [],
title: {
text: null,
},
},
yAxis: {
title: {
text: "Stimmen",
},
labels: {
enabled: true,
},
tickInterval: 1,
showLastLabel: false,
showFirstLabel: false,
},
plotOptions: {
bar: {
dataLabels: {
enabled: true
},
},
},
tooltip: {
enabled: false,
},
credits: {
enabled: false,
},
series: [{
data: [],
colorByPoint: true,
}],
};
for (var i = 0; i < data.results.answers.length; i++) {
let answer = data.results.answers[i];
attrs["xAxis"]["categories"].push(answer.text);
attrs["series"][0]["data"].push(answer.votes);
}
jQuery(this.resultView).html(`
<div id="result-${this.id}"></div>
<div class="totalVotes text-center"></div>
`);
let sum = attrs["series"][0]["data"].reduce((a, b) => a + b, 0);
this.updateVoteCount(sum);
this.resultView.chart = Highcharts.chart(`result-${this.id}`, attrs);
if (data.pollOpen) {
this.addVoteButton();
}
} else {
var seriesData = [];
for (var i = 0; i < data.results.answers.length; i++) {
let answer = data.results.answers[i]
seriesData.push(answer.votes);
}
this.resultView.chart.update({
"series": [{"data": seriesData}]
});
}
jQuery(this.voteView).hide();
jQuery(this.resultView).show();
}
/**
* Update the vote count.
* @param {number} votes - The number of votes.
*/
updateVoteCount(votes) {
jQuery(this.resultView).find(".totalVotes").text(`Abgegebene Stimmen: ${votes}`);
}
/**
* Start showing the vote by fetching the poll data.
*/
showVote() {
jQuery.get({
url: this.endpoint_url,
data: `action=hpolls&poll_id=${this.id}&data=vote&poll_${this.id}-nonce=${this.nonce}`,
dataType: "json"
}).success(function(data) {
let pollId = data.id;
document.pollController.polls[pollId].showVoteCallback(data);
}).fail(function () {
console.log("Fetching the vote failed");
});
}
/**
* Show the fetched poll data
* @param {object} data - The returned data as a json object
*/
showVoteCallback(data) {
var options = "";
if (data.maxVotes > 1) {
options = this.multipleVotesOptions(data.id, data.options);
} else {
options = this.singleVoteOptions(data.id, data.options);
}
let template = `
<div class="panel-heading">${data.question}</div>
<div class="panel-body">
<form>
<div class="form-group">
${options}
</div>
</form>
</div>
`;
jQuery(this.resultView).hide();
jQuery(this.voteView).html(template);
this.addResultButton();
jQuery(this.voteView).show();
}
/**
* Return the single vote options.
* @param {number} pollId - The id of the poll
* @param {object} options - The options to display
* @param {string} The html of the options
*/
singleVoteOptions(pollId, options) {
var options_html = "";
for (var i = 0; i < options.length; i++) {
let option = options[i];
options_html += `
<div class="radio">
<label>
<input id="poll-${pollId}-option-${option.id}" type="radio" name="poll-${pollId}" value="${option.id}">
${option.text}
</label>
</div>`;
}
return options_html;
}
/**
* Return the multiple votes options.
* @param {number} pollId - The id of the poll
* @param {object} options - The options to display
* @param {string} The html of the options
*/
multipleVotesOptions(pollId, options) {
var options_html = "";
for (var i = 0; i < options.length; i++) {
let option = options[i];
options_html += `
<div class="checkbox">
<label>
<input type="checkbox" value="${option.id}">
${option.text}
</label>
</div>`;
}
return options_html;
}
/**
* Append the button to show the voting.
*/
addVoteButton() {
jQuery(this.resultView).append(`
<button class="btn btn-primary" data-poll-id="${this.id}">Abstimmen!</button>
`);
let button = jQuery(this.resultView).children(":button");
jQuery(button).click(function(sender) {
let pollId = jQuery(sender.target).attr("data-poll-id");
document.pollController.polls[pollId].viewMode = "vote";
})
}
/**
* Append the button to show the result.
*/
addResultButton() {
jQuery(this.voteView).children(".panel-body").append(`
<button class="btn btn-primary" data-poll-id="${this.id}">Ergebniss anzeigen!</button>
`);
let button = jQuery(this.voteView).children(":button");
jQuery(button).click(function(sender) {
let pollId = jQuery(sender.target).attr("data-poll-id");
document.pollController.polls[pollId].viewMode = "result";
})
}
}
class PollController {
constructor() {
this.polls = [];
this.pollContainer = [];
this.getContainer();
}
init() {
if (this.pollContainer.length > 0) {
jQuery.each(this.pollContainer, function(index, container) {
document.pollController.addPoll(container);
});
}
}
addPoll(container) {
let poll = new Poll(container);
this.polls[poll.id] = poll;
poll.init();
}
getContainer() {
let pollContainer = jQuery(".hpoll");
this.pollContainer = pollContainer;
}
}
document.pollController = new PollController();
document.pollController.init();
......@@ -1450,6 +1450,7 @@ function vote_poll_process($poll_id, $poll_aid_array = [])
add_action('wp_ajax_polls', 'vote_poll');
add_action('wp_ajax_nopriv_polls', 'vote_poll');
function vote_poll() {
error_log("vote_poll");
global $wpdb, $user_identity, $user_ID;
if( isset( $_REQUEST['action'] ) && sanitize_key( $_REQUEST['action'] ) === 'polls') {
......@@ -1979,3 +1980,220 @@ function polls_activate() {
}
cron_polls_place();
}
### Function: Short Code For Inserting Polls Into Posts
add_shortcode('highpoll', 'highchartsResultShortcode');
function highchartsResultShortcode($atts) {
$attributes = shortcode_atts(['id' => 0, 'type' => 'vote'], $atts);
if (!is_feed()) {
wp_enqueue_script('highcharts', plugins_url('wp-polls/js/highcharts/highcharts.js'), [], "8.2.0", true);
wp_enqueue_script('hpolls', plugins_url('wp-polls/js/hpolls.js'), ["highcharts"], "1.0.0", true);
$id = (int) $attributes['id'];
// To maintain backward compatibility with [poll=1]. Props @tz-ua
if (!$id && isset($atts[0])) {
$id = (int) trim( $atts[0], '="\'' );
}
if ($attributes['type'] === 'vote') {
return displayHighchartsPollVote( $id, false );
} elseif($attributes['type'] === 'result') {
return displayHighchartsPollResult($id);
}
} else {
return __('Note: There is a poll embedded within this post, please visit the site to participate in this post\'s poll.', 'wp-polls');
}
}
add_action('wp_ajax_hpolls', 'pollAPIEndpoint');
add_action('wp_ajax_nopriv_hpolls', 'pollAPIEndpoint');
function pollAPIEndpoint() {
if(isset( $_REQUEST['action']) && sanitize_key($_REQUEST['action']) === 'hpolls') {
header(
sprintf('Content-Type: text/html; charset=%s', get_option('blog_charset'))
);
// Get Poll ID
$poll_id = (isset($_REQUEST['poll_id']) ? (int) sanitize_key($_REQUEST['poll_id']) : 0);
// Ensure Poll ID Is Valid
if($poll_id === 0) {
exit(_e('Invalid Poll ID', 'wp-polls'));
}
// Verify Referer
$ref_name = sprintf('poll_%s-nonce', $poll_id);
if(!check_ajax_referer($ref_name, $ref_name, false )) {
exit(_e('Failed To Verify Referrer', 'wp-polls'));
}
switch(sanitize_key($_REQUEST['data'])) {
case "results":
echo poll_results($poll_id);
break;
case "vote":
echo poll_vote($poll_id);
break;
}
}
exit();
}
function poll_results($poll_id) {
$wpdb = $GLOBALS['wpdb'];
$poll_open = false;
// Get the question
$question_result = $wpdb->get_row(
$wpdb->prepare(
"SELECT pollq_id, pollq_question AS question, pollq_active AS is_active FROM $wpdb->pollsq WHERE pollq_id = %d LIMIT 1",
$poll_id
)
);
$question = $question_result->question;
$poll_open = ((int) $question_result->is_active === 1) ? true : false;
// Get the answers
$answers = [];
$answers_result = $wpdb->get_results(
$wpdb->prepare(
"SELECT polla_aid, polla_answers AS answer, polla_votes AS votes FROM $wpdb->pollsa WHERE polla_qid = %d ORDER BY polla_aid ASC",
$poll_id
)
);
foreach ($answers_result as $answer) {
$answers[] = [
"text" => $answer->answer,
"votes" => (int) $answer->votes
];
}
$nonce = wp_create_nonce(sprintf('poll_%s-nonce', $poll_id));
return json_encode([
"results" => [
"question" => $question,
"answers" => $answers
],
"id" => $poll_id,
"pollOpen" => $poll_open,
"nonce" => $nonce,
]);
}
function poll_vote($poll_id) {
$wpdb = $GLOBALS['wpdb'];
$poll_open = false;
// Get the question
$question_result = $wpdb->get_row(
$wpdb->prepare(
"SELECT pollq_id, pollq_question AS question, pollq_active AS is_active, pollq_multiple AS max_votes FROM $wpdb->pollsq WHERE pollq_id = %d LIMIT 1",
$poll_id
)
);
$question = $question_result->question;
$poll_open = ((int) $question_result->is_active === 1) ? true : false;
$max_votes = (int) $question->max_votes;
$options = [];
$poll_answers = $wpdb->get_results(
$wpdb->prepare(
"SELECT polla_aid, polla_qid, polla_answers AS option FROM $wpdb->pollsa WHERE polla_qid = %d ORDER BY polla_aid ASC",
$poll_id
)
);
foreach ($poll_answers as $key => $answer) {
$options[] = [
"id" => $answer->polla_aid,
"text" => $answer->option
];
}
return json_encode([
"id" => $poll_id,
"pollOpen" => $poll_open,
"question" => $question,
"options" => $options,
"maxVotes" => $max_votes,
"nonce" => $nonce,
]);
}
function displayHighchartsPollVote($poll_id, $user_voted = [], $display_loading = true) {
$nonce = wp_create_nonce(sprintf('poll_%s-nonce', $poll_id));
return sprintf(
'<div data-poll-id="%s" class="hpoll" data-poll-nonce="%s" data-poll-view-mode="vote"></div>',
$poll_id,
$nonce
);
}
function displayHighchartsPollResult($poll_id, $user_voted = [], $display_loading = true) {
$chartAttributes = [
"chart" => [
"type" => "bar"
],
"title" => [
"text" => ""
],
"legend" => [
"enabled" => false
],
"xAxis" => [
"categories" => [],
"title" => [
"text" => null,
]
],
"yAxis" => [
"title" => [
"text" => "Stimmen",
],
"labels" => [
"enabled" => true,
],
"tickInterval" => 1,
"showLastLabel" => false,
"showFirstLabel" => false,
],
"plotOptions" => [
"bar" => [
"dataLabels" => [
"enabled" => true
]
]
],
"tooltip" => [
"enabled" => false,
],
"credits" => [
"enabled" => false
],
"series" => [
[
"data" => [],
"colorByPoint" => true,
]
]
];
$nonce = wp_create_nonce(sprintf('poll_%s-nonce', $poll_id));
// Return Poll Result
return sprintf(
'<div data-poll-id="%s" class="hpoll" data-poll-nonce="%s" data-poll-view-mode="result"></div>',
$poll_id,
$nonce
);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment