diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py index 1a9a5e9b4..efd6c0d63 100644 --- a/openslides/agenda/models.py +++ b/openslides/agenda/models.py @@ -185,7 +185,6 @@ class Item(RESTModelMixin, models.Model): An Agenda Item """ objects = ItemManager() - slide_callback_name = 'agenda' AGENDA_ITEM = 1 HIDDEN_ITEM = 2 diff --git a/openslides/agenda/static/js/agenda/base.js b/openslides/agenda/static/js/agenda/base.js index a45826445..ff58ee2f3 100644 --- a/openslides/agenda/static/js/agenda/base.js +++ b/openslides/agenda/static/js/agenda/base.js @@ -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() { diff --git a/openslides/assignments/models.py b/openslides/assignments/models.py index 4b448f2a8..2791343f0 100644 --- a/openslides/assignments/models.py +++ b/openslides/assignments/models.py @@ -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( diff --git a/openslides/assignments/projector.py b/openslides/assignments/projector.py index eff456960..30b360fce 100644 --- a/openslides/assignments/projector.py +++ b/openslides/assignments/projector.py @@ -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') diff --git a/openslides/assignments/static/js/assignments/base.js b/openslides/assignments/static/js/assignments/base.js index 35d595d02..22a63781e 100644 --- a/openslides/assignments/static/js/assignments/base.js +++ b/openslides/assignments/static/js/assignments/base.js @@ -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: { diff --git a/openslides/assignments/static/js/assignments/projector.js b/openslides/assignments/static/js/assignments/projector.js index 6c348f978..97c4d8490 100644 --- a/openslides/assignments/static/js/assignments/projector.js +++ b/openslides/assignments/static/js/assignments/projector.js @@ -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) { diff --git a/openslides/assignments/static/templates/assignments/assignment-detail.html b/openslides/assignments/static/templates/assignments/assignment-detail.html index d511348b7..fa5eda2dc 100644 --- a/openslides/assignments/static/templates/assignments/assignment-detail.html +++ b/openslides/assignments/static/templates/assignments/assignment-detail.html @@ -143,14 +143,22 @@ - + + | diff --git a/openslides/assignments/static/templates/assignments/slide_assignment.html b/openslides/assignments/static/templates/assignments/slide_assignment.html index f0c9afb41..e6ce4c5cb 100644 --- a/openslides/assignments/static/templates/assignments/slide_assignment.html +++ b/openslides/assignments/static/templates/assignments/slide_assignment.html @@ -19,13 +19,81 @@ -
{{ assignment.description }}
+
+ {{ assignment.description }} +
-

Candidates

-
    -
  1. - {{ related_user.user.get_full_name() }} - -
+
+

Candidates

+
    +
  1. + {{ related_user.user.get_full_name() }} + +
+
+ + +
+ + + + + + + + +
Candidates + Votes + + +
+ + {{ option.candidate.get_full_name() }} + + + +
+
+ + {{ votes[0].label }}: {{ votes[0].value }} · + {{ votes[1].label }}: {{ votes[1].value }} · + {{ votes[2].label }}: {{ votes[2].value }} + + + {{votes[0].percentNumber}} % + + + {{votes[1].percentNumber}} % + + + {{votes[2].percentNumber}} % + + +
+
+
+ {{ vote.value }} {{ vote.percentStr }} - {{vote.percentNumber}} +
+ +
+
+
+
+ + +
+ Valid votes + + {{ vote.value }} {{ vote.percent }} +
+ Invalid votes + + {{ vote.value }} +
+ Votes cast + + {{ vote.value }} {{ vote.percent }} +
+
diff --git a/openslides/core/static/css/projector.css b/openslides/core/static/css/projector.css index d0a745789..0af63ba20 100644 --- a/openslides/core/static/css/projector.css +++ b/openslides/core/static/css/projector.css @@ -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; } diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index 657e4b1c2..cb30f603a 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -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; } diff --git a/openslides/motions/models.py b/openslides/motions/models.py index 6c7983173..2c24416c9 100644 --- a/openslides/motions/models.py +++ b/openslides/motions/models.py @@ -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,