Initial quick port of HTML interface
This commit is contained in:
parent
e88d2674d6
commit
227c38a5fa
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
/pkg/opentally.js
|
/html/opentally.js
|
||||||
/pkg/opentally_bg.wasm
|
/html/opentally_bg.wasm
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
cargo build --lib --target wasm32-unknown-unknown && /home/runassudo/.cargo/bin/wasm-bindgen --target no-modules target/wasm32-unknown-unknown/debug/opentally.wasm --out-dir pkg --no-typescript
|
cargo build --lib --target wasm32-unknown-unknown && /home/runassudo/.cargo/bin/wasm-bindgen --target no-modules target/wasm32-unknown-unknown/debug/opentally.wasm --out-dir html --no-typescript
|
||||||
|
250
html/index.html
Normal file
250
html/index.html
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
<!--
|
||||||
|
* OpenTally: Open-source election vote counting
|
||||||
|
* Copyright © 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 <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>OpenTally</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" integrity="sha512-NhSC1YmyruXifcj/KFRWoC561YpHpc5Jtzgvbuzx5VozKpWvQ+4nXhPdFgmx8xqexRcpAglTj9sIBWINXa8x5w==" crossorigin="anonymous" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="main.css?v=GITVERSION">
|
||||||
|
</head>
|
||||||
|
<body class="interactive">
|
||||||
|
<div class="menudiv">
|
||||||
|
<input type="file" id="bltFile">
|
||||||
|
<button onclick="clickCount()">Count</button>
|
||||||
|
<!--<label>
|
||||||
|
Preset:
|
||||||
|
<select id="selPreset" onchange="changePreset()">
|
||||||
|
<option value="scottish" selected>Scottish STV</option>
|
||||||
|
<option value="senate">Australian Senate STV</option>
|
||||||
|
<option value="meek">Meek STV</option>
|
||||||
|
<option value="wright">Wright STV</option>
|
||||||
|
<option value="prsa77">PRSA 1977</option>
|
||||||
|
<option value="ers97">ERS97</option>
|
||||||
|
</select>
|
||||||
|
</label>-->
|
||||||
|
<button id="btnAdvancedOptions" onclick="clickAdvancedOptions()">Show advanced options</button>
|
||||||
|
<!--GITREV-->
|
||||||
|
<!--<a href="https://yingtongli.me/blog/2020/12/24/pyrcv2.html">Information and instructions</a> ·
|
||||||
|
<a href="blt/">Ballot input/editor</a>-->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="divAdvancedOptions" class="menudiv cols-12 cols-sm-6" style="display: none;">
|
||||||
|
<div class="col-6" style="align-self: start;">
|
||||||
|
<div class="subheading">
|
||||||
|
Method specification:
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Quota:
|
||||||
|
<select id="selQuotaCriterion">
|
||||||
|
<option value="geq" selected>>=</option>
|
||||||
|
<option value="gt">></option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<select id="selQuota">
|
||||||
|
<option value="droop" selected>Droop</option>
|
||||||
|
<option value="droop_exact">Droop (exact)</option>
|
||||||
|
<option value="hare">Hare</option>
|
||||||
|
<option value="hare_exact">Hare (exact)</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<!--<label>
|
||||||
|
<select id="selQuotaMode">
|
||||||
|
<option value="static" selected>Static quota</option>
|
||||||
|
<option value="progressive">Progressive quota</option>
|
||||||
|
<option value="ers97">Static with ERS97 rules</option>
|
||||||
|
</select>
|
||||||
|
</label>-->
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Surplus order:
|
||||||
|
<select id="selSurplus">
|
||||||
|
<option value="by_size" selected>By size</option>
|
||||||
|
<option value="by_order">By order</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Method:
|
||||||
|
<select id="selTransfers">
|
||||||
|
<option value="wig" selected>Weighted inclusive Gregory</option>
|
||||||
|
<option value="uig">Unweighted inclusive Gregory</option>
|
||||||
|
<option value="eg">Exclusive Gregory (last bundle)</option>
|
||||||
|
<option value="meek">Meek method</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<select id="selPapers">
|
||||||
|
<option value="both" selected>Include non-transferable papers</option>
|
||||||
|
<option value="transferable">Use transferable papers only</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Exclusion:
|
||||||
|
<select id="selExclusion">
|
||||||
|
<option value="single_stage" selected>Exclude in single stage</option>
|
||||||
|
<option value="by_value">Exclude by value</option>
|
||||||
|
<option value="parcels_by_order">Exclude by parcel (by order)</option>
|
||||||
|
<!--<option value="wright">Wright method (re-iterate)</option>-->
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!--<div class="subheading">
|
||||||
|
Tie-breaking:
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Ties:
|
||||||
|
<select id="selTies">
|
||||||
|
<option value="backwards_random" selected>Backwards then random</option>
|
||||||
|
<option value="forwards_random">Forwards then random</option>
|
||||||
|
<option value="random">Random</option>
|
||||||
|
<option value="prompt">Prompt</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Random seed:
|
||||||
|
<input type="text" id="txtSeed" value="">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="subheading">
|
||||||
|
Constraints:
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="file" id="conFile">
|
||||||
|
</div>-->
|
||||||
|
</div>
|
||||||
|
<div class="col-6 cols-12" style="align-self: start;">
|
||||||
|
<div class="col-12 subheading">
|
||||||
|
Numeric representation:
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<!--<label>
|
||||||
|
Numbers:
|
||||||
|
<select id="selNumbers">
|
||||||
|
<option value="native">Native</option>
|
||||||
|
<option value="rational">Rational</option>
|
||||||
|
<option value="fixed" selected>Fixed</option>
|
||||||
|
<option value="gfixed">Fixed (guarded)</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Decimal places (if Numbers = Fixed):
|
||||||
|
<input type="number" id="txtDP" value="5" min="0" style="width: 3em;">
|
||||||
|
</label>-->
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<label>
|
||||||
|
Display up to
|
||||||
|
<input type="number" id="txtPPDP" value="2" min="0" style="width: 3em;">
|
||||||
|
d.p.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!--<div class="col-12 subheading">
|
||||||
|
Count optimisations:
|
||||||
|
</div>
|
||||||
|
<label class="col-6">
|
||||||
|
<input type="checkbox" id="chkBulkElection" checked>
|
||||||
|
Bulk election
|
||||||
|
</label>
|
||||||
|
<label class="col-6">
|
||||||
|
<input type="checkbox" id="chkBulkExclusion">
|
||||||
|
Bulk exclusion
|
||||||
|
</label>
|
||||||
|
<label class="col-12">
|
||||||
|
<input type="checkbox" id="chkDeferSurpluses">
|
||||||
|
Defer surpluses
|
||||||
|
</label>-->
|
||||||
|
<div class="col-12 subheading">
|
||||||
|
Rounding:
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="chkRoundQuota" checked>
|
||||||
|
Quota:
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="number" id="txtRoundQuota" value="0" min="0" style="width: 3em;">
|
||||||
|
d.p.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="chkRoundVotes">
|
||||||
|
Votes:
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="number" id="txtRoundVotes" value="0" min="0" style="width: 3em;">
|
||||||
|
d.p.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="chkRoundTVs">
|
||||||
|
Transfer values:
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="number" id="txtRoundTVs" value="0" min="0" style="width: 3em;">
|
||||||
|
d.p.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="chkRoundWeights">
|
||||||
|
Ballot weights:
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="number" id="txtRoundWeights" value="0" min="0" style="width: 3em;">
|
||||||
|
d.p.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="resultLogs1" style="white-space: pre-wrap;"></div>
|
||||||
|
|
||||||
|
<table id="result" class="result"></table>
|
||||||
|
|
||||||
|
<div id="resultLogs2"></div>
|
||||||
|
|
||||||
|
<div id="printPane" style="display: none;">
|
||||||
|
<button onclick="printResult()">Print result</button>
|
||||||
|
<label>
|
||||||
|
Paper size:
|
||||||
|
<select id="selPaperSize">
|
||||||
|
<option value="A4" selected>A4</option>
|
||||||
|
<option value="A3">A3</option>
|
||||||
|
<option value="letter">US Letter</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="printWarning">Printing directly from this page is not supported. Use the ‘Print result’ button to generate a printer-friendly report.</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var openTallyVersion = 'GITVERSION';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script src="opentally.js?v=GITVERSION"></script>
|
||||||
|
<script src="index.js?v=GITVERSION"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
77
html/index.js
Normal file
77
html/index.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* OpenTally: Open-source election vote counting
|
||||||
|
* Copyright © 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function clickAdvancedOptions() {
|
||||||
|
if (document.getElementById('divAdvancedOptions').style.display === 'none') {
|
||||||
|
document.getElementById('divAdvancedOptions').style.display = 'grid';
|
||||||
|
document.getElementById('btnAdvancedOptions').innerHTML = 'Hide advanced options';
|
||||||
|
} else {
|
||||||
|
document.getElementById('divAdvancedOptions').style.display = 'none';
|
||||||
|
document.getElementById('btnAdvancedOptions').innerHTML = 'Show advanced options';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log = function(v) {
|
||||||
|
document.getElementById('resultLogs1').append(v);
|
||||||
|
document.getElementById('resultLogs1').append("\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
var wasm = wasm_bindgen;
|
||||||
|
|
||||||
|
async function clickCount() {
|
||||||
|
if (document.getElementById('bltFile').files.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read BLT file
|
||||||
|
let bltFile = document.getElementById('bltFile').files[0];
|
||||||
|
let electionData = await bltFile.text();
|
||||||
|
|
||||||
|
// Load WASM
|
||||||
|
await wasm_bindgen('opentally_bg.wasm');
|
||||||
|
|
||||||
|
// Init election
|
||||||
|
let election = wasm.election_from_blt_Rational(electionData);
|
||||||
|
let state = wasm.CountStateRational.new(election);
|
||||||
|
|
||||||
|
// Init STV options
|
||||||
|
let stv_opts = wasm.STVOptions.new(
|
||||||
|
document.getElementById('chkRoundTVs').checked ? parseInt(document.getElementById('txtRoundTVs').value) : null,
|
||||||
|
document.getElementById('chkRoundWeights').checked ? parseInt(document.getElementById('txtRoundWeights').value) : null,
|
||||||
|
document.getElementById('chkRoundVotes').checked ? parseInt(document.getElementById('txtRoundVotes').value) : null,
|
||||||
|
document.getElementById('chkRoundQuota').checked ? parseInt(document.getElementById('txtRoundQuota').value) : null,
|
||||||
|
document.getElementById('selQuota').value,
|
||||||
|
document.getElementById('selQuotaCriterion').value,
|
||||||
|
document.getElementById('selTransfers').value,
|
||||||
|
document.getElementById('selSurplus').value,
|
||||||
|
document.getElementById('selPapers').value == 'transferable',
|
||||||
|
document.getElementById('selExclusion').value,
|
||||||
|
parseInt(document.getElementById('txtPPDP').value),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step election
|
||||||
|
wasm.count_init_Rational(state, stv_opts);
|
||||||
|
wasm.make_and_print_result_Rational(1, state);
|
||||||
|
|
||||||
|
for (let stage_num = 2;; stage_num++) {
|
||||||
|
let is_done = wasm.count_one_stage_Rational(state, stv_opts);
|
||||||
|
if (is_done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wasm.make_and_print_result_Rational(stage_num, state);
|
||||||
|
}
|
||||||
|
}
|
257
html/main.css
Normal file
257
html/main.css
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap');
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
font-family: 'Source Sans Pro', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #1d46c4;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #1d3da2;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu styling */
|
||||||
|
|
||||||
|
.menudiv {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
line-height: 1.8;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menudiv .subheading {
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cols-12 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(12, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-3 { grid-column-end: span 3; }
|
||||||
|
.col-6 { grid-column-end: span 6; }
|
||||||
|
.col-12 { grid-column-end: span 12; }
|
||||||
|
|
||||||
|
@media screen and (max-width: 17.5cm) {
|
||||||
|
.cols-sm-6 {
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count table */
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.result td {
|
||||||
|
padding: 0px 8px;
|
||||||
|
min-height: 1em;
|
||||||
|
}
|
||||||
|
td.count {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
td.count sup {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
tr.stage-no td, tr.stage-kind td, tr.stage-comment td {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
tr.stage-no td:not(:first-child) {
|
||||||
|
border-top: 1px solid #76858c;
|
||||||
|
}
|
||||||
|
tr.stage-kind td:not(:first-child) {
|
||||||
|
font-size: 0.75em;
|
||||||
|
min-width: 5rem;
|
||||||
|
color: #1b2839;
|
||||||
|
background-color: #f0f5fb;
|
||||||
|
color-adjust: exact;
|
||||||
|
-webkit-print-color-adjust: exact;
|
||||||
|
}
|
||||||
|
td.excluded {
|
||||||
|
background-color: #fde2e2;
|
||||||
|
color-adjust: exact;
|
||||||
|
-webkit-print-color-adjust: exact;
|
||||||
|
}
|
||||||
|
td.elected {
|
||||||
|
background-color: #e0fdc5;
|
||||||
|
color-adjust: exact;
|
||||||
|
-webkit-print-color-adjust: exact;
|
||||||
|
}
|
||||||
|
tr.info td {
|
||||||
|
background-color: #f0f5fb;
|
||||||
|
color-adjust: exact;
|
||||||
|
-webkit-print-color-adjust: exact;
|
||||||
|
}
|
||||||
|
td.bt {
|
||||||
|
border-top: 1px solid #76858c;
|
||||||
|
}
|
||||||
|
td.bb {
|
||||||
|
border-bottom: 1px solid #76858c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BLT input tool */
|
||||||
|
|
||||||
|
#selBallots {
|
||||||
|
min-width: 10em;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bltMain {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tblBallot {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tblBallot input {
|
||||||
|
margin-right: 0.5ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#divEditCandidates div {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#txtCandidates {
|
||||||
|
min-width: 20em;
|
||||||
|
min-height: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print stylesheet */
|
||||||
|
|
||||||
|
#printWarning {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#printContainer > div:first-child > p:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
body.interactive > * {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#divAdvancedOptions, #printPane {
|
||||||
|
/* Override inline style */
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
#printWarning {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form styling */
|
||||||
|
/* Adapted in part from https://github.com/nathansmith/formalize (GPL/MIT) */
|
||||||
|
|
||||||
|
select, input, button {
|
||||||
|
line-height: 1.15;
|
||||||
|
}
|
||||||
|
|
||||||
|
select, input[type="text"], input[type="number"], textarea {
|
||||||
|
appearance: none;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #999 #bbb #ddd;
|
||||||
|
border-radius: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #000;
|
||||||
|
padding: 2px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
/* Dropdown arrow */
|
||||||
|
background-image: url(data:image/png;base64,R0lGODlhDQAEAIAAAAAAAP8A/yH5BAEHAAEALAAAAAANAAQAAAILhA+hG5jMDpxvhgIAOw==);
|
||||||
|
background-position: right center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
padding-right: 20px; /* Padding for dropdown arrow */
|
||||||
|
}
|
||||||
|
|
||||||
|
button, input[type="file"]::-webkit-file-upload-button {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #ddd #bbb #999;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #000;
|
||||||
|
font-family: inherit;
|
||||||
|
padding: 2px 10px;
|
||||||
|
}
|
||||||
|
button:hover, input[type="file"]::-webkit-file-upload-button:hover {
|
||||||
|
background-color: #eaeaea;
|
||||||
|
}
|
||||||
|
button:active, input[type="file"]::-webkit-file-upload-button:active {
|
||||||
|
background-color: #dfdfdf;
|
||||||
|
border-color: #999 #bbb #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chrome can't parse this and ignores the entire rule */
|
||||||
|
input[type="file"]::file-selector-button {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #ddd #bbb #999;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #000;
|
||||||
|
font-family: inherit;
|
||||||
|
padding: 2px 10px;
|
||||||
|
}
|
||||||
|
button:hover, input[type="file"]::file-selector-button:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
button:active, input[type="file"]::file-selector-button:active {
|
||||||
|
background-color: #eaeaea;
|
||||||
|
border-color: #999 #bbb #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
appearance: none;
|
||||||
|
position: relative;
|
||||||
|
width: 0.9em;
|
||||||
|
height: 0.9em;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #999 #bbb #ddd;
|
||||||
|
vertical-align: -2px;
|
||||||
|
}
|
||||||
|
input[type="checkbox"]:checked {
|
||||||
|
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw1AUhU9Ti0VaHMwg4pChOlkQFXHUKhShQqgVWnUweekfNGlJUlwcBdeCgz+LVQcXZ10dXAVB8AfEzc1J0UVKvC8ptIjxwuN9nHfP4b37AKFZYbrVMw7ohm2mkwkpm1uVel8RQAhhRCEqzKrNyXIKvvV1T91Ud3Ge5d/3Z0W1vMWAgEQ8y2qmTbxBPL1p1zjvE4uspGjE58RjJl2Q+JHrqsdvnIsuCzxTNDPpeWKRWCp2sdrFrGTqxFPEMU03KF/Ieqxx3uKsV+qsfU/+wkjeWFnmOq1hJLGIJciQoKKOMiqwEafdIMVCms4TPv4h1y+TSyVXGYwcC6hCh+L6wf/g92ytwuSElxRJAKEXx/kYAXp3gVbDcb6PHad1AgSfgSuj4682gZlP0hsdLXYE9G8DF9cdTd0DLneAwaeaYiquFKQlFArA+xl9Uw4YuAX61ry5tc9x+gBkaFapG+DgEBgtUva6z7vD3XP7t6c9vx/h6nJtOtJaHwAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB+UBBQgnA808S3QAAABpSURBVDjLxZNLEsAgCEPRO3pKuOPrrkXRDtZFs/PzkjGMBUAOVOVQnwzM7FmwKVVFRFBVAOpucmut39xN9ukAcgJ3BuNBBr4NxmKycDDwFzNweIIHMnAo0YMZeDqFVR9pg7eJzFR+/40Xt0cwTrDq4YsAAAAASUVORK5C);
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus, select:focus, input:focus, textarea:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
select:focus, input:focus, textarea:focus {
|
||||||
|
border-color: #3daee9;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
@ -1,49 +0,0 @@
|
|||||||
<html>
|
|
||||||
<body>
|
|
||||||
<div id="output" style="white-space: pre-wrap;"></div>
|
|
||||||
|
|
||||||
<script src="opentally.js"></script>
|
|
||||||
<script>
|
|
||||||
var election_data = '4 2\n\
|
|
||||||
3 1 3 4 0\n\
|
|
||||||
4 1 3 2 0\n\
|
|
||||||
2 4 1 3 0\n\
|
|
||||||
1 2 0\n\
|
|
||||||
2 2 4 3 1 0\n\
|
|
||||||
1 3 4 2 0\n\
|
|
||||||
0\n\
|
|
||||||
"Adam"\n\
|
|
||||||
"Basil"\n\
|
|
||||||
"Charlotte"\n\
|
|
||||||
"Donald"\n\
|
|
||||||
"Title"';
|
|
||||||
|
|
||||||
console.log = function(v) {
|
|
||||||
document.getElementById('output').append(v);
|
|
||||||
document.getElementById('output').append("\n");
|
|
||||||
};
|
|
||||||
|
|
||||||
var wasm = wasm_bindgen;
|
|
||||||
async function run() {
|
|
||||||
await wasm_bindgen("opentally_bg.wasm");
|
|
||||||
|
|
||||||
let stv_opts = wasm.STVOptions.new(null, "wig", "by_size", false, "single_stage", 2);
|
|
||||||
|
|
||||||
let election = wasm.election_from_blt_Rational(election_data);
|
|
||||||
let state = wasm.CountStateRational.new(election);
|
|
||||||
|
|
||||||
wasm.count_init_Rational(state, stv_opts);
|
|
||||||
wasm.make_and_print_result_Rational(1, state);
|
|
||||||
|
|
||||||
for (let stage_num = 2;; stage_num++) {
|
|
||||||
let is_done = wasm.count_one_stage_Rational(state, stv_opts);
|
|
||||||
if (is_done) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
wasm.make_and_print_result_Rational(stage_num, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -247,9 +247,7 @@ impl ops::SubAssign<&Rational> for Rational {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ops::MulAssign<&Rational> for Rational {
|
impl ops::MulAssign<&Rational> for Rational {
|
||||||
fn mul_assign(&mut self, _rhs: &Rational) {
|
fn mul_assign(&mut self, rhs: &Rational) { self.0 *= &rhs.0 }
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::DivAssign<&Rational> for Rational {
|
impl ops::DivAssign<&Rational> for Rational {
|
||||||
|
@ -154,22 +154,3 @@ fn print_stage<N: Number>(stage_num: usize, result: &StageResult<N>) {
|
|||||||
|
|
||||||
cprintln!("");
|
cprintln!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct STVOptions(stv::STVOptions);
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl STVOptions {
|
|
||||||
pub fn new(round_votes: Option<usize>, exclusion: String) -> Self {
|
|
||||||
if exclusion == "one_round" {
|
|
||||||
return STVOptions(stv::STVOptions {
|
|
||||||
round_votes: round_votes,
|
|
||||||
exclusion: &"one_round",
|
|
||||||
pp_decimals: 2,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
panic!("Unknown --exclusion");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
Loading…
Reference in New Issue
Block a user