This repository has been archived on 2021-05-25. You can view files and clone it, but cannot push or open issues or pull requests.
pyRCV2/html/blt/index.js

179 lines
4.7 KiB
JavaScript
Raw Normal View History

2021-01-25 19:47:18 +11:00
/*
pyRCV2: Preferential vote counting
Copyright © 20202021 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 <https://www.gnu.org/licenses/>.
*/
let candidates = ['Candidate 1', 'Candidate 2', 'Candidate 3'];
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 <option>
let elOption = document.createElement('option');
elOption.innerText = 'Ballot ' + ballots.length;
selBallots.insertBefore(elOption, selBallots.selectedOptions[0]);
} else if (selBallots.selectedIndex >= 0) {
// Editing existing ballot
ballots[selBallots.selectedIndex] = ballot;
// Advance to next ballot
selBallots.selectedIndex += 1;
}
// Update ballot entry
changeBallot();
}
function changeBallot() {
if (selBallots.value === 'new') {
// Clear input
for (let elInput of tblBallot.querySelectorAll('input')) {
elInput.value = '';
}
txtBallotValue.value = '1';
} else if (selBallots.selectedIndex >= 0) {
// Update input
let ballot = ballots[selBallots.selectedIndex];
let i = 0;
for (let elInput of tblBallot.querySelectorAll('input')) {
elInput.value = ballot['preferences'][i];
i += 1;
}
txtBallotValue.value = ballot['value'];
}
// Move cursor to first input box
tblBallot.querySelector('input').focus();
tblBallot.querySelector('input').select();
}
function clickOpenJSON() {
inpFile.value = '';
inpFile.click();
}
async function changeInpFile() {
if (inpFile.value !== '') {
// Open JSON file
let text = await inpFile.files[0].text();
let obj = JSON.parse(text);
// Load data
candidates = obj['candidates'];
ballots = obj['ballots'];
// Update ballot entry
initBallot();
// Update ballot list
selBallots.innerHTML = '<option value="new" selected>-- New Ballot --</option>';
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,
};
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 clickEditCandidates() {
document.getElementById('bltMain').style.display = 'none';
document.getElementById('divEditCandidates').style.display = 'block';
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();
document.getElementById('bltMain').style.display = 'flex';
document.getElementById('divEditCandidates').style.display = 'none';
}
// Init tasks
initBallot();
changeBallot();