diff --git a/eos/base/election.py b/eos/base/election.py index 054d946..a530632 100644 --- a/eos/base/election.py +++ b/eos/base/election.py @@ -101,6 +101,17 @@ class ApprovalQuestion(Question): class ApprovalAnswer(Answer): choices = ListField(IntField()) +class PreferentialQuestion(Question): + choices = ListField(StringField()) + min_choices = IntField() + max_choices = IntField() + + def pretty_answer(self, answer): + return ', '.join([self.choices[choice] for choice in answer.choices]) + +class PreferentialAnswer(Answer): + choices = ListField(IntField()) + class RawResult(Result): answers = EmbeddedObjectListField() diff --git a/eosweb/core/bower.json b/eosweb/core/bower.json index 61a6d2a..3587672 100644 --- a/eosweb/core/bower.json +++ b/eosweb/core/bower.json @@ -17,6 +17,7 @@ ], "dependencies": { "semantic": "semantic-ui#^2.2.13", - "nunjucks": "^3.0.1" + "nunjucks": "^3.0.1", + "dragula.js": "dragula#^3.7.2" } } diff --git a/eosweb/core/main.py b/eosweb/core/main.py index 16a4e08..4ab0cb9 100644 --- a/eosweb/core/main.py +++ b/eosweb/core/main.py @@ -109,7 +109,7 @@ def setup_test_election(): election.sk = EGPrivateKey.generate() election.public_key = election.sk.public_key - question = ApprovalQuestion(prompt='President', choices=['John Smith', 'Joe Bloggs', 'John Q. Public'], min_choices=0, max_choices=2) + question = PreferentialQuestion(prompt='President', choices=['John Smith', 'Joe Bloggs', '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) diff --git a/eosweb/core/modelview.py b/eosweb/core/modelview.py index d33d6f6..9616f6f 100644 --- a/eosweb/core/modelview.py +++ b/eosweb/core/modelview.py @@ -27,6 +27,12 @@ model_view_map = { Election: { 'tabs': 'election/core/tabs.html' }, + PreferentialQuestion: { + 'view': 'question/preferential/view.html', + 'result_raw': 'question/preferential/result_raw.html', + 'selections_make': 'question/preferential/selections_make.html', + 'selections_review': 'question/preferential/selections_review.html' + }, PSRElection: { 'tabs': 'election/psr/tabs.html' } diff --git a/eosweb/core/static/css/main.css b/eosweb/core/static/css/main.css index f1d10f0..bafefd8 100644 --- a/eosweb/core/static/css/main.css +++ b/eosweb/core/static/css/main.css @@ -36,3 +36,60 @@ margin-top: 4em; } } + +/* Preferential voting */ + +.preferential-choices { + padding: 0.5em; + position: relative; +} + +.preferential-choices .dragarea { + min-height: 3em; + margin-top: 0.5em; +} + +.preferential-choices .dragarea-hint:first-child:last-child { + content: ""; + width: calc(100% - 1em); + height: 3em; + box-sizing: border-box; + z-index: -100; + border: 1px dashed #555; + position: absolute; +} + +#question-choices-selected { + border: 1px solid #3465a4; + margin-bottom: 0.5em; +} + +.preferential-choice { + background-color: #eee; + font-size: 1.1rem; + margin-top: 0.5em; + display: flex; + align-items: center; + min-height: 3em; +} + +.preferential-choice:first-child { + margin-top: 0; +} + +#question-choices-selected .preferential-choice { + background-color: #e6f1fc; +} + +#question-choices-remaining { + border: 1px solid #555; +} + +.preferential-choice .number, .preferential-choice .name { + padding: 0.5em 0 0.5em 0.5em; +} + +.preferential-choice .number { + width: 2em; + text-align: center; +} diff --git a/eosweb/core/static/nunjucks/question/approval/selections_make.html b/eosweb/core/static/nunjucks/question/approval/selections_make.html index cdced20..1526e6f 100644 --- a/eosweb/core/static/nunjucks/question/approval/selections_make.html +++ b/eosweb/core/static/nunjucks/question/approval/selections_make.html @@ -18,7 +18,7 @@
Vote for between {{ election.questions.__getitem__(questionNum).min_choices }} and {{ election.questions.__getitem__(questionNum).max_choices }} candidates. Click the check-boxes to the left of the candidates' names to make your selection, then click the ‘Continue’ button. If you make a mistake, click the check-boxes again to clear your selection.
+Vote for between {{ election.questions.__getitem__(questionNum).min_choices }} and {{ election.questions.__getitem__(questionNum).max_choices }} choices. Click the check-boxes to the left of the choices to make your selection, then click the ‘Continue’ button. If you make a mistake, click the check-boxes again to clear your selection.