From 6bb2dfddcb9d70bdae6d2f03c49bf25e3fb54b87 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Mon, 11 Dec 2017 10:55:01 +1030 Subject: [PATCH] Basic ticket dragging #7 --- eos/base/election.py | 14 ++++- eos/base/tests.py | 4 +- eos/psr/tests.py | 4 +- eosweb/core/main.py | 10 +++- eosweb/core/static/css/main.css | 26 +++++++-- .../preferential/selections_make.html | 58 ++++++++++++++++--- .../templates/question/approval/view.html | 2 +- .../templates/question/preferential/view.html | 14 ++++- 8 files changed, 107 insertions(+), 25 deletions(-) diff --git a/eos/base/election.py b/eos/base/election.py index 888242a..e563142 100644 --- a/eos/base/election.py +++ b/eos/base/election.py @@ -110,14 +110,16 @@ class Result(EmbeddedObject): pass class ListChoiceQuestion(Question): - choices = ListField(StringField()) + _ver = StringField(default='0.4') + + choices = EmbeddedObjectListField() min_choices = IntField() max_choices = IntField() def pretty_answer(self, answer): if len(answer.choices) == 0: return '(blank votes)' - return ', '.join([self.choices[choice] for choice in answer.choices]) + return ', '.join([self.choices[choice].name for choice in answer.choices]) def max_bits(self): answer = self.answer_type(choices=list(range(len(self.choices)))) @@ -135,6 +137,14 @@ class PreferentialAnswer(Answer): class PreferentialQuestion(ListChoiceQuestion): answer_type = PreferentialAnswer +class Choice(EmbeddedObject): + name = StringField() + party = StringField(default=None) + +class Ticket(EmbeddedObject): + name = StringField() + choices = EmbeddedObjectListField() + class RawResult(Result): plaintexts = ListField(EmbeddedObjectListField()) answers = EmbeddedObjectListField() diff --git a/eos/base/tests.py b/eos/base/tests.py index be6d865..78abbcb 100644 --- a/eos/base/tests.py +++ b/eos/base/tests.py @@ -56,10 +56,10 @@ class ElectionTestCase(EosTestCase): # Check _instance self.assertEqual(voter._instance, (election.voters, i)) - question = ApprovalQuestion(prompt='President', choices=['John Smith', 'Joe Bloggs', 'John Q. Public']) + question = ApprovalQuestion(prompt='President', choices=[Choice(name='John Smith'), Choice(name='Joe Bloggs'), Choice(name='John Q. Public')]) election.questions.append(question) - question = ApprovalQuestion(prompt='Chairman', choices=['John Doe', 'Andrew Citizen']) + question = ApprovalQuestion(prompt='Chairman', choices=[Choice(name='John Doe'), Choice(name='Andrew Citizen')]) election.questions.append(question) election.save() diff --git a/eos/psr/tests.py b/eos/psr/tests.py index 29bf25e..8104f71 100644 --- a/eos/psr/tests.py +++ b/eos/psr/tests.py @@ -252,10 +252,10 @@ class ElectionTestCase(EosTestCase): election.sk = EGPrivateKey.generate() election.public_key = election.sk.public_key - question = ApprovalQuestion(prompt='President', choices=['John Smith', 'Joe Bloggs', 'John Q. Public']) + question = ApprovalQuestion(prompt='President', choices=[Choice(name='John Smith'), Choice(name='Joe Bloggs'), Choice(name='John Q. Public')]) election.questions.append(question) - question = ApprovalQuestion(prompt='Chairman', choices=['John Doe', 'Andrew Citizen']) + question = ApprovalQuestion(prompt='Chairman', choices=[Choice(name='John Doe'), Choice(name='Andrew Citizen')]) election.questions.append(question) election.save() diff --git a/eosweb/core/main.py b/eosweb/core/main.py index 2703ed1..61a29f0 100644 --- a/eosweb/core/main.py +++ b/eosweb/core/main.py @@ -123,10 +123,16 @@ def setup_test_election(): election.sk = EGPrivateKey.generate() election.public_key = election.sk.public_key - question = PreferentialQuestion(prompt='President', choices=['John Smith', 'Joe Bloggs', 'John Q. Public'], min_choices=0, max_choices=3) + question = PreferentialQuestion(prompt='President', choices=[ + Ticket(name='ACME Party', choices=[ + Choice(name='John Smith'), + Choice(name='Joe Bloggs', party='Independent ACME') + ]), + Choice(name='John Q. Public') + ], min_choices=0, max_choices=3) election.questions.append(question) - question = ApprovalQuestion(prompt='Chairman', choices=['John Doe', 'Andrew Citizen'], min_choices=0, max_choices=1) + question = ApprovalQuestion(prompt='Chairman', choices=[Choice(name='John Doe'), Choice(name='Andrew Citizen')], min_choices=0, max_choices=1) election.questions.append(question) election.save() diff --git a/eosweb/core/static/css/main.css b/eosweb/core/static/css/main.css index dad7e4f..99eacc2 100644 --- a/eosweb/core/static/css/main.css +++ b/eosweb/core/static/css/main.css @@ -51,13 +51,13 @@ } .preferential-choices .dragarea { - min-height: 3em; + min-height: 2em; margin-top: 0.5em; } .preferential-choices .dragarea-hint:first-child:last-child { width: calc(100% - 1em); - height: 3em; + height: 2em; box-sizing: border-box; z-index: -100; border: 1px dashed #555; @@ -71,11 +71,13 @@ .preferential-choice { background-color: #eee; - font-size: 1.1rem; margin-top: 0.5em; display: flex; - align-items: center; - min-height: 3em; + min-height: 2em; +} + +.ticket-choices .preferential-choice { + margin-top: 0em; } .preferential-choice:first-child { @@ -94,11 +96,23 @@ background-color: #eee; } -.preferential-choice .number, .preferential-choice .name { +.preferential-choice .number, .preferential-choice .content { padding: 0.5em 0 0.5em 0.5em; } +.ticket-choices .number, .ticket-choices .content { + padding: 0 0 0 0.5em; +} + .preferential-choice .number { width: 2em; text-align: center; } + +.preferential-choice .party-name { + font-style: italic; +} + +.ticket > .content > .party-name { + min-height: 2em; +} diff --git a/eosweb/core/static/nunjucks/question/preferential/selections_make.html b/eosweb/core/static/nunjucks/question/preferential/selections_make.html index f338493..6284312 100644 --- a/eosweb/core/static/nunjucks/question/preferential/selections_make.html +++ b/eosweb/core/static/nunjucks/question/preferential/selections_make.html @@ -30,16 +30,41 @@ + + +{% macro printchoice(choice, ticket=None) %} +
+
+
+
{{ choice.name }}
+ {% if (ticket and choice.party and choice.party != ticket.name) or (not ticket and choice.party) %}
{{ choice.party }}
{% endif %} +
+
+{% endmacro %}
Options not yet voted for:
{% for choice in election.questions.__getitem__(questionNum).choices.impl %} -
-
-
{{ choice }}
-
+ {% if choice.choices %} + {# Ticket #} +
+
+
+
{{ choice.name }}
+
+ {% for choice2 in choice.choices.impl %} + {{ printchoice(choice2, choice) }} + {% endfor %} +
+
+
+ {% else %} + {{ printchoice(choice) }} + {% endif %} {% endfor %}
@@ -52,17 +77,28 @@ $(".preferential-choices .preferential-choice .number").each(function(i, el) { $(el).text(""); }); - var selectedChoices = $("#question-choices-selected .preferential-choice .number"); + var selectedChoices = $("#question-choices-selected .dragarea > .preferential-choice > .number"); selectedChoices.each(function(i, el) { $(el).text(i + 1); }); - if (selectedChoices.length >= election.questions.__getitem__(booth.questionNum).max_choices) { + var selectedCandidates = $("#question-choices-selected .preferential-choice:not(.ticket) .number"); + if (selectedCandidates.length >= election.questions.__getitem__(booth.questionNum).max_choices) { // Prevent making any more selections allowAdding = false; - $("#message-max-choices").removeClass("hidden"); + + if (selectedCandidates.length > election.questions.__getitem__(booth.questionNum).max_choices) { + // Prevent progression + $(".primary.button").addClass("disabled"); + $("#message-too-many-choices").removeClass("hidden"); + } else { + $(".primary.button").removeClass("disabled"); + $("#message-max-choices").removeClass("hidden"); + } } else { allowAdding = true; $("#message-max-choices").addClass("hidden"); + $("#message-too-many-choices").addClass("hidden"); + $(".primary.button").removeClass("disabled"); } } @@ -75,17 +111,21 @@ } var dragulaChoices = dragula( - [document.querySelector("#question-choices-selected .dragarea"), document.querySelector("#question-choices-remaining .dragarea")], + [document.querySelector("#question-choices-selected .dragarea"), document.querySelector("#question-choices-remaining .dragarea")].concat([].slice.apply(document.querySelectorAll(".ticket-choices"))), { moves: function(el, source, handle, sibling) { if ("dragarea-hint" in el.classList) { return false; } + //if ("ticket" in el.classList && !("party-name" in handle.classList)) { + // return false; + //} if ($.contains(document.querySelector("#question-choices-remaining"), el)) { return allowAdding; } return true; - } + }, + mirrorContainer: document.querySelector("#question-choices-remaining") } ); diff --git a/eosweb/core/templates/question/approval/view.html b/eosweb/core/templates/question/approval/view.html index 1264829..e40b4a9 100644 --- a/eosweb/core/templates/question/approval/view.html +++ b/eosweb/core/templates/question/approval/view.html @@ -20,6 +20,6 @@ diff --git a/eosweb/core/templates/question/preferential/view.html b/eosweb/core/templates/question/preferential/view.html index 02e460c..cf546e4 100644 --- a/eosweb/core/templates/question/preferential/view.html +++ b/eosweb/core/templates/question/preferential/view.html @@ -20,6 +20,18 @@