-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
130 lines (107 loc) · 3.71 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
"use strict";
const sortPromise = import('./sort.js').then(module => module.default);
const condorcetPromise = import('./condorcet.js');
let winnerElement = document.querySelector('#winner');
let button = document.querySelector('#winnerButton');
let ballotButton = document.querySelector('#ballotButton');
let form = document.querySelector('form');
let candidatesInput = document.querySelector('#candidates');
let candidateList = document.querySelector('#candidateList');
let candidates = [];
let ballotsInput = document.querySelector('#ballots');
let ballotList = document.querySelector('#ballotList');
let selector = document.querySelector('.preference-selector');
let options = selector.querySelectorAll('.preferences > span');
function fixSize(textarea) {
while (textarea.offsetHeight <= textarea.scrollHeight)
textarea.rows += 4;
while (textarea.offsetWidth <= textarea.scrollWidth)
textarea.cols += 10;
}
for (let textarea of document.querySelectorAll('textarea'))
textarea.addEventListener('input', () => fixSize(textarea));
form.onsubmit = async function(event) {
event.preventDefault();
button.disabled = true;
winnerElement.textContent = "Calculating...";
const {notationToBallots, areValid, condorcetIrvWinner, condorcetMatrix} = await condorcetPromise;
try {
let ballots = notationToBallots(ballotsInput.value);
if (areValid(ballots))
winnerElement.textContent = candidates[await condorcetIrvWinner(condorcetMatrix(ballots), ballots, candidates.join())];
else
winnerElement.textContent = "Error, invalid ballots format";
}
catch(e) {
winnerElement.textContent = "Error, invalid ballots format";
}
}
function resetWinner() {
winnerElement.textContent = '';
button.disabled = false;
}
function toItem(string) {
let li = document.createElement("li");
li.textContent = string;
return li;
}
function updateCandidateList() {
candidateList.innerHTML = '';
candidates = candidatesInput.value.trim();
candidates = candidates && candidates.split(/\s+^\s*/m) || [];
candidateList.append(...candidates.map(toItem));
}
function updateBallotList() {
ballotList.innerHTML = '';
if (ballotsInput.value) {
ballotList.append(
...ballotsInput.value.trim().replace(/g/g, '>').replace(/e/g, '=')
.replace(/[0-9]+/g, candidate => candidates[Number(candidate) - 1])
.split(/\s+^\s*/m).map(toItem)
);
}
}
form.addEventListener('input', resetWinner);
form.addEventListener('input', updateBallotList);
candidatesInput.addEventListener('input', updateCandidateList);
updateCandidateList();
updateBallotList();
button.disabled = false;
function askPreference(i1, i2) {
return new Promise(resolve => {
function answer(myAnswer) {
selector.classList.remove('enabled');
resolve(myAnswer);
}
options[0].textContent = candidates[i1-1];
options[2].textContent = candidates[i2-1];
options[0].onclick = () => answer(-1);
options[1].onclick = () => answer(0);
options[2].onclick = () => answer(1);
selector.classList.add('enabled');
})
}
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.trunc(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
ballotButton.onclick = async function() {
if (!candidatesInput.reportValidity())
return false;
if (candidates.length < 2)
return alert("Add more candidates");
ballotButton.disabled = true;
const sort = await sortPromise;
let result = await sort(shuffle(Array.from({length: candidates.length}, (x, i) => i + 1)), askPreference);
ballotButton.disabled = false;
let lastChar = ballotsInput.value.slice(-1);
if (lastChar && lastChar != '\n')
ballotsInput.value += '\n';
ballotsInput.value += result.join(' ');
resetWinner();
updateBallotList();
}
ballotButton.disabled = false;