parent
6bb2dfddcb
commit
90bb2b6265
@ -119,12 +119,24 @@ class ListChoiceQuestion(Question):
|
|||||||
def pretty_answer(self, answer):
|
def pretty_answer(self, answer):
|
||||||
if len(answer.choices) == 0:
|
if len(answer.choices) == 0:
|
||||||
return '(blank votes)'
|
return '(blank votes)'
|
||||||
return ', '.join([self.choices[choice].name for choice in answer.choices])
|
flat_choices = self.flatten_choices()
|
||||||
|
return ', '.join([flat_choices[choice].name for choice in answer.choices])
|
||||||
|
|
||||||
def max_bits(self):
|
def max_bits(self):
|
||||||
answer = self.answer_type(choices=list(range(len(self.choices))))
|
answer = self.answer_type(choices=list(range(len(self.choices))))
|
||||||
return len(EosObject.to_json(EosObject.serialise_and_wrap(answer))) * 8
|
return len(EosObject.to_json(EosObject.serialise_and_wrap(answer))) * 8
|
||||||
|
|
||||||
|
def flatten_choices(self):
|
||||||
|
# Return a flat list of Choices, without Tickets
|
||||||
|
flat_choices = []
|
||||||
|
for choice in self.choices:
|
||||||
|
if isinstance(choice, Ticket):
|
||||||
|
for choice2 in choice.choices:
|
||||||
|
flat_choices.append(choice2)
|
||||||
|
else:
|
||||||
|
flat_choices.append(choice)
|
||||||
|
return flat_choices
|
||||||
|
|
||||||
class ApprovalAnswer(Answer):
|
class ApprovalAnswer(Answer):
|
||||||
choices = ListField(IntField())
|
choices = ListField(IntField())
|
||||||
|
|
||||||
@ -141,6 +153,16 @@ class Choice(EmbeddedObject):
|
|||||||
name = StringField()
|
name = StringField()
|
||||||
party = StringField(default=None)
|
party = StringField(default=None)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def party_or_ticket(self):
|
||||||
|
if self.party is not None:
|
||||||
|
return self.party
|
||||||
|
else:
|
||||||
|
ticket = self.recurse_parents(Ticket)
|
||||||
|
if ticket:
|
||||||
|
return ticket.name
|
||||||
|
return None
|
||||||
|
|
||||||
class Ticket(EmbeddedObject):
|
class Ticket(EmbeddedObject):
|
||||||
name = StringField()
|
name = StringField()
|
||||||
choices = EmbeddedObjectListField()
|
choices = EmbeddedObjectListField()
|
||||||
|
@ -109,10 +109,14 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preferential-choice .party-name {
|
.preferential-choice .party-name, .preferential-choice .ticket-party-name {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ticket .ticket-party-name {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ticket > .content > .party-name {
|
.ticket > .content > .party-name {
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" id="question-choice-{{ loop.index0 }}" onchange="choicesChanged();">
|
<input type="checkbox" id="question-choice-{{ loop.index0 }}" onchange="choicesChanged();">
|
||||||
<label for="question-choice-{{ loop.index0 }}">{{ choice }}</label>
|
<label for="question-choice-{{ loop.index0 }}">{{ choice.name }}{% if choice.party %} – {{ choice.party }}{% endif %}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
{% for choice in booth.answers[loop.index0].value.choices %}
|
{% for choice in booth.answers[loop.index0].value.choices %}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<i class="checkmark icon"></i>
|
<i class="checkmark icon"></i>
|
||||||
<div class="content">{{ question.choices.__getitem__(choice) }}</div>
|
<div class="content">{{ question.choices.__getitem__(choice).name }}{% if question.choices.__getitem__(choice).party %}{{ question.choices.__getitem__(choice).party }}{% endif %}</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
|
@ -34,12 +34,22 @@
|
|||||||
<p>You have selected more than the maximum allowed number of choices. To proceed, you must deselect some choices by dragging them from the blue box back to the grey box.</p>
|
<p>You have selected more than the maximum allowed number of choices. To proceed, you must deselect some choices by dragging them from the blue box back to the grey box.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% set flat_choices = election.questions.__getitem__(questionNum).flatten_choices() %}
|
||||||
|
|
||||||
{% macro printchoice(choice, ticket=None) %}
|
{% macro printchoice(choice, ticket=None) %}
|
||||||
<div class="preferential-choice" data-choiceno="{{ loop.index0 }}">
|
<div class="preferential-choice" data-choiceno="{{ flat_choices.indexOf(choice) }}">
|
||||||
<div class="number"></div>
|
<div class="number"></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="candidate-name">{{ choice.name }}</div>
|
<div class="candidate-name">{{ choice.name }}</div>
|
||||||
{% if (ticket and choice.party and choice.party != ticket.name) or (not ticket and choice.party) %}<div class="party-name">{{ choice.party }}</div>{% endif %}
|
{% if choice.party %}
|
||||||
|
{% if (ticket and choice.party != ticket.name) or not ticket %}
|
||||||
|
<div class="party-name">{{ choice.party }}</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="ticket-party-name">{{ choice.party }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% elif ticket %}
|
||||||
|
<div class="ticket-party-name">{{ ticket.name }}</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
@ -51,7 +61,7 @@
|
|||||||
{% for choice in election.questions.__getitem__(questionNum).choices.impl %}
|
{% for choice in election.questions.__getitem__(questionNum).choices.impl %}
|
||||||
{% if choice.choices %}
|
{% if choice.choices %}
|
||||||
{# Ticket #}
|
{# Ticket #}
|
||||||
<div class="preferential-choice ticket" data-choiceno="{{ loop.index0 }}">
|
<div class="preferential-choice ticket" data-ticketno="{{ loop.index0 }}">
|
||||||
<div class="number"></div>
|
<div class="number"></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="party-name">{{ choice.name }}</div>
|
<div class="party-name">{{ choice.name }}</div>
|
||||||
@ -71,6 +81,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
var allowAdding = true;
|
var allowAdding = true;
|
||||||
|
var flat_choices = election.questions.__getitem__(booth.questionNum).flatten_choices();
|
||||||
|
|
||||||
function choicesChanged() {
|
function choicesChanged() {
|
||||||
// Recalculate numbers
|
// Recalculate numbers
|
||||||
@ -103,10 +114,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill in ballot with previous selections
|
// Fill in ballot with previous selections
|
||||||
if (booth.answers[booth.questionNum]) {
|
if (booth.q_state[booth.questionNum]) {
|
||||||
for (var selection of booth.answers[booth.questionNum].value.choices) { // Answer already serialised
|
$("#question-choices-selected .dragarea").html(booth.q_state[booth.questionNum][0]);
|
||||||
$(".preferential-choice[data-choiceno=" + selection + "]").detach().appendTo("#question-choices-selected .dragarea");
|
$("#question-choices-remaining .dragarea").html(booth.q_state[booth.questionNum][1]);
|
||||||
}
|
|
||||||
choicesChanged();
|
choicesChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,9 +127,6 @@
|
|||||||
if ("dragarea-hint" in el.classList) {
|
if ("dragarea-hint" in el.classList) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//if ("ticket" in el.classList && !("party-name" in handle.classList)) {
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
if ($.contains(document.querySelector("#question-choices-remaining"), el)) {
|
if ($.contains(document.querySelector("#question-choices-remaining"), el)) {
|
||||||
return allowAdding;
|
return allowAdding;
|
||||||
}
|
}
|
||||||
@ -129,16 +136,33 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function breakTicket(ticket) {
|
||||||
|
ticket.find(".ticket-choices .preferential-choice").each(function(i, el) {
|
||||||
|
$(el).detach().insertAfter(ticket);
|
||||||
|
});
|
||||||
|
ticket.remove();
|
||||||
|
}
|
||||||
|
|
||||||
dragulaChoices.on("drop", function(el, target, source, sibling) {
|
dragulaChoices.on("drop", function(el, target, source, sibling) {
|
||||||
|
// If the source or target is a ticket, break the ticket
|
||||||
|
if ($(source).parents(".ticket").length > 0) {
|
||||||
|
breakTicket($(source).parents(".ticket").first())
|
||||||
|
}
|
||||||
|
if ($(target).parents(".ticket").length > 0) {
|
||||||
|
breakTicket($(target).parents(".ticket").first())
|
||||||
|
}
|
||||||
|
|
||||||
choicesChanged();
|
choicesChanged();
|
||||||
});
|
});
|
||||||
|
|
||||||
function saveSelections() {
|
function saveSelections() {
|
||||||
selections = [];
|
selections = [];
|
||||||
$("#question-choices-selected .preferential-choice").each(function(i, el) {
|
$("#question-choices-selected .preferential-choice:not(.ticket)").each(function(i, el) {
|
||||||
selections.push(parseInt(el.dataset.choiceno));
|
selections.push(parseInt(el.dataset.choiceno));
|
||||||
});
|
});
|
||||||
answer = eosjs.eos.base.election.__all__.PreferentialAnswer(eosjs.__kwargtrans__({choices: selections}));
|
answer = eosjs.eos.base.election.__all__.PreferentialAnswer(eosjs.__kwargtrans__({choices: selections}));
|
||||||
booth.answers[booth.questionNum] = eosjs.eos.core.objects.__all__.EosObject.serialise_and_wrap(answer);
|
booth.answers[booth.questionNum] = eosjs.eos.core.objects.__all__.EosObject.serialise_and_wrap(answer);
|
||||||
|
|
||||||
|
booth.q_state[booth.questionNum] = [$("#question-choices-selected .dragarea").html(), $("#question-choices-remaining .dragarea").html()]; // wew lad
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -16,11 +16,13 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#}
|
#}
|
||||||
|
|
||||||
|
{% set flat_choices = question.flatten_choices() %}
|
||||||
|
|
||||||
{% if booth.answers[loop.index0].value.choices.length > 0 %}
|
{% if booth.answers[loop.index0].value.choices.length > 0 %}
|
||||||
<div class="ui ordered list">
|
<div class="ui ordered list">
|
||||||
{% for choice in booth.answers[loop.index0].value.choices %}
|
{% for choice in booth.answers[loop.index0].value.choices %}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="content">{{ question.choices.__getitem__(choice) }}</div>
|
<div class="content">{{ flat_choices[choice].name }}{% if flat_choices[choice].party_or_ticket %} – {{ flat_choices[choice].party_or_ticket }}{% endif %}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
booth = {
|
booth = {
|
||||||
"questionNum": 0,
|
"questionNum": 0,
|
||||||
"answers": [],
|
"answers": [],
|
||||||
|
"q_state": []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
resetBooth();
|
resetBooth();
|
||||||
@ -136,6 +137,7 @@
|
|||||||
techDetails = '<p>Technical details: ' + err + '</p>';
|
techDetails = '<p>Technical details: ' + err + '</p>';
|
||||||
}
|
}
|
||||||
$("#booth-content").html('<div class="ui error message"><p>We were unable to display the next page of the voting booth. For your security, your ballot selections have been cleared. Please try again. If this problem persists, contact the {{ election.kind }} administrator.</p>' + techDetails + '</div>');
|
$("#booth-content").html('<div class="ui error message"><p>We were unable to display the next page of the voting booth. For your security, your ballot selections have been cleared. Please try again. If this problem persists, contact the {{ election.kind }} administrator.</p>' + techDetails + '</div>');
|
||||||
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showTemplate(template, opts, destination) {
|
function showTemplate(template, opts, destination) {
|
||||||
|
Loading…
Reference in New Issue
Block a user