Merge pull request #21 from vincentmdealmeida/Fixes
Fixed a number of bugs that arose from merging the code from Bens for…
This commit is contained in:
commit
59d3b26e95
6 changed files with 281 additions and 75 deletions
|
@ -211,7 +211,7 @@ class Ballot(models.Model):
|
|||
|
||||
class EncBallot(models.Model):
|
||||
handle = models.CharField(primary_key=True, default=uuid.uuid4, editable=False, max_length=255)
|
||||
ballot = models.CharField(max_length=4096)
|
||||
ballot = models.CharField(max_length=10240)
|
||||
|
||||
|
||||
# Implements the new binary encoding scheme
|
||||
|
|
|
@ -212,6 +212,22 @@ def email_voters_vote_url(voters, event):
|
|||
voter.send_email(email_subject, email_body)
|
||||
|
||||
|
||||
@task()
|
||||
def email_voting_success(voter, ballotHandle, eventTitle):
|
||||
email_subject = "Vote(s) received for Event '" + eventTitle + "'"
|
||||
|
||||
# Plain text email - this could be replaced for a HTML-based email in the future
|
||||
email_body_base = str("")
|
||||
email_body_base += "Dear Voter,\n\n"
|
||||
email_body_base += "Thank you for your vote(s) for the event: " + eventTitle + ". This has been securely encrypted "
|
||||
email_body_base += "and anonymously stored in our system.\n\n"
|
||||
email_body_base += "For your reference, the identifier for your selected ballot is:\n"
|
||||
email_body_base += ballotHandle
|
||||
email_body_base += get_email_sign_off()
|
||||
|
||||
voter.send_email(email_subject, email_body_base)
|
||||
|
||||
|
||||
'''
|
||||
Updates the EID of an event to contain 2 event IDs: a human readable one (hr) and a crypto one (GP from param())
|
||||
'''
|
||||
|
|
|
@ -18,6 +18,7 @@ from allauthdemo.auth.models import DemoUser
|
|||
|
||||
from .tasks import email_trustees_prep, update_EID, generate_combpk, event_ended, create_ballots
|
||||
from .tasks import create_ballots_for_poll, email_voters_vote_url, combine_decryptions_and_tally, combine_encrypted_votes
|
||||
from .tasks import email_voting_success
|
||||
|
||||
from .utils.EventModelAdaptor import EventModelAdaptor
|
||||
|
||||
|
@ -220,7 +221,9 @@ def event_vote(request, event_id, poll_id):
|
|||
ballot.selection = selection
|
||||
ballot.save()
|
||||
|
||||
combine_encrypted_votes.delay(email_key[0].user, poll)
|
||||
voter = email_key[0].user
|
||||
combine_encrypted_votes.delay(voter, poll)
|
||||
email_voting_success.delay(voter, handle_json, event.title)
|
||||
|
||||
if next_poll_uuid:
|
||||
return HttpResponseRedirect(reverse('polls:event-vote', kwargs={'event_id': event.uuid,
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
{% endif %}
|
||||
</span>
|
||||
<br/>
|
||||
<span><strong>Number of polls for this event:</strong> {{ poll_count }}</span>
|
||||
<br/>
|
||||
<br/>
|
||||
<span><strong>Instructions:</strong>
|
||||
You will be shown each poll for this event one by one where you will need to make a selection for the current
|
||||
|
@ -61,26 +59,21 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Options</strong></div>
|
||||
<div class="panel panel-body">
|
||||
{% comment %}<select class="radio-inline select form-control" id="poll-options" name="options">
|
||||
{% load custom_filters_tags %}
|
||||
<option value="{{ -1|get_ballot_value:object.options.all.count }}">Please Select...</option>
|
||||
{% for option in object.options.all %}
|
||||
<option value="{{forloop.counter|get_ballot_value:object.options.all.count}}">{{ option.choice_text }}</option>
|
||||
{% endfor %}
|
||||
</select>{% endcomment %}
|
||||
{% for option in object.options.all %}
|
||||
<div class="checkbox">
|
||||
{% load custom_filters_tags %}
|
||||
<label><input type="checkbox" value="{{forloop.counter|get_ballot_value:object.options.all.count}}">{{ option.choice_text }}</label>
|
||||
<label id="{{forloop.counter|get_ballot_value:object.options.all.count}}">
|
||||
<input type="checkbox" value="{{forloop.counter|get_ballot_value:object.options.all.count}}">{{ option.choice_text }}
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<hr/>
|
||||
<div id="ballot-gen-progress-area">
|
||||
<button id="gen-ballots-btn" class="btn btn-primary">Generate Ballots</button>
|
||||
<button id="gen-ballots-btn" class="btn btn-primary">Begin Voting</button>
|
||||
<!-- Progress bar which is used during encryption -->
|
||||
<h4 id="progress-bar-description" class="hidden">Generating Ballots...</h4>
|
||||
<h4 id="progress-bar-description" class="hidden">Generating 2 Digital Ballots. Please wait...</h4>
|
||||
<div id="progress-bar-container" class="progress hidden">
|
||||
<div id="progress-bar" class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<div id="progress-bar" class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="sr-only">70% Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -124,8 +117,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="cancelVoteBtn" type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
|
||||
<button id="nextDialogBtn" type="button" class="btn btn-primary">Next</button>
|
||||
<button id="cancelDialogBtn" type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
|
||||
<button id="closeDialogBtn" type="button" class="btn btn-primary hidden" data-dismiss="modal">Close</button>
|
||||
<button id="startOverDialogBtn" type="button" class="btn btn-danger hidden" data-dismiss="modal">Start Over</button>
|
||||
<button id="submitDialogBtn" type="button" class="btn btn-success hidden">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -209,3 +209,29 @@ input[type="file"] {
|
|||
width: 54%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
img[src^="data"] {
|
||||
width: 45%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.containerMarginTop {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.skDIV {
|
||||
width: 75%;
|
||||
margin: 0 auto;
|
||||
height: 3em;
|
||||
background-color: darkslategrey;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.skDIV > p {
|
||||
text-align: center;
|
||||
height: 3em;
|
||||
vertical-align: middle;
|
||||
line-height: 2.9em;
|
||||
}
|
|
@ -1,4 +1,11 @@
|
|||
var dialogOpen = false;
|
||||
var DIALOG_BTN_STATES = {
|
||||
STEP_1: 1,
|
||||
STEP_2: 2,
|
||||
STEP_3: 3,
|
||||
VOTE_SUCCESS: 4,
|
||||
VOTE_ERROR: 5
|
||||
};
|
||||
|
||||
function showDialogWithText(titleTxt, bodyTxt) {
|
||||
var modalDialog = $('#modalDialog');
|
||||
|
@ -18,6 +25,47 @@ function showDialogWithText(titleTxt, bodyTxt) {
|
|||
}
|
||||
}
|
||||
|
||||
function updateDialogButtons(state) {
|
||||
// Trigger the btn selectors once here
|
||||
let nextDialogBtn = $('#nextDialogBtn');
|
||||
let cancelDialogBtn = $('#cancelDialogBtn');
|
||||
let closeDialogBtn = $('#closeDialogBtn');
|
||||
let startOverDialogBtn = $('#startOverDialogBtn');
|
||||
let submitDialogBtn = $('#submitDialogBtn');
|
||||
|
||||
switch(state) {
|
||||
case DIALOG_BTN_STATES.STEP_1:
|
||||
nextDialogBtn.removeClass("hidden");
|
||||
cancelDialogBtn.removeClass("hidden");
|
||||
closeDialogBtn.addClass("hidden");
|
||||
startOverDialogBtn.addClass("hidden");
|
||||
submitDialogBtn.addClass("hidden");
|
||||
break;
|
||||
case DIALOG_BTN_STATES.STEP_2:
|
||||
nextDialogBtn.addClass("hidden");
|
||||
cancelDialogBtn.removeClass("hidden");
|
||||
closeDialogBtn.addClass("hidden");
|
||||
startOverDialogBtn.addClass("hidden");
|
||||
submitDialogBtn.addClass("hidden");
|
||||
break;
|
||||
case DIALOG_BTN_STATES.STEP_3:
|
||||
nextDialogBtn.addClass("hidden");
|
||||
cancelDialogBtn.addClass("hidden");
|
||||
closeDialogBtn.addClass("hidden");
|
||||
startOverDialogBtn.removeClass("hidden");
|
||||
submitDialogBtn.removeClass("hidden");
|
||||
break;
|
||||
case DIALOG_BTN_STATES.VOTE_SUCCESS:
|
||||
case DIALOG_BTN_STATES.VOTE_ERROR:
|
||||
nextDialogBtn.addClass("hidden");
|
||||
cancelDialogBtn.addClass("hidden");
|
||||
closeDialogBtn.removeClass("hidden");
|
||||
startOverDialogBtn.addClass("hidden");
|
||||
submitDialogBtn.addClass("hidden");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This should stop people ticking more than the maximum permitted
|
||||
function updateCheckboxInteractivity() {
|
||||
var inputs = $("label input[type=checkbox]");
|
||||
|
@ -65,10 +113,6 @@ function isVotingInputValid() {
|
|||
valid = false;
|
||||
}
|
||||
|
||||
if(selectedCount < MAX_SELECTIONS) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
// This will highlight when people haven't selected enough options
|
||||
|
||||
if(!valid) {
|
||||
|
@ -86,6 +130,7 @@ function isVotingInputValid() {
|
|||
let titleTxt = 'Voting Error';
|
||||
|
||||
showDialogWithText(titleTxt, errText);
|
||||
updateDialogButtons(DIALOG_BTN_STATES.VOTE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -259,6 +304,18 @@ function SHA256Hash(bytes, toStr) {
|
|||
}
|
||||
|
||||
function generateBallots() {
|
||||
// Get the user's selected option
|
||||
let inputs = $("label input[type=checkbox]");
|
||||
let selectedOption = "";
|
||||
inputs.each(function() {
|
||||
let input = $(this);
|
||||
|
||||
if(input.prop('checked')) {
|
||||
selectedOption = input.val();
|
||||
selectedOption = document.getElementById(selectedOption).innerText;
|
||||
}
|
||||
});
|
||||
|
||||
// Generate Ballot A and Ballot B to be displayed to the user
|
||||
// This fn starts the process
|
||||
var ballotA = generateBallot();
|
||||
|
@ -271,11 +328,12 @@ function generateBallots() {
|
|||
var ballotB = generateBallot();
|
||||
progressBar.setAttribute("style", "width: 100%;");
|
||||
|
||||
showFirstQRCode(ballotA, ballotB);
|
||||
showFirstQRCode(ballotA, ballotB, selectedOption);
|
||||
}, 150);
|
||||
}
|
||||
|
||||
function showFirstQRCode(ballotA, ballotB) {
|
||||
// Called in stage 1 of 3 in the voting process
|
||||
function showFirstQRCode(ballotA, ballotB, selectedOption) {
|
||||
var ballots = new Array(ballotA, ballotB);
|
||||
var ballotHashes = new Array(2);
|
||||
|
||||
|
@ -287,14 +345,19 @@ function showFirstQRCode(ballotA, ballotB) {
|
|||
var modalDialog = $('#modalDialog');
|
||||
var title = modalDialog.find('.modal-title');
|
||||
var body = modalDialog.find('.modal-body');
|
||||
var footer = modalDialog.find('.modal-footer');
|
||||
|
||||
body.empty();
|
||||
title.text('Please Scan this QR Code');
|
||||
title.text('Step 1 of 3: Link Your Vote');
|
||||
|
||||
let pleaseScanP = document.createElement('p');
|
||||
pleaseScanP.innerHTML = "Please scan the following QR code from your DEMOS 2 mobile application:";
|
||||
|
||||
let QRDiv = document.createElement('div');
|
||||
var QRCodeImg = document.createElement('img');
|
||||
QRCodeImg.setAttribute('class', 'QR-code');
|
||||
QRCodeImg.setAttribute('id', "qr-img");
|
||||
new QRCode(QRCodeImg, ballotHashes[0] + ';' + ballotHashes[1]);
|
||||
QRDiv.append(QRCodeImg);
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
|
@ -315,37 +378,31 @@ function showFirstQRCode(ballotA, ballotB) {
|
|||
|
||||
// -----------------------------------------------
|
||||
|
||||
body.append(QRCodeImg);
|
||||
body.append(pleaseScanP);
|
||||
body.append(QRDiv);
|
||||
body.append(hashGroupDiv);
|
||||
|
||||
var closeButton = $('close-button');
|
||||
closeButton.removeClass('btn-success');
|
||||
closeButton.addClass('btn-danger');
|
||||
closeButton.text("Close without submitting vote");
|
||||
// Prepare the appropriate dialog buttons
|
||||
updateDialogButtons(DIALOG_BTN_STATES.STEP_1);
|
||||
|
||||
var nextButton = document.createElement('button');
|
||||
nextButton.setAttribute('type', 'button');
|
||||
nextButton.setAttribute('id', 'next-button');
|
||||
nextButton.setAttribute('class', 'btn btn-default');
|
||||
nextButton.innerHTML = "Next";
|
||||
if(!dialogOpen) {
|
||||
modalDialog.modal('toggle');
|
||||
dialogOpen = true;
|
||||
}
|
||||
|
||||
footer.prepend(nextButton);
|
||||
|
||||
modalDialog.modal('show');
|
||||
|
||||
$('#next-button').click(function(e) {
|
||||
showBallotChoiceDialog(ballots);
|
||||
$('#nextDialogBtn').click(function(e) {
|
||||
showBallotChoiceDialog(ballots, ballotHashes, selectedOption, modalDialog);
|
||||
});
|
||||
}
|
||||
|
||||
function showBallotChoiceDialog(ballots) {
|
||||
// Called in stage 2 of 3 in the voting process
|
||||
function showBallotChoiceDialog(ballots, ballotHashes, selectedOption, dialog) {
|
||||
// Display the ballot choice dialog
|
||||
var modalDialog = $('#modalDialog');
|
||||
var title = modalDialog.find('.modal-title');
|
||||
var body = modalDialog.find('.modal-body');
|
||||
var title = dialog.find('.modal-title');
|
||||
var body = dialog.find('.modal-body');
|
||||
|
||||
body.empty();
|
||||
title.text('Please Select a Ballot');
|
||||
title.text('Step 2 of 3: Select a Ballot');
|
||||
|
||||
// Generate the body of the dialog which consists of a button for A and for B
|
||||
var choiceGroupDiv = document.createElement('div');
|
||||
|
@ -363,21 +420,104 @@ function showBallotChoiceDialog(ballots) {
|
|||
btnChoiceB.innerHTML = 'B';
|
||||
choiceGroupDiv.append(btnChoiceB);
|
||||
|
||||
body.append(choiceGroupDiv);
|
||||
// ----------------------------------------------
|
||||
|
||||
modalDialog.modal('show');
|
||||
var hashGroupDiv = document.createElement('div');
|
||||
var br = document.createElement('br');
|
||||
hashGroupDiv.append( br );
|
||||
|
||||
var hashA = document.createElement("span");
|
||||
hashA.innerHTML = "Hash A: " + ballotHashes[0];
|
||||
hashGroupDiv.append( hashA );
|
||||
|
||||
var br2 = document.createElement('br');
|
||||
hashGroupDiv.append( br2 );
|
||||
|
||||
var hashB = document.createElement("span");
|
||||
hashB.innerHTML = "Hash B: " + ballotHashes[1];
|
||||
hashGroupDiv.append( hashB );
|
||||
|
||||
// -----------------------------------------------
|
||||
|
||||
body.append(choiceGroupDiv);
|
||||
body.append(hashGroupDiv);
|
||||
|
||||
// Register callback functions for the selection of either A or B
|
||||
$('#choice-A').click(function(e) {
|
||||
sendBallotsToServer(ballots[0], ballots[1]);
|
||||
showSelectionConfirmationDialog("A", ballots[0], ballotHashes[0], ballots[1], selectedOption, dialog);
|
||||
});
|
||||
|
||||
$('#choice-B').click(function(e) {
|
||||
sendBallotsToServer(ballots[1], ballots[0]);
|
||||
showSelectionConfirmationDialog("B", ballots[1], ballotHashes[1], ballots[0], selectedOption, dialog);
|
||||
});
|
||||
|
||||
updateDialogButtons(DIALOG_BTN_STATES.STEP_2);
|
||||
|
||||
if(!dialogOpen) {
|
||||
modalDialog.modal('toggle');
|
||||
dialogOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
function sendBallotsToServer(selection, alt) {
|
||||
// Called in stage 3 of 3 in the voting process
|
||||
function showSelectionConfirmationDialog(selection, selectedBallot, selectedBallotHash,
|
||||
otherBallot, selectedOption, dialog) {
|
||||
let title = dialog.find('.modal-title');
|
||||
let body = dialog.find('.modal-body');
|
||||
body.empty();
|
||||
|
||||
title.text("Step 3 of 3: Confirm Ballot Selection");
|
||||
|
||||
// Ballot detail section
|
||||
let selectedInfoSecDiv = document.createElement('div');
|
||||
|
||||
let detailsP = document.createElement('p');
|
||||
detailsP.innerHTML = "Please check the following details are correct: ";
|
||||
selectedInfoSecDiv.append(detailsP);
|
||||
|
||||
let ul = document.createElement('ul');
|
||||
|
||||
let selectedOptionLi = document.createElement('li');
|
||||
selectedOptionLi.innerHTML = "Selected Option: " + selectedOption;
|
||||
|
||||
let ballotSelectionLi = document.createElement('li');
|
||||
ballotSelectionLi.innerHTML = "Selected Ballot: " + selection;
|
||||
|
||||
let ballotHashLi = document.createElement('li');
|
||||
ballotHashLi.innerHTML = "SHA256 Ballot Fingerprint: " + selectedBallotHash;
|
||||
|
||||
ul.append(selectedOptionLi);
|
||||
ul.append(ballotSelectionLi);
|
||||
ul.append(ballotHashLi);
|
||||
selectedInfoSecDiv.append(ul);
|
||||
|
||||
// Instruction section
|
||||
let instructionsP = document.createElement('p');
|
||||
instructionsP.innerHTML = "If you are happy with your selection you can click on the 'Submit' button below to store"
|
||||
+ " your vote. Otherwise you can select 'Start Over' to go through the voting process again.";
|
||||
selectedInfoSecDiv.append(instructionsP);
|
||||
|
||||
let additionalInstructionsP = document.createElement('p');
|
||||
additionalInstructionsP.innerHTML = "You can overwrite your vote later by re-visiting this page and voting again.";
|
||||
selectedInfoSecDiv.append(additionalInstructionsP);
|
||||
|
||||
body.append(selectedInfoSecDiv);
|
||||
|
||||
// Update the dialog buttons accordingly
|
||||
updateDialogButtons(DIALOG_BTN_STATES.STEP_3);
|
||||
|
||||
$('#submitDialogBtn').click(function() {
|
||||
// Dispatch the ballot to the server
|
||||
sendBallotsToServer(selection, selectedBallot, otherBallot);
|
||||
});
|
||||
|
||||
if(!dialogOpen) {
|
||||
modalDialog.modal('toggle');
|
||||
dialogOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
function sendBallotsToServer(selection, selectedBallot, otherBallot) {
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||
|
@ -416,14 +556,15 @@ function sendBallotsToServer(selection, alt) {
|
|||
var pollNum = $('#poll-num').text();
|
||||
var ballotID = encodeURIComponent(btoa(JSON.stringify({voterID: voterID, eventID: eventID, pollNum: pollNum})));
|
||||
|
||||
// TODO: Generate a SK rather than using a static one. UUID generated server side and then injected JS side?
|
||||
var SK = "temporary";
|
||||
var encAlt = sjcl.encrypt(SK, JSON.stringify(alt));
|
||||
selection = JSON.stringify(selection);
|
||||
var encAlt = sjcl.encrypt(SK, JSON.stringify(otherBallot));
|
||||
let selectedBallotAsStr = JSON.stringify(selectedBallot);
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url : window.location,
|
||||
data : { handle: ballotID, encBallot: encAlt, ballot: selection },
|
||||
data : { handle: ballotID, encBallot: encAlt, ballot: selectedBallotAsStr, selection: selection },
|
||||
success : function(){
|
||||
onAfterBallotSend(ballotID, SK);
|
||||
}
|
||||
|
@ -432,40 +573,64 @@ function sendBallotsToServer(selection, alt) {
|
|||
|
||||
// Called once the ballot has been sent to the back-end and dialog has closed
|
||||
function onAfterBallotSend(ballotID, SK) {
|
||||
let titleText = 'Vote Successfully Received';
|
||||
let bodyText = "Thank you for voting! Your secret key is '"+SK+"'. Make sure to scan this QR code with your phone before closing this window.";
|
||||
|
||||
if(POLL_NUM !== POLL_COUNT) {
|
||||
bodyText += " You can vote on the next poll by closing down this dialog and clicking 'Next Poll'.";
|
||||
}
|
||||
|
||||
// With one ballot selected, we can display a QR code of the ballot ID
|
||||
var modalDialog = $('#modalDialog');
|
||||
var title = modalDialog.find('.modal-title');
|
||||
var body = modalDialog.find('.modal-body');
|
||||
title.text(titleText);
|
||||
body.empty();
|
||||
|
||||
var p = document.createElement("p");
|
||||
p.innerHTML = bodyText;
|
||||
body.append(p);
|
||||
let titleText = 'Vote Successfully Received';
|
||||
title.text(titleText);
|
||||
|
||||
// Generate the body of the dialog which displays the unselected ballot QR code
|
||||
// Add the first section: Instructions on next steps
|
||||
let instructions1Txt = "Thank you for voting! Please note down the ballot identifier by scanning " +
|
||||
"this QR code using the DEMOS2 mobile application: ";
|
||||
|
||||
var instructions1P = document.createElement("p");
|
||||
instructions1P.innerHTML = instructions1Txt;
|
||||
body.append(instructions1P);
|
||||
|
||||
// Add the second section: QR code that contains the ballot identifier
|
||||
var QRCodeImg = document.createElement('img');
|
||||
QRCodeImg.setAttribute('class', 'QR-code');
|
||||
new QRCode(QRCodeImg, ballotID);
|
||||
|
||||
body.append(QRCodeImg);
|
||||
|
||||
var closeButton = $('#close-button');
|
||||
closeButton.removeClass('btn-danger');
|
||||
closeButton.addClass('btn-success');
|
||||
closeButton.text("Close");
|
||||
if(POLL_NUM == POLL_COUNT) {
|
||||
$('#next-button').hide();
|
||||
// Add the third section: instructions on Ballot ID and SK
|
||||
let instructions2Div = document.createElement('div');
|
||||
instructions2Div.setAttribute('class', 'containerMarginTop');
|
||||
|
||||
let instructions2Txt = "You will also be emailed the ballot identifier. However, you will need to note down the following " +
|
||||
"secret in order to later verify your ballot was recorded as cast: ";
|
||||
let instructions2P = document.createElement('p');
|
||||
instructions2P.innerHTML = instructions2Txt;
|
||||
instructions2Div.append(instructions2P);
|
||||
body.append(instructions2Div);
|
||||
|
||||
// Add the fourth section: SK plain text
|
||||
let SKContainerDiv = document.createElement('div');
|
||||
SKContainerDiv.setAttribute("class", "containerMarginTop");
|
||||
|
||||
let SKDiv = document.createElement('div');
|
||||
SKDiv.setAttribute("class", "skDIV");
|
||||
|
||||
let SKP = document.createElement('p');
|
||||
SKP.innerHTML = SK;
|
||||
SKDiv.append(SKP);
|
||||
|
||||
SKContainerDiv.append(SKDiv);
|
||||
body.append(SKContainerDiv);
|
||||
|
||||
// Conditional fifth section: Instructions on how to vote on the next poll for the event
|
||||
if(POLL_NUM !== POLL_COUNT) {
|
||||
let instructions3Txt = "You can vote on the next poll by closing down this dialog and clicking 'Next Poll'.";
|
||||
let instructions3P = document.createElement('p');
|
||||
instructions3P.innerHTML = instructions3Txt;
|
||||
body.append(instructions3P);
|
||||
}
|
||||
|
||||
modalDialog.modal('show');
|
||||
updateDialogButtons(DIALOG_BTN_STATES.VOTE_SUCCESS);
|
||||
}
|
||||
|
||||
$('#modalDialog').on('hide.bs.modal', function (e) {
|
||||
|
@ -474,7 +639,7 @@ $('#modalDialog').on('hide.bs.modal', function (e) {
|
|||
if(titleText.indexOf("Received") > -1) {
|
||||
// Update page to reflect the fact that a vote has taken place
|
||||
location.reload();
|
||||
} else {
|
||||
} else if (titleText.indexOf("Error") === -1) {
|
||||
// Reset poll voting to allow user to vote again
|
||||
progressBar.setAttribute("style", "width: 0%;");
|
||||
$('#gen-ballots-btn').toggleClass("hidden");
|
||||
|
|
Reference in a new issue