Merge pull request #3774 from FinnStutzenstein/abstain-no-for-assignment-votes
Added general abstain/no fields for assignments. Used in votes mode.
This commit is contained in:
commit
e9ad439cdd
27
openslides/assignments/migrations/0004_auto_20180703_1523.py
Normal file
27
openslides/assignments/migrations/0004_auto_20180703_1523.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.8 on 2018-07-03 13:23
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
from openslides.utils.models import MinMaxIntegerField
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assignments', '0003_candidate_weight'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignmentpoll',
|
||||||
|
name='votesabstain',
|
||||||
|
field=MinMaxIntegerField(null=True, blank=True, min_value=-2),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignmentpoll',
|
||||||
|
name='votesno',
|
||||||
|
field=MinMaxIntegerField(null=True, blank=True, min_value=-2),
|
||||||
|
),
|
||||||
|
]
|
@ -19,7 +19,7 @@ from openslides.poll.models import (
|
|||||||
)
|
)
|
||||||
from openslides.utils.autoupdate import inform_changed_data
|
from openslides.utils.autoupdate import inform_changed_data
|
||||||
from openslides.utils.exceptions import OpenSlidesError
|
from openslides.utils.exceptions import OpenSlidesError
|
||||||
from openslides.utils.models import RESTModelMixin
|
from openslides.utils.models import MinMaxIntegerField, RESTModelMixin
|
||||||
|
|
||||||
from .access_permissions import AssignmentAccessPermissions
|
from .access_permissions import AssignmentAccessPermissions
|
||||||
|
|
||||||
@ -423,6 +423,11 @@ class AssignmentPoll(RESTModelMixin, CollectDefaultVotesMixin, # type: ignore
|
|||||||
max_length=79,
|
max_length=79,
|
||||||
blank=True)
|
blank=True)
|
||||||
|
|
||||||
|
votesabstain = MinMaxIntegerField(null=True, blank=True, min_value=-2)
|
||||||
|
""" General abstain votes, used for pollmethod 'votes' """
|
||||||
|
votesno = MinMaxIntegerField(null=True, blank=True, min_value=-2)
|
||||||
|
""" General no votes, used for pollmethod 'votes' """
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
default_permissions = ()
|
default_permissions = ()
|
||||||
|
|
||||||
|
@ -111,6 +111,8 @@ class AssignmentAllPollSerializer(ModelSerializer):
|
|||||||
'description',
|
'description',
|
||||||
'published',
|
'published',
|
||||||
'options',
|
'options',
|
||||||
|
'votesabstain',
|
||||||
|
'votesno',
|
||||||
'votesvalid',
|
'votesvalid',
|
||||||
'votesinvalid',
|
'votesinvalid',
|
||||||
'votescast',
|
'votescast',
|
||||||
@ -160,6 +162,8 @@ class AssignmentAllPollSerializer(ModelSerializer):
|
|||||||
# Update remaining writeable fields.
|
# Update remaining writeable fields.
|
||||||
instance.description = validated_data.get('description', instance.description)
|
instance.description = validated_data.get('description', instance.description)
|
||||||
instance.published = validated_data.get('published', instance.published)
|
instance.published = validated_data.get('published', instance.published)
|
||||||
|
instance.votesabstain = validated_data.get('votesabstain', instance.votesabstain)
|
||||||
|
instance.votesno = validated_data.get('votesno', instance.votesno)
|
||||||
instance.votesvalid = validated_data.get('votesvalid', instance.votesvalid)
|
instance.votesvalid = validated_data.get('votesvalid', instance.votesvalid)
|
||||||
instance.votesinvalid = validated_data.get('votesinvalid', instance.votesinvalid)
|
instance.votesinvalid = validated_data.get('votesinvalid', instance.votesinvalid)
|
||||||
instance.votescast = validated_data.get('votescast', instance.votescast)
|
instance.votescast = validated_data.get('votescast', instance.votescast)
|
||||||
@ -182,6 +186,8 @@ class AssignmentShortPollSerializer(AssignmentAllPollSerializer):
|
|||||||
'description',
|
'description',
|
||||||
'published',
|
'published',
|
||||||
'options',
|
'options',
|
||||||
|
'votesabstain',
|
||||||
|
'votesno',
|
||||||
'votesvalid',
|
'votesvalid',
|
||||||
'votesinvalid',
|
'votesinvalid',
|
||||||
'votescast',
|
'votescast',
|
||||||
|
@ -214,7 +214,9 @@ angular.module('OpenSlidesApp.assignments', [])
|
|||||||
if (_.findIndex(this.options, predicate) !== -1) {
|
if (_.findIndex(this.options, predicate) !== -1) {
|
||||||
base = void 0;
|
base = void 0;
|
||||||
} else {
|
} else {
|
||||||
if (typeof base === 'undefined' && type !== 'votescast' && type !== 'votesinvalid' && type !== 'votesvalid') {
|
if (typeof base === 'undefined' && type !== 'votesabstain' &&
|
||||||
|
type !== 'votesno' && type !== 'votescast' &&
|
||||||
|
type !== 'votesinvalid' && type !== 'votesvalid') {
|
||||||
base = _.reduce(this.options, function (sum, option) {
|
base = _.reduce(this.options, function (sum, option) {
|
||||||
return sum + option.votes[0].weight;
|
return sum + option.votes[0].weight;
|
||||||
}, 0);
|
}, 0);
|
||||||
@ -240,6 +242,12 @@ angular.module('OpenSlidesApp.assignments', [])
|
|||||||
config = Config.get('assignments_poll_100_percent_base').value;
|
config = Config.get('assignments_poll_100_percent_base').value;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case 'votesabstain':
|
||||||
|
vote = this.votesabstain;
|
||||||
|
break;
|
||||||
|
case 'votesno':
|
||||||
|
vote = this.votesno;
|
||||||
|
break;
|
||||||
case 'votesinvalid':
|
case 'votesinvalid':
|
||||||
vote = this.votesinvalid;
|
vote = this.votesinvalid;
|
||||||
break;
|
break;
|
||||||
|
@ -67,7 +67,7 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
var candidatesText = gettextCatalog.getString("Candidates") + ": ";
|
var candidatesText = gettextCatalog.getString("Candidates") + ": ";
|
||||||
var userList = [];
|
var userList = [];
|
||||||
|
|
||||||
angular.forEach(candidates, function(assignmentsRelatedUser) {
|
_.forEach(candidates, function(assignmentsRelatedUser) {
|
||||||
userList.push({
|
userList.push({
|
||||||
text: assignmentsRelatedUser.user.get_full_name(),
|
text: assignmentsRelatedUser.user.get_full_name(),
|
||||||
margin: [0, 0, 0, 10],
|
margin: [0, 0, 0, 10],
|
||||||
@ -114,30 +114,30 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
|
|
||||||
//creates the voting string for the result table and differentiates between special values
|
//creates the voting string for the result table and differentiates between special values
|
||||||
var parseVoteValue = function(voteObject, printLabel) {
|
var parseVoteValue = function(voteObject, printLabel) {
|
||||||
var voteVal = "";
|
var voteVal = '';
|
||||||
if (voteObject) {
|
if (voteObject) {
|
||||||
if (printLabel) {
|
if (printLabel) {
|
||||||
voteVal += voteObject.label + ": ";
|
voteVal += voteObject.label + ': ';
|
||||||
}
|
}
|
||||||
voteVal += voteObject.value;
|
voteVal += voteObject.value;
|
||||||
|
|
||||||
if (voteObject.percentStr) {
|
if (voteObject.percentStr) {
|
||||||
voteVal += " " + voteObject.percentStr;
|
voteVal += ' ' + voteObject.percentStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
voteVal += "\n";
|
voteVal += '\n';
|
||||||
return voteVal;
|
return voteVal;
|
||||||
};
|
};
|
||||||
|
|
||||||
// creates the election result table
|
// creates the election result table
|
||||||
var createPollResultTable = function() {
|
var createPollResultTable = function() {
|
||||||
var resultBody = [];
|
var resultBody = [];
|
||||||
angular.forEach(assignment.polls, function(poll, pollIndex) {
|
_.forEach(assignment.polls, function(poll, pollIndex) {
|
||||||
if (poll.published) {
|
if (poll.published) {
|
||||||
var pollTableBody = [];
|
var pollTableBody = [];
|
||||||
|
|
||||||
resultBody.push({
|
resultBody.push({
|
||||||
text: gettextCatalog.getString("Ballot") + " " + (pollIndex+1),
|
text: gettextCatalog.getString('Ballot') + ' ' + (pollIndex+1),
|
||||||
bold: true,
|
bold: true,
|
||||||
style: 'textItem',
|
style: 'textItem',
|
||||||
margin: [0, 15, 0, 0]
|
margin: [0, 15, 0, 0]
|
||||||
@ -145,16 +145,16 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
|
|
||||||
pollTableBody.push([
|
pollTableBody.push([
|
||||||
{
|
{
|
||||||
text: gettextCatalog.getString("Candidates"),
|
text: gettextCatalog.getString('Candidates'),
|
||||||
style: 'tableHeader',
|
style: 'tableHeader',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: gettextCatalog.getString("Votes"),
|
text: gettextCatalog.getString('Votes'),
|
||||||
style: 'tableHeader',
|
style: 'tableHeader',
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
angular.forEach(poll.options, function(pollOption, optionIndex) {
|
_.forEach(poll.options, function(pollOption, optionIndex) {
|
||||||
var candidateName = pollOption.candidate.get_full_name();
|
var candidateName = pollOption.candidate.get_full_name();
|
||||||
var votes = pollOption.getVotes(); // 0 = yes, 1 = no, 2 = abstain
|
var votes = pollOption.getVotes(); // 0 = yes, 1 = no, 2 = abstain
|
||||||
var tableLine = [];
|
var tableLine = [];
|
||||||
@ -169,7 +169,7 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
var resultBlock = [];
|
var resultBlock = [];
|
||||||
angular.forEach(votes, function(vote) {
|
_.forEach(votes, function(vote) {
|
||||||
resultBlock.push(parseVoteValue(vote, true));
|
resultBlock.push(parseVoteValue(vote, true));
|
||||||
});
|
});
|
||||||
tableLine.push({
|
tableLine.push({
|
||||||
@ -181,44 +181,26 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
pollTableBody.push(tableLine);
|
pollTableBody.push(tableLine);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (poll.votesvalid) {
|
var pushConcludeRow = function (title, fieldName) {
|
||||||
|
if (poll[fieldName]) {
|
||||||
pollTableBody.push([
|
pollTableBody.push([
|
||||||
{
|
{
|
||||||
text: gettextCatalog.getString("Valid ballots"),
|
text: gettextCatalog.getString(title),
|
||||||
style: 'tableConclude'
|
style: 'tableConclude'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: parseVoteValue(poll.getVote('votesvalid'), false),
|
text: parseVoteValue(poll.getVote(fieldName), false),
|
||||||
style: 'tableConclude'
|
style: 'tableConclude'
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (poll.votesinvalid) {
|
pushConcludeRow('Abstain', 'votesabstain');
|
||||||
pollTableBody.push([
|
pushConcludeRow('No', 'votesno');
|
||||||
{
|
pushConcludeRow('Valid ballots', 'votesvalid');
|
||||||
text: gettextCatalog.getString("Invalid ballots"),
|
pushConcludeRow('Invalid ballots', 'votesinvalid');
|
||||||
style: 'tableConclude'
|
pushConcludeRow('Casted ballots', 'votescast');
|
||||||
},
|
|
||||||
{
|
|
||||||
text: parseVoteValue(poll.getVote('votesinvalid'), false),
|
|
||||||
style: 'tableConclude'
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (poll.votescast) {
|
|
||||||
pollTableBody.push([
|
|
||||||
{
|
|
||||||
text: gettextCatalog.getString("Casted ballots"),
|
|
||||||
style: 'tableConclude'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: parseVoteValue(poll.getVote('votescast'), false),
|
|
||||||
style: 'tableConclude'
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultTableJsonSting = {
|
var resultTableJsonSting = {
|
||||||
table: {
|
table: {
|
||||||
@ -236,7 +218,7 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
// add the legend to the result body
|
// add the legend to the result body
|
||||||
if (assignment.polls.length > 0 && isElectedSemaphore) {
|
if (assignment.polls.length > 0 && isElectedSemaphore) {
|
||||||
resultBody.push({
|
resultBody.push({
|
||||||
text: "* = " + gettextCatalog.getString("is elected"),
|
text: '* = ' + gettextCatalog.getString('is elected'),
|
||||||
margin: [0, 5, 0, 0],
|
margin: [0, 5, 0, 0],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -366,12 +348,17 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
var candidateBallotList = [];
|
var candidateBallotList = [];
|
||||||
|
|
||||||
if (poll.pollmethod == 'votes') {
|
if (poll.pollmethod == 'votes') {
|
||||||
angular.forEach(candidates, function(option) {
|
_.forEach(candidates, function(option) {
|
||||||
var candidate = option.candidate.get_full_name();
|
var candidate = option.candidate.get_full_name();
|
||||||
candidateBallotList.push(PDFLayout.createBallotEntry(candidate));
|
candidateBallotList.push(PDFLayout.createBallotEntry(candidate));
|
||||||
});
|
});
|
||||||
|
// Add 'no' option
|
||||||
|
var no = gettextCatalog.getString('No');
|
||||||
|
var ballotEntry = PDFLayout.createBallotEntry(no);
|
||||||
|
ballotEntry.margin[1] = 25; // top margin
|
||||||
|
candidateBallotList.push(ballotEntry);
|
||||||
} else {
|
} else {
|
||||||
angular.forEach(candidates, function(option) {
|
_.forEach(candidates, function(option) {
|
||||||
var candidate;
|
var candidate;
|
||||||
if (option.candidate) {
|
if (option.candidate) {
|
||||||
candidate = option.candidate.get_full_name();
|
candidate = option.candidate.get_full_name();
|
||||||
@ -565,7 +552,7 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
};
|
};
|
||||||
|
|
||||||
var toc = [];
|
var toc = [];
|
||||||
angular.forEach(assignmentTitles, function(title) {
|
_.forEach(assignmentTitles, function(title) {
|
||||||
toc.push({
|
toc.push({
|
||||||
text: title,
|
text: title,
|
||||||
style: "tableofcontent"
|
style: "tableofcontent"
|
||||||
@ -656,7 +643,7 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
createBallotPdf: function (assignment, pollId) {
|
createBallotPdf: function (assignment, pollId) {
|
||||||
var thePoll;
|
var thePoll;
|
||||||
var pollNumber;
|
var pollNumber;
|
||||||
angular.forEach(assignment.polls, function(poll, pollIndex) {
|
_.forEach(assignment.polls, function(poll, pollIndex) {
|
||||||
if (poll.id == pollId) {
|
if (poll.id == pollId) {
|
||||||
thePoll = poll;
|
thePoll = poll;
|
||||||
pollNumber = pollIndex+1;
|
pollNumber = pollIndex+1;
|
||||||
|
@ -708,7 +708,7 @@ angular.module('OpenSlidesApp.assignments.site', [
|
|||||||
|
|
||||||
// add dynamic form fields
|
// add dynamic form fields
|
||||||
var options = $filter('orderBy')(assignmentpoll.options, 'weight');
|
var options = $filter('orderBy')(assignmentpoll.options, 'weight');
|
||||||
options.forEach(function(option) {
|
_.forEach(options, function(option) {
|
||||||
var defaultValue;
|
var defaultValue;
|
||||||
if (assignmentpoll.pollmethod == 'yna' || assignmentpoll.pollmethod == 'yn') {
|
if (assignmentpoll.pollmethod == 'yna' || assignmentpoll.pollmethod == 'yn') {
|
||||||
defaultValue = {};
|
defaultValue = {};
|
||||||
@ -783,8 +783,33 @@ angular.module('OpenSlidesApp.assignments.site', [
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (assignmentpoll.pollmethod == 'votes'){
|
||||||
|
$scope.formFields.push(
|
||||||
|
{
|
||||||
|
key: 'votesabstain',
|
||||||
|
type: 'input',
|
||||||
|
templateOptions: {
|
||||||
|
label: gettextCatalog.getString('Abstain'),
|
||||||
|
type: 'number',
|
||||||
|
min: -2,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'votesno',
|
||||||
|
type: 'input',
|
||||||
|
templateOptions: {
|
||||||
|
label: gettextCatalog.getString('No'),
|
||||||
|
type: 'number',
|
||||||
|
min: -2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
// add general form fields
|
// add general form fields
|
||||||
$scope.formFields.push(
|
$scope.formFields.push(
|
||||||
|
{
|
||||||
|
template: '<hr class="smallhr">',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'votesvalid',
|
key: 'votesvalid',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
@ -820,22 +845,22 @@ angular.module('OpenSlidesApp.assignments.site', [
|
|||||||
if (assignmentpoll.pollmethod == 'yna') {
|
if (assignmentpoll.pollmethod == 'yna') {
|
||||||
assignmentpoll.options.forEach(function(option) {
|
assignmentpoll.options.forEach(function(option) {
|
||||||
votes.push({
|
votes.push({
|
||||||
"Yes": poll['yes_' + option.candidate_id],
|
'Yes': poll['yes_' + option.candidate_id],
|
||||||
"No": poll['no_' + option.candidate_id],
|
'No': poll['no_' + option.candidate_id],
|
||||||
"Abstain": poll['abstain_' + option.candidate_id]
|
'Abstain': poll['abstain_' + option.candidate_id]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (assignmentpoll.pollmethod == 'yn') {
|
} else if (assignmentpoll.pollmethod == 'yn') {
|
||||||
assignmentpoll.options.forEach(function(option) {
|
assignmentpoll.options.forEach(function(option) {
|
||||||
votes.push({
|
votes.push({
|
||||||
"Yes": poll['yes_' + option.candidate_id],
|
'Yes': poll['yes_' + option.candidate_id],
|
||||||
"No": poll['no_' + option.candidate_id]
|
'No': poll['no_' + option.candidate_id]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
assignmentpoll.options.forEach(function(option) {
|
assignmentpoll.options.forEach(function(option) {
|
||||||
votes.push({
|
votes.push({
|
||||||
"Votes": poll['vote_' + option.candidate_id],
|
'Votes': poll['vote_' + option.candidate_id],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -843,9 +868,11 @@ angular.module('OpenSlidesApp.assignments.site', [
|
|||||||
poll.DSUpdate({
|
poll.DSUpdate({
|
||||||
assignment_id: poll.assignment_id,
|
assignment_id: poll.assignment_id,
|
||||||
votes: votes,
|
votes: votes,
|
||||||
|
votesabstain: poll.votesabstain,
|
||||||
|
votesno: poll.votesno,
|
||||||
votesvalid: poll.votesvalid,
|
votesvalid: poll.votesvalid,
|
||||||
votesinvalid: poll.votesinvalid,
|
votesinvalid: poll.votesinvalid,
|
||||||
votescast: poll.votescast
|
votescast: poll.votescast,
|
||||||
})
|
})
|
||||||
.then(function(success) {
|
.then(function(success) {
|
||||||
$scope.alert.show = false;
|
$scope.alert.show = false;
|
||||||
|
@ -195,10 +195,6 @@
|
|||||||
{{ option.candidate.get_full_name() }}
|
{{ option.candidate.get_full_name() }}
|
||||||
</a>
|
</a>
|
||||||
</ul>
|
</ul>
|
||||||
<strong translate>Election method</strong><br>
|
|
||||||
<span ng-if="poll.pollmethod == 'votes'" translate>One vote per candidate</span>
|
|
||||||
<span ng-if="poll.pollmethod == 'yna'" translate>Yes/No/Abstain per candidate</span>
|
|
||||||
<span ng-if="poll.pollmethod == 'yn'" translate>Yes/No per candidate</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Settings for majority calculations -->
|
<!-- Settings for majority calculations -->
|
||||||
@ -254,6 +250,18 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- total votes (valid/invalid/casts) -->
|
<!-- total votes (valid/invalid/casts) -->
|
||||||
|
<tr ng-if="poll.pollmethod === 'votes'">
|
||||||
|
<td>
|
||||||
|
<translate>Abstain</translate>
|
||||||
|
<td>
|
||||||
|
{{ poll.getVote('votesabstain').value }}
|
||||||
|
{{ poll.getVote('votesabstain').percentStr }}
|
||||||
|
<tr ng-if="poll.pollmethod === 'votes'">
|
||||||
|
<td>
|
||||||
|
<translate>No</translate>
|
||||||
|
<td>
|
||||||
|
{{ poll.getVote('votesno').value }}
|
||||||
|
{{ poll.getVote('votesno').percentStr }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<translate>Valid ballots</translate>
|
<translate>Valid ballots</translate>
|
||||||
@ -273,6 +281,11 @@
|
|||||||
{{ poll.getVote('votescast').value }}
|
{{ poll.getVote('votescast').value }}
|
||||||
{{ poll.getVote('votescast').percentStr }}
|
{{ poll.getVote('votescast').percentStr }}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<strong translate>Election method</strong><br>
|
||||||
|
<span ng-if="poll.pollmethod == 'votes'" translate>One vote per candidate</span>
|
||||||
|
<span ng-if="poll.pollmethod == 'yna'" translate>Yes/No/Abstain per candidate</span>
|
||||||
|
<span ng-if="poll.pollmethod == 'yn'" translate>Yes/No per candidate</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</uib-tab>
|
</uib-tab>
|
||||||
|
@ -63,7 +63,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- total votes (valid/invalid/casts) -->
|
<!-- total votes (abstain/no/valid/invalid/casts) -->
|
||||||
|
<tr class="total" ng-if="poll.has_votes && poll.pollmethod === 'votes' && poll.getVote('votesabstain').value !== null">
|
||||||
|
<td>
|
||||||
|
<translate>Abstain</translate>
|
||||||
|
<td ng-init="vote = poll.getVote('votesabstain')">
|
||||||
|
{{ vote.value }} {{ vote.percentStr }}
|
||||||
|
<tr class="total" ng-if="poll.has_votes && poll.pollmethod === 'votes' && poll.getVote('votesno').value !== null">
|
||||||
|
<td>
|
||||||
|
<translate>No</translate>
|
||||||
|
<td ng-init="vote = poll.getVote('votesno')">
|
||||||
|
{{ vote.value }} {{ vote.percentStr }}
|
||||||
<tr class="total" ng-if="poll.has_votes && poll.getVote('votesvalid').value !== null">
|
<tr class="total" ng-if="poll.has_votes && poll.getVote('votesvalid').value !== null">
|
||||||
<td>
|
<td>
|
||||||
<translate>Valid ballots</translate>
|
<translate>Valid ballots</translate>
|
||||||
|
Loading…
Reference in New Issue
Block a user