Merge pull request #1964 from emanuelschuetze/assignmentpoll
Assignmentpoll slide
This commit is contained in:
commit
2d5f5c685c
@ -185,7 +185,6 @@ class Item(RESTModelMixin, models.Model):
|
||||
An Agenda Item
|
||||
"""
|
||||
objects = ItemManager()
|
||||
slide_callback_name = 'agenda'
|
||||
|
||||
AGENDA_ITEM = 1
|
||||
HIDDEN_ITEM = 2
|
||||
|
@ -81,15 +81,22 @@ angular.module('OpenSlidesApp.agenda', ['OpenSlidesApp.users'])
|
||||
},
|
||||
// override isProjected function of jsDataModel factory
|
||||
isProjected: function () {
|
||||
// Returns true if there is a projector element with the same
|
||||
// name and the same id.
|
||||
var projector = Projector.get(1);
|
||||
if (typeof projector === 'undefined') return false;
|
||||
var self = this;
|
||||
var predicate = function (element) {
|
||||
return element.name == self.content_object.collection &&
|
||||
typeof element.id !== 'undefined' &&
|
||||
element.id == self.content_object.id;
|
||||
};
|
||||
return typeof _.findKey(projector.elements, predicate) === 'string';
|
||||
var isProjected;
|
||||
if (typeof projector !== 'undefined') {
|
||||
var self = this;
|
||||
var predicate = function (element) {
|
||||
return element.name == self.content_object.collection &&
|
||||
typeof element.id !== 'undefined' &&
|
||||
element.id == self.content_object.id;
|
||||
};
|
||||
isProjected = typeof _.findKey(projector.elements, predicate) === 'string';
|
||||
} else {
|
||||
isProjected = false;
|
||||
}
|
||||
return isProjected;
|
||||
},
|
||||
// project list of speakers
|
||||
projectListOfSpeakers: function() {
|
||||
|
@ -49,7 +49,6 @@ class AssignmentRelatedUser(RESTModelMixin, models.Model):
|
||||
|
||||
|
||||
class Assignment(RESTModelMixin, models.Model):
|
||||
slide_callback_name = 'assignment'
|
||||
|
||||
PHASE_SEARCH = 0
|
||||
PHASE_VOTING = 1
|
||||
@ -345,7 +344,6 @@ class AssignmentOption(RESTModelMixin, BaseOption):
|
||||
|
||||
class AssignmentPoll(RESTModelMixin, CollectDefaultVotesMixin,
|
||||
PublishPollMixin, BasePoll):
|
||||
slide_callback_name = 'assignmentpoll'
|
||||
option_class = AssignmentOption
|
||||
|
||||
assignment = models.ForeignKey(
|
||||
|
@ -2,7 +2,7 @@ from openslides.core.exceptions import ProjectorException
|
||||
from openslides.core.views import TagViewSet
|
||||
from openslides.utils.projector import ProjectorElement, ProjectorRequirement
|
||||
|
||||
from .models import Assignment
|
||||
from .models import Assignment, AssignmentPoll
|
||||
from .views import AssignmentViewSet
|
||||
|
||||
|
||||
@ -20,6 +20,11 @@ class AssignmentSlide(ProjectorElement):
|
||||
# Detail slide.
|
||||
if not Assignment.objects.filter(pk=pk).exists():
|
||||
raise ProjectorException('Election does not exist.')
|
||||
poll_id = self.config_entry.get('poll')
|
||||
if poll_id is not None:
|
||||
# Poll slide.
|
||||
if not AssignmentPoll.objects.filter(pk=poll_id).exists():
|
||||
raise ProjectorException('Poll does not exist.')
|
||||
|
||||
def get_requirements(self, config_entry):
|
||||
pk = config_entry.get('id')
|
||||
|
@ -72,14 +72,21 @@ angular.module('OpenSlidesApp.assignments', [])
|
||||
])
|
||||
|
||||
.factory('AssignmentPoll', [
|
||||
'$http',
|
||||
'DS',
|
||||
'jsDataModel',
|
||||
'gettextCatalog',
|
||||
'AssignmentPollOption',
|
||||
'Config',
|
||||
function (DS, gettextCatalog, AssignmentPollOption, Config) {
|
||||
function ($http, DS, jsDataModel, gettextCatalog, AssignmentPollOption, Config) {
|
||||
var name = 'assignments/poll';
|
||||
return DS.defineResource({
|
||||
name: 'assignments/poll',
|
||||
name: name,
|
||||
useClass: jsDataModel,
|
||||
methods: {
|
||||
getResourceName: function () {
|
||||
return name;
|
||||
},
|
||||
// returns object with value and percent (for votes valid/invalid/cast only)
|
||||
getVote: function (vote) {
|
||||
if (!this.has_votes || !vote) {
|
||||
@ -148,11 +155,12 @@ angular.module('OpenSlidesApp.assignments', [])
|
||||
.factory('Assignment', [
|
||||
'$http',
|
||||
'DS',
|
||||
'Projector',
|
||||
'AssignmentRelatedUser',
|
||||
'AssignmentPoll',
|
||||
'jsDataModel',
|
||||
'gettext',
|
||||
function ($http, DS, AssignmentRelatedUser, AssignmentPoll, jsDataModel, gettext) {
|
||||
function ($http, DS, Projector, AssignmentRelatedUser, AssignmentPoll, jsDataModel, gettext) {
|
||||
var name = 'assignments/assignment';
|
||||
var phases;
|
||||
return DS.defineResource({
|
||||
@ -183,6 +191,45 @@ angular.module('OpenSlidesApp.assignments', [])
|
||||
// subtitle of search result
|
||||
getSearchResultSubtitle: function () {
|
||||
return "Election";
|
||||
},
|
||||
// override project function of jsDataModel factory
|
||||
project: function (poll_id) {
|
||||
return $http.post(
|
||||
'/rest/core/projector/1/prune_elements/',
|
||||
[{name: 'assignments/assignment', id: this.id, poll: poll_id}]
|
||||
);
|
||||
},
|
||||
// override isProjected function of jsDataModel factory
|
||||
isProjected: function (poll_id) {
|
||||
// Returns true if there is a projector element with the name
|
||||
// 'assignments/assignment'.
|
||||
var projector = Projector.get(1);
|
||||
var isProjected;
|
||||
if (typeof projector !== 'undefined') {
|
||||
var self = this;
|
||||
var predicate = function (element) {
|
||||
var value;
|
||||
if (typeof poll_id === 'undefined') {
|
||||
// Assignment detail slide without poll
|
||||
value = element.name == 'assignments/assignment' &&
|
||||
typeof element.id !== 'undefined' &&
|
||||
element.id == self.id &&
|
||||
typeof element.poll === 'undefined';
|
||||
} else {
|
||||
// Assignment detail slide with specific poll
|
||||
value = element.name == 'assignments/assignment' &&
|
||||
typeof element.id !== 'undefined' &&
|
||||
element.id == self.id &&
|
||||
typeof element.poll !== 'undefined' &&
|
||||
element.poll == poll_id;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
isProjected = typeof _.findKey(projector.elements, predicate) === 'string';
|
||||
} else {
|
||||
isProjected = false;
|
||||
}
|
||||
return isProjected;
|
||||
}
|
||||
},
|
||||
relations: {
|
||||
|
@ -22,6 +22,7 @@ angular.module('OpenSlidesApp.assignments.projector', ['OpenSlidesApp.assignment
|
||||
// Add it to the coresponding get_requirements method of the ProjectorElement
|
||||
// class.
|
||||
var id = $scope.element.id;
|
||||
var poll = $scope.element.poll;
|
||||
|
||||
// load assignemt object and related agenda item
|
||||
Assignment.find(id).then(function(assignment) {
|
||||
|
@ -143,14 +143,22 @@
|
||||
<button ng-if="!poll.published" ng-click="publishBallot(poll, true)"
|
||||
class="btn btn-default btn-sm">
|
||||
<i class="fa fa-toggle-off"></i>
|
||||
3. <translate>Publish ballot</translate>
|
||||
3. <translate>Publish</translate>
|
||||
</button>
|
||||
<button ng-if="poll.published" ng-click="publishBallot(poll, false)"
|
||||
class="btn btn-default btn-sm">
|
||||
<i class="fa fa-toggle-on"></i>
|
||||
<translate>Published</translate>
|
||||
3. <translate>Published</translate>
|
||||
</button>
|
||||
<a class="btn btn-danger btn-sm"
|
||||
<i class="fa fa-arrow-right"></i>
|
||||
<button os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
|
||||
ng-class="{ 'btn-primary': assignment.isProjected(poll.id) }"
|
||||
ng-click="assignment.project(poll.id)"
|
||||
title="{{ 'Project ballot' | translate }}">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
4. <translate>Project</translate>
|
||||
</button>
|
||||
| <a class="btn btn-danger btn-sm"
|
||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete this ballot?' | translate }}"
|
||||
ng-bootbox-confirm-action="deleteBallot(poll)">
|
||||
<i class="fa fa-times"></i>
|
||||
|
@ -19,13 +19,81 @@
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div class="white-space-pre-line">{{ assignment.description }}</div>
|
||||
<div ng-hide="element.poll" class="white-space-pre-line">
|
||||
{{ assignment.description }}
|
||||
</div>
|
||||
|
||||
<!-- Candidates -->
|
||||
<h3 translate>Candidates</h3>
|
||||
<ol>
|
||||
<li ng-repeat="related_user in assignment.assignment_related_users">
|
||||
{{ related_user.user.get_full_name() }}
|
||||
<i ng-if="related_user.elected" class="fa fa-star" title="{{ 'is elected' | translate }}"></i>
|
||||
</ol>
|
||||
<div ng-hide="element.poll">
|
||||
<h3 translate>Candidates</h3>
|
||||
<ol>
|
||||
<li ng-repeat="related_user in assignment.assignment_related_users">
|
||||
{{ related_user.user.get_full_name() }}
|
||||
<i ng-if="related_user.elected" class="fa fa-star" title="{{ 'is elected' | translate }}"></i>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- vote results -->
|
||||
<div ng-show="element.poll" class="electionresults spacer" ng-repeat="poll in assignment.polls | filter: {id: element.poll}">
|
||||
<table class="table table-bordered table-striped minimumTable">
|
||||
<tr>
|
||||
<th translate>Candidates
|
||||
<th ng-if="poll.has_votes" class="col-sm-6" translate>Votes
|
||||
|
||||
<!-- candidates (poll options) -->
|
||||
<tr ng-repeat="option in poll.options">
|
||||
|
||||
<!-- candidate name -->
|
||||
<td>
|
||||
<i ng-if="option.is_elected" class="fa fa-star" title="{{ 'is elected' | translate }}"></i>
|
||||
<strong>{{ option.candidate.get_full_name() }}</strong>
|
||||
|
||||
<!-- votes -->
|
||||
<td ng-if="poll.has_votes">
|
||||
<div ng-init="votes = option.getVotes()">
|
||||
<div ng-show="poll.yesnoabstain">
|
||||
<span>
|
||||
{{ votes[0].label }}: <strong>{{ votes[0].value }}</strong> ·
|
||||
{{ votes[1].label }}: {{ votes[1].value }} ·
|
||||
{{ votes[2].label }}: {{ votes[2].value }} </span>
|
||||
<uib-progress ng-if="votes[0].percentNumber">
|
||||
<uib-bar value="votes[0].percentNumber" type="success">
|
||||
<span ng-hide="votes[0].percentNumber < 5">{{votes[0].percentNumber}} %</span>
|
||||
</uib-bar>
|
||||
<uib-bar value="votes[1].percentNumber" type="danger">
|
||||
<span ng-hide="votes[1].percentNumber < 5">{{votes[1].percentNumber}} %</span>
|
||||
</uib-bar>
|
||||
<uib-bar value="votes[2].percentNumber" type="warning"></uib-bar>
|
||||
<span ng-hide="votes[2].percentNumber < 5">{{votes[2].percentNumber}} %</span>
|
||||
</uib-bar>
|
||||
</uib-progress>
|
||||
</div>
|
||||
<div ng-hide="poll.yesnoabstain">
|
||||
<div ng-repeat="vote in votes">
|
||||
{{ vote.value }} {{ vote.percentStr }} - {{vote.percentNumber}}
|
||||
<div ng-if="vote.percentNumber">
|
||||
<uib-progressbar value="vote.percentNumber" type="success"></uib-progressbar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- total votes (valid/invalid/casts) -->
|
||||
<tr class="total">
|
||||
<td>
|
||||
<translate>Valid votes</translate>
|
||||
<td ng-if="poll.has_votes" ng-init="vote = poll.getVote(poll.votesvalid)">
|
||||
{{ vote.value }} {{ vote.percent }}
|
||||
<tr class="total">
|
||||
<td>
|
||||
<translate>Invalid votes</translate>
|
||||
<td ng-if="poll.has_votes" ng-init="vote = poll.getVote(poll.votesinvalid)">
|
||||
{{ vote.value }}
|
||||
<tr class="total bg-info">
|
||||
<td>
|
||||
<translate>Votes cast</translate>
|
||||
<td ng-if="poll.has_votes" ng-init="vote = poll.getVote(poll.votescast)">
|
||||
{{ vote.value }} {{ vote.percent }}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -168,6 +168,12 @@ li {
|
||||
.result .bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.electionresults table {
|
||||
width: calc(100% - 230px);
|
||||
}
|
||||
.electionresults .progress {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
hr {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
@ -261,14 +261,19 @@ angular.module('OpenSlidesApp.core', [
|
||||
// Returns true if there is a projector element with the same
|
||||
// name and the same id.
|
||||
var projector = Projector.get(1);
|
||||
if (typeof projector === 'undefined') return false;
|
||||
var self = this;
|
||||
var predicate = function (element) {
|
||||
return element.name == self.getResourceName() &&
|
||||
typeof element.id !== 'undefined' &&
|
||||
element.id == self.id;
|
||||
};
|
||||
return typeof _.findKey(projector.elements, predicate) === 'string';
|
||||
var isProjected;
|
||||
if (typeof projector !== 'undefined') {
|
||||
var self = this;
|
||||
var predicate = function (element) {
|
||||
return element.name == self.getResourceName() &&
|
||||
typeof element.id !== 'undefined' &&
|
||||
element.id == self.id;
|
||||
};
|
||||
isProjected = typeof _.findKey(projector.elements, predicate) === 'string';
|
||||
} else {
|
||||
isProjected = false;
|
||||
}
|
||||
return isProjected;
|
||||
};
|
||||
return BaseModel;
|
||||
}
|
||||
|
@ -30,11 +30,6 @@ class Motion(RESTModelMixin, models.Model):
|
||||
This class is the main entry point to all other classes related to a motion.
|
||||
"""
|
||||
|
||||
slide_callback_name = 'motion'
|
||||
"""
|
||||
Name of the callback for the slide-system.
|
||||
"""
|
||||
|
||||
active_version = models.ForeignKey(
|
||||
'MotionVersion',
|
||||
on_delete=models.SET_NULL,
|
||||
@ -738,9 +733,6 @@ class MotionOption(RESTModelMixin, BaseOption):
|
||||
class MotionPoll(RESTModelMixin, CollectDefaultVotesMixin, BasePoll):
|
||||
"""The Class to saves the vote result for a motion poll."""
|
||||
|
||||
slide_callback_name = 'motionpoll'
|
||||
"""Name of the callback for the slide-system."""
|
||||
|
||||
motion = models.ForeignKey(
|
||||
Motion,
|
||||
on_delete=models.CASCADE,
|
||||
|
Loading…
Reference in New Issue
Block a user