/*
pyRCV2: Preferential vote counting
Copyright © 2020–2021 Lee Yingtong Li (RunasSudo)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
let candidates = [];
let ballots = [];
let inpFile = document.getElementById('inpFile');
let txtBallotValue = document.getElementById('txtBallotValue');
let tblBallot = document.getElementById('tblBallot');
let selBallots = document.getElementById('selBallots');
selBallots.value = 'new';
function initBallot() {
// Init ballot table
tblBallot.innerHTML = '';
for (let candidate of candidates) {
let elTr = document.createElement('tr');
let elTd = document.createElement('td');
let elInput = document.createElement('input');
elInput.type = 'number';
elInput.min = '1';
elInput.style.width = '3em';
elTd.appendChild(elInput);
elTr.appendChild(elTd);
// Add listener
elInput.addEventListener('keyup', function(evt) {
if (evt.key === 'Enter') {
evt.preventDefault();
clickSave();
}
});
elTd = document.createElement('td');
elTd.innerText = candidate;
elTr.appendChild(elTd);
tblBallot.appendChild(elTr);
}
}
function clickSave() {
// Save ballot
let ballot = {'value': txtBallotValue.value, 'preferences': []};
for (let elInput of tblBallot.querySelectorAll('input')) {
ballot['preferences'].push(elInput.value);
}
if (selBallots.value === 'new') {
// New ballot
ballots.push(ballot);
// Add new ballot ';
selBallots.value = 'new';
for (let i = 0; i < ballots.length; i++) {
let elOption = document.createElement('option');
elOption.innerText = 'Ballot ' + (i + 1);
selBallots.insertBefore(elOption, selBallots.selectedOptions[0]);
}
inpFile.value = '';
}
}
function clickSaveJSON() {
let result = {
'candidates': candidates,
'ballots': ballots,
};
// Download file
let url = URL.createObjectURL(new File([JSON.stringify(result)], 'ballots.json', {type: 'application/json'}));
let elA = document.createElement('a');
elA.href = url;
elA.download = '';
elA.click();
}
function clickExportBLT() {
let election = py.pyRCV2.model.Election();
let result = window.prompt('Enter the number of seats to elect:', '1');
if (result !== null) {
election.seats = parseInt(result);
} else {
return;
}
result = window.prompt('Enter the name of the election:');
if (result !== null) {
election.py_name = result;
} else {
return;
}
for (let candidate of candidates) {
let py_candidate = py.pyRCV2.model.Candidate(candidate);
election.candidates.push(py_candidate);
}
// Process ballots
for (let ballot of ballots) {
let py_ballot = py.pyRCV2.model.Ballot(py.pyRCV2.numbers.StringNum(ballot['value']), []);
for (let i = 1; i < candidates.length + 1; i++) {
let candidate = null;
for (let j = 0; j < candidates.length; j++) {
if (ballot.preferences[j].trim() === '' + i) {
candidate = j;
break;
}
}
if (candidate !== null) {
py_ballot.preferences.push(election.candidates[candidate]);
} else {
// No such preference
break;
}
}
election.ballots.push(py_ballot);
}
// Download file
let url = URL.createObjectURL(new File([py.pyRCV2.blt.writeBLT(election)], 'election.blt', {type: 'application/json'}));
let elA = document.createElement('a');
elA.href = url;
elA.download = '';
elA.click();
}
function clickEditCandidates() {
document.getElementById('bltMain').style.display = 'none';
document.getElementById('divEditCandidates').style.display = '';
document.getElementById('txtCandidates').value = candidates.join('\n');
}
function clickSaveCandidates() {
candidates = [];
for (let candidate of document.getElementById('txtCandidates').value.split('\n')) {
if (candidate.trim() !== '') {
candidates.push(candidate.trim());
}
}
// Update ballot entry
initBallot();
changeBallot();
document.getElementById('bltMain').style.display = '';
document.getElementById('divEditCandidates').style.display = 'none';
}