Implement detailed transfers in web UI
This commit is contained in:
parent
9817d6c199
commit
df1b2f7bdc
|
@ -517,6 +517,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "html-escape"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "816ea801a95538fc5f53c836697b3f8b64a9d664c4f0b91efe1fe7c92e4dbcb7"
|
||||||
|
dependencies = [
|
||||||
|
"utf8-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ibig"
|
name = "ibig"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -637,9 +646,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.0"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512"
|
checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
|
@ -710,6 +719,7 @@ dependencies = [
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"flate2",
|
"flate2",
|
||||||
"git-version",
|
"git-version",
|
||||||
|
"html-escape",
|
||||||
"ibig",
|
"ibig",
|
||||||
"itertools",
|
"itertools",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
@ -1124,6 +1134,12 @@ dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8-width"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7cf7d77f457ef8dfa11e4cd5933c5ddb5dc52a94664071951219a97710f0a32b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
|
|
|
@ -14,15 +14,16 @@ git-version = "0.3.4"
|
||||||
ibig = "0.3.2"
|
ibig = "0.3.2"
|
||||||
itertools = "0.10.1"
|
itertools = "0.10.1"
|
||||||
ndarray = "0.15.3"
|
ndarray = "0.15.3"
|
||||||
predicates = "1.0.8"
|
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
|
predicates = "1.0.8"
|
||||||
sha2 = "0.9.5"
|
sha2 = "0.9.5"
|
||||||
wasm-bindgen = "0.2.74"
|
wasm-bindgen = "=0.2.74" # 0.2.77 causes "remaining data" error
|
||||||
|
|
||||||
# Only for WebAssembly - include here for syntax highlighting
|
# Only for WebAssembly - include here for syntax highlighting
|
||||||
#[target.'cfg(target_arch = "wasm32")'.dependencies]
|
#[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
console_error_panic_hook = "0.1.6"
|
console_error_panic_hook = "0.1.6"
|
||||||
js-sys = "0.3.51"
|
js-sys = "0.3.51"
|
||||||
|
html-escape = "0.2.9"
|
||||||
num-bigint = "0.4.0"
|
num-bigint = "0.4.0"
|
||||||
num-rational = "0.4.0"
|
num-rational = "0.4.0"
|
||||||
paste = "1.0.5"
|
paste = "1.0.5"
|
||||||
|
|
|
@ -29,6 +29,8 @@ var tblResult = document.getElementById('result');
|
||||||
var divLogs2 = document.getElementById('resultLogs2');
|
var divLogs2 = document.getElementById('resultLogs2');
|
||||||
var olStageComments;
|
var olStageComments;
|
||||||
|
|
||||||
|
var detailedTransfers = {};
|
||||||
|
|
||||||
var worker = new Worker('worker.js?v=GITVERSION');
|
var worker = new Worker('worker.js?v=GITVERSION');
|
||||||
|
|
||||||
worker.onmessage = function(evt) {
|
worker.onmessage = function(evt) {
|
||||||
|
@ -78,10 +80,13 @@ worker.onmessage = function(evt) {
|
||||||
|
|
||||||
} else if (evt.data.type === 'updateStageComments') {
|
} else if (evt.data.type === 'updateStageComments') {
|
||||||
let elLi = document.createElement('li');
|
let elLi = document.createElement('li');
|
||||||
elLi.id = 'stage' + (olStageComments.childElementCount + 1);
|
elLi.id = 'stage' + evt.data.stageNum;
|
||||||
elLi.innerHTML = evt.data.comment;
|
elLi.innerHTML = evt.data.comment;
|
||||||
olStageComments.append(elLi);
|
olStageComments.append(elLi);
|
||||||
|
|
||||||
|
} else if (evt.data.type === 'updateDetailedTransfers') {
|
||||||
|
detailedTransfers[evt.data.stageNum] = evt.data.table;
|
||||||
|
|
||||||
} else if (evt.data.type === 'finalResultSummary') {
|
} else if (evt.data.type === 'finalResultSummary') {
|
||||||
divLogs2.insertAdjacentHTML('beforeend', evt.data.summary);
|
divLogs2.insertAdjacentHTML('beforeend', evt.data.summary);
|
||||||
document.getElementById('printPane').style.display = 'block';
|
document.getElementById('printPane').style.display = 'block';
|
||||||
|
@ -170,6 +175,8 @@ async function clickCount() {
|
||||||
tblResult.innerHTML = '';
|
tblResult.innerHTML = '';
|
||||||
divLogs2.innerHTML = '';
|
divLogs2.innerHTML = '';
|
||||||
|
|
||||||
|
detailedTransfers = {};
|
||||||
|
|
||||||
// Dispatch to worker
|
// Dispatch to worker
|
||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
'type': 'countElection',
|
'type': 'countElection',
|
||||||
|
@ -187,6 +194,26 @@ async function clickCount() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function viewDetailedTransfers(stageNum) {
|
||||||
|
let wtransfers = window.open('', '', 'location=0,width=800,height=600');
|
||||||
|
wtransfers.document.title = 'OpenTally Detailed Transfers: Stage ' + stageNum;
|
||||||
|
|
||||||
|
// Add stylesheets
|
||||||
|
for (let elCSSBase of document.querySelectorAll('head link')) {
|
||||||
|
let elCSS = wtransfers.document.createElement('link');
|
||||||
|
elCSS.rel = elCSSBase.rel;
|
||||||
|
elCSS.type = elCSSBase.type;
|
||||||
|
if (elCSSBase.href.endsWith('?v=GITVERSION')) {
|
||||||
|
elCSS.href = elCSSBase.href.replace('?v=GITVERSION', '?v=' + Math.random());
|
||||||
|
} else {
|
||||||
|
elCSS.href = elCSSBase.href;
|
||||||
|
}
|
||||||
|
wtransfers.document.head.appendChild(elCSS);
|
||||||
|
}
|
||||||
|
|
||||||
|
wtransfers.document.body.innerHTML = detailedTransfers[stageNum];
|
||||||
|
}
|
||||||
|
|
||||||
// Provide a default seed
|
// Provide a default seed
|
||||||
if (document.getElementById('txtSeed').value === '') {
|
if (document.getElementById('txtSeed').value === '') {
|
||||||
function pad(x) { if (x < 10) { return '0' + x; } return '' + x; }
|
function pad(x) { if (x < 10) { return '0' + x; } return '' + x; }
|
||||||
|
|
|
@ -94,7 +94,7 @@ table {
|
||||||
color-adjust: exact;
|
color-adjust: exact;
|
||||||
-webkit-print-color-adjust: exact;
|
-webkit-print-color-adjust: exact;
|
||||||
}
|
}
|
||||||
.result td {
|
table.result td, table.transfers td {
|
||||||
padding: 0px 8px;
|
padding: 0px 8px;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
}
|
}
|
||||||
|
@ -127,10 +127,12 @@ td.elected {
|
||||||
tr.info td {
|
tr.info td {
|
||||||
background-color: #f0f5fb;
|
background-color: #f0f5fb;
|
||||||
}
|
}
|
||||||
tr.stage-no td:not(:empty), tr.hint-papers-votes td:not(:empty), tr.transfers td {
|
tr.stage-no td:not(:empty), tr.hint-papers-votes td:not(:empty), tr.transfers td,
|
||||||
|
table.transfers tr:first-child td, table.transfers tr:nth-last-child(2) td, table.transfers tr:last-child td {
|
||||||
border-top: 1px solid #76858c;
|
border-top: 1px solid #76858c;
|
||||||
}
|
}
|
||||||
tr.info:last-child td, .bb {
|
tr.info:last-child td, .bb,
|
||||||
|
table.transfers tr:first-child td, table.transfers tr:nth-last-child(2) td, table.transfers tr:last-child td {
|
||||||
border-bottom: 1px solid #76858c;
|
border-bottom: 1px solid #76858c;
|
||||||
}
|
}
|
||||||
.blw {
|
.blw {
|
||||||
|
@ -138,13 +140,18 @@ tr.info:last-child td, .bb {
|
||||||
border-left: 2px solid #76858c;
|
border-left: 2px solid #76858c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.transfers tr:first-child td {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
/* Table stripes */
|
/* Table stripes */
|
||||||
|
|
||||||
tr.stage-no td:nth-child(even):not([rowspan]),
|
tr.stage-no td:nth-child(even):not([rowspan]),
|
||||||
tr.stage-comment td:nth-child(odd),
|
tr.stage-comment td:nth-child(odd),
|
||||||
tr.hint-papers-votes td:nth-child(even),
|
tr.hint-papers-votes td:nth-child(even),
|
||||||
tr.candidate.transfers td:nth-child(even):not(.elected):not(.excluded),
|
tr.candidate.transfers td:nth-child(even):not(.elected):not(.excluded),
|
||||||
tr.candidate.votes td:nth-child(odd):not(.elected):not(.excluded) {
|
tr.candidate.votes td:nth-child(odd):not(.elected):not(.excluded),
|
||||||
|
table.transfers td:nth-child(even) {
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
}
|
}
|
||||||
tr.candidate.transfers td.elected:nth-child(even),
|
tr.candidate.transfers td.elected:nth-child(even),
|
||||||
|
@ -161,33 +168,8 @@ tr.info.votes td:nth-child(odd) {
|
||||||
background-color: #e8eef7;
|
background-color: #e8eef7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BLT input tool */
|
a.detailedTransfersLink {
|
||||||
|
color: #aaa;
|
||||||
#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 */
|
/* Print stylesheet */
|
||||||
|
|
|
@ -105,7 +105,12 @@ function resumeCount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
postMessage({'type': 'updateResultsTable', 'result': wasm['update_results_table_' + numbers](stageNum, state, opts, reportStyle)});
|
postMessage({'type': 'updateResultsTable', 'result': wasm['update_results_table_' + numbers](stageNum, state, opts, reportStyle)});
|
||||||
postMessage({'type': 'updateStageComments', 'comment': wasm['update_stage_comments_' + numbers](state)});
|
postMessage({'type': 'updateStageComments', 'comment': wasm['update_stage_comments_' + numbers](state, stageNum), 'stageNum': stageNum});
|
||||||
|
|
||||||
|
let transfers_table = state.transfer_table_render_html(opts);
|
||||||
|
if (transfers_table) {
|
||||||
|
postMessage({'type': 'updateDetailedTransfers', 'table': transfers_table, 'stageNum': stageNum});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
postMessage({'type': 'updateResultsTable', 'result': wasm['finalise_results_table_' + numbers](state, reportStyle)});
|
postMessage({'type': 'updateResultsTable', 'result': wasm['finalise_results_table_' + numbers](state, reportStyle)});
|
||||||
|
|
|
@ -15,9 +15,19 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// --------------
|
||||||
|
// Child packages
|
||||||
|
|
||||||
|
/// Transfer tables
|
||||||
mod transfers;
|
mod transfers;
|
||||||
pub use transfers::{TransferTable, TransferTableCell, TransferTableColumn};
|
pub use transfers::{TransferTable, TransferTableCell, TransferTableColumn};
|
||||||
|
|
||||||
|
/// prettytable-compatible API for HTML table output in WebAssembly
|
||||||
|
pub mod prettytable_html;
|
||||||
|
|
||||||
|
// --------
|
||||||
|
// STV code
|
||||||
|
|
||||||
use super::{ExclusionMethod, STVError, STVOptions, SurplusMethod, SurplusOrder};
|
use super::{ExclusionMethod, STVError, STVOptions, SurplusMethod, SurplusOrder};
|
||||||
use super::sample;
|
use super::sample;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
/// Table
|
||||||
|
pub struct Table {
|
||||||
|
/// Rows in the table
|
||||||
|
rows: Vec<Row>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Table {
|
||||||
|
/// Return a new [Table]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
rows: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a [Row] to the table
|
||||||
|
pub fn add_row(&mut self, row: Row) {
|
||||||
|
self.rows.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alias for [add_row]
|
||||||
|
pub fn set_titles(&mut self, row: Row) {
|
||||||
|
self.add_row(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render the table as HTML
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
return format!(r#"<table class="transfers">{}</table>"#, self.rows.iter().map(|r| r.to_string()).join(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Row in a [Table]
|
||||||
|
pub struct Row {
|
||||||
|
/// Cells in the row
|
||||||
|
cells: Vec<Cell>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Row {
|
||||||
|
/// Return a new [Row]
|
||||||
|
pub fn new(cells: Vec<Cell>) -> Self {
|
||||||
|
Self {
|
||||||
|
cells
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render the row as HTML
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
return format!(r#"<tr>{}</tr>"#, self.cells.iter().map(|c| c.to_string()).join(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cell in a [Row]
|
||||||
|
pub struct Cell {
|
||||||
|
/// Content of the cell
|
||||||
|
content: String,
|
||||||
|
/// HTML tag/attributes
|
||||||
|
attrs: Vec<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cell {
|
||||||
|
/// Return a new [Cell]
|
||||||
|
pub fn new(content: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
content: String::from(content),
|
||||||
|
attrs: vec!["td"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply a style to the cell
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
pub fn style_spec(mut self, spec: &str) -> Self {
|
||||||
|
if spec.contains("H2") {
|
||||||
|
self.attrs.push(r#"colspan="2""#);
|
||||||
|
}
|
||||||
|
if spec.contains("c") {
|
||||||
|
self.attrs.push(r#"style="text-align:center""#);
|
||||||
|
}
|
||||||
|
if spec.contains("r") {
|
||||||
|
self.attrs.push(r#"style="text-align:right""#);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render the cell as HTML
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
return format!(r#"<{}>{}</td>"#, self.attrs.join(" "), html_escape::encode_text(&self.content));
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,10 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use prettytable::{Cell, Row, Table};
|
use prettytable::{Cell, Row, Table};
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
use super::prettytable_html::{Cell, Row, Table};
|
||||||
|
|
||||||
use crate::election::{Candidate, CountState};
|
use crate::election::{Candidate, CountState};
|
||||||
use crate::numbers::Number;
|
use crate::numbers::Number;
|
||||||
|
@ -287,10 +290,10 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
||||||
return checksum;
|
return checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render table as plain text
|
/// Render table as [Table]
|
||||||
pub fn render_text(&self, state: &CountState<N>, opts: &STVOptions) -> String {
|
fn render(&self, state: &CountState<N>, opts: &STVOptions) -> Table {
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
table.set_format(*prettytable::format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
|
set_table_format(&mut table);
|
||||||
|
|
||||||
let show_transfers_per_ballot = !self.surpfrac.is_none() && opts.sum_surplus_transfers == SumSurplusTransfersMode::PerBallot;
|
let show_transfers_per_ballot = !self.surpfrac.is_none() && opts.sum_surplus_transfers == SumSurplusTransfersMode::PerBallot;
|
||||||
|
|
||||||
|
@ -448,12 +451,18 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
||||||
|
|
||||||
table.add_row(Row::new(row));
|
table.add_row(Row::new(row));
|
||||||
|
|
||||||
return table.to_string();
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render table as plain text
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn render_text(&self, state: &CountState<N>, opts: &STVOptions) -> String {
|
||||||
|
return self.render(state, opts).to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render table as HTML
|
/// Render table as HTML
|
||||||
pub fn render_html(&self) -> String {
|
pub fn render_html(&self, state: &CountState<N>, opts: &STVOptions) -> String {
|
||||||
todo!();
|
return self.render(state, opts).to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,3 +506,13 @@ pub struct TransferTableCell<N: Number> {
|
||||||
/// Votes transferred to the continuing candidate
|
/// Votes transferred to the continuing candidate
|
||||||
pub votes_out: N,
|
pub votes_out: N,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
fn set_table_format(table: &mut Table) {
|
||||||
|
table.set_format(*prettytable::format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
fn set_table_format(_table: &mut Table) {
|
||||||
|
// No op
|
||||||
|
}
|
||||||
|
|
|
@ -141,8 +141,8 @@ macro_rules! impl_type {
|
||||||
/// Wrapper for [update_stage_comments]
|
/// Wrapper for [update_stage_comments]
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn [<update_stage_comments_$type>](state: &[<CountState$type>]) -> String {
|
pub fn [<update_stage_comments_$type>](state: &[<CountState$type>], stage_num: usize) -> String {
|
||||||
return update_stage_comments(&state.0);
|
return update_stage_comments(&state.0, stage_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper for [finalise_results_table]
|
/// Wrapper for [finalise_results_table]
|
||||||
|
@ -173,6 +173,14 @@ macro_rules! impl_type {
|
||||||
pub fn new(election: &[<Election$type>]) -> Self {
|
pub fn new(election: &[<Election$type>]) -> Self {
|
||||||
return [<CountState$type>](CountState::new(election.as_static()));
|
return [<CountState$type>](CountState::new(election.as_static()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call [render_html](crate::stv::transfers::TransferTable::render_html) on [CountState::transfer_table]
|
||||||
|
pub fn transfer_table_render_html(&self, opts: &STVOptions) -> Option<String> {
|
||||||
|
return match &self.0.transfer_table {
|
||||||
|
Some(tt) => Some(tt.render_html(&self.0, &opts.0)), // TODO
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper for [Election]
|
/// Wrapper for [Election]
|
||||||
|
@ -613,8 +621,12 @@ fn update_results_table<N: Number>(stage_num: usize, state: &CountState<N>, opts
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the comment for the current stage
|
/// Get the comment for the current stage
|
||||||
fn update_stage_comments<N: Number>(state: &CountState<N>) -> String {
|
fn update_stage_comments<N: Number>(state: &CountState<N>, stage_num: usize) -> String {
|
||||||
return state.logger.render().join(" ");
|
let mut comments = state.logger.render().join(" ");
|
||||||
|
if let Some(_) = state.transfer_table {
|
||||||
|
comments.push_str(&format!(r##" <a href="#" class="detailedTransfersLink" onclick="viewDetailedTransfers({});return false;">[View detailed transfers]</a>"##, stage_num));
|
||||||
|
}
|
||||||
|
return comments;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate the final column of the HTML results table
|
/// Generate the final column of the HTML results table
|
||||||
|
|
Loading…
Reference in New Issue