diff --git a/CHANGELOG b/CHANGELOG index 3f14ccdc0..c8661eec5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -21,6 +21,7 @@ Core: - Added HTML support for messages on the projector. - Moved custom slides to own app "topics". Renamed it to "Topic". - Added support for multiple projectors. +- Added an overlay for the current list of speakers. Motions: - Added origin field. diff --git a/openslides/agenda/projector.py b/openslides/agenda/projector.py index e8ce31f5d..db1b10e52 100644 --- a/openslides/agenda/projector.py +++ b/openslides/agenda/projector.py @@ -1,5 +1,6 @@ from ..core.config import config from ..core.exceptions import ProjectorException +from ..core.models import Projector from ..utils.collection import CollectionElement from ..utils.projector import ProjectorElement from .models import Item @@ -32,7 +33,6 @@ class ItemListSlide(ProjectorElement): class ListOfSpeakersSlide(ProjectorElement): """ Slide definitions for Item model. - This is only for list of speakers slide. You have to set 'id'. """ name = 'agenda/list-of-speakers' @@ -69,31 +69,56 @@ class ListOfSpeakersSlide(ProjectorElement): output.extend(self.get_requirements_as_collection_elements(config_entry)) return output + def update_data(self): + return {'agenda_item_id': self.config_entry.get('id')} -class CurrentListOfSpeakersSlide(ProjectorElement): + +class CurrentListOfSpeakersMetaClass(ProjectorElement): + """ + Main class for the list of speaker slides. + + """ + def get_requirements(self, config_entry): + items = self.get_agenda_items(config['projector_currentListOfSpeakers_reference']) + for item in items: + yield item + for speaker in item.speakers.filter(end_time=None): + yield speaker.user + query = (item.speakers.exclude(end_time=None) + .order_by('-end_time')[:config['agenda_show_last_speakers']]) + for speaker in query: + # Yield last speakers + yield speaker.user + + def get_agenda_items(self, projector_id): + projector = Projector.objects.get(pk=projector_id) + for element in projector.elements.values(): + agenda_item_id = element.get('agenda_item_id') + if agenda_item_id is not None: + yield Item.objects.get(pk=agenda_item_id) + + def get_collection_elements_required_for_this(self, collection_element, config_entry): + output = super().get_collection_elements_required_for_this(collection_element, config_entry) + # Full update if agenda_item changes because then we may have new + # candidates and therefor need new users. + items = self.get_agenda_items(config['projector_currentListOfSpeakers_reference']) + for item in items: + if collection_element == CollectionElement.from_values(item.get_collection_string(), item.pk): + output.extend(self.get_requirements_as_collection_elements(config_entry)) + break + return output + + +class CurrentListOfSpeakersSlide(CurrentListOfSpeakersMetaClass): """ Slide for the current list of speakers. - - Nothing special to check. """ name = 'agenda/current-list-of-speakers' - def get_requirements(self, config_entry): - pk = config['projector_currentListOfSpeakers_reference'] - if pk is not None: - # List of speakers slide. - try: - item = Item.objects.get(pk=pk) - except Item.DoesNotExist: - # Item does not exist. Just do nothing. - pass - else: - yield item - for speaker in item.speakers.filter(end_time=None): - # Yield current speaker and next speakers - yield speaker.user - query = (item.speakers.exclude(end_time=None) - .order_by('-end_time')[:config['agenda_show_last_speakers']]) - for speaker in query: - # Yield last speakers - yield speaker.user + +class CurrentListOfSpeakersOverlaySlide(CurrentListOfSpeakersMetaClass): + """ + List of speakers overlay. + Subclass of ListOfSpeakers + """ + name = 'agenda/current-list-of-speakers-overlay' diff --git a/openslides/agenda/static/js/agenda/base.js b/openslides/agenda/static/js/agenda/base.js index b0302d2ed..e4be45c88 100644 --- a/openslides/agenda/static/js/agenda/base.js +++ b/openslides/agenda/static/js/agenda/base.js @@ -298,7 +298,7 @@ angular.module('OpenSlidesApp.agenda', ['OpenSlidesApp.users']) 'Agenda', function (Projector, Assignment, Topic, Motion, Agenda) { return { - getItem: function (projectorId) { + getItem: function (projectorId) { var elementPromise; return Projector.find(projectorId).then(function (projector) { // scan all elements @@ -338,6 +338,59 @@ angular.module('OpenSlidesApp.agenda', ['OpenSlidesApp.users']) } ]) +.factory('ListOfSpeakersOverlay', [ + '$http', + 'Projector', + 'gettextCatalog', + 'gettext', + function($http, Projector, gettextCatalog, gettext) { + var name = 'agenda/current-list-of-speakers-overlay'; + return { + name: name, + verboseName: gettext('List of speakers overlay'), + project: function (projectorId, overlay) { + var isProjectedId = this.isProjected(overlay); + if (isProjectedId > 0) { + // Deactivate + var projector = Projector.get(isProjectedId); + var uuid; + _.forEach(projector.elements, function (element) { + if (element.name == 'agenda/current-list-of-speakers-overlay') { + uuid = element.uuid; + } + }); + $http.post('/rest/core/projector/' + isProjectedId + '/deactivate_elements/', + [uuid]); + } + // Activate, if the projector_id is a new projector. + if (isProjectedId != projectorId) { + return $http.post( + '/rest/core/projector/' + projectorId + '/activate_elements/', + [{name: 'agenda/current-list-of-speakers-overlay',stable: true}]); + } + }, + isProjected: function (additionalId) { + // Returns the id of the last projector with an agenda-item element. Else return 0. + // additionalId is not needed + var isProjected = 0; + var predicate = function (element) { + var value; + value = element.name == 'agenda/current-list-of-speakers-overlay'; + return value; + }; + Projector.getAll().forEach(function (projector) { + if (typeof _.findKey(projector.elements, predicate) === 'string') { + isProjected = projector.id; + } + }); + return isProjected; + } + }; + } +]) + + + // Make sure that the Agenda resource is loaded. .run(['Agenda', function(Agenda) {}]); diff --git a/openslides/agenda/static/js/agenda/projector.js b/openslides/agenda/static/js/agenda/projector.js index 074ed90b1..83dccbea7 100644 --- a/openslides/agenda/static/js/agenda/projector.js +++ b/openslides/agenda/static/js/agenda/projector.js @@ -16,6 +16,9 @@ angular.module('OpenSlidesApp.agenda.projector', ['OpenSlidesApp.agenda']) slidesProvider.registerSlide('agenda/current-list-of-speakers', { template: 'static/templates/agenda/slide-current-list-of-speakers.html', }); + slidesProvider.registerSlide('agenda/current-list-of-speakers-overlay', { + template: 'static/templates/agenda/slide-current-list-of-speakers-overlay.html', + }); } ]) diff --git a/openslides/agenda/static/templates/agenda/slide-current-list-of-speakers-overlay.html b/openslides/agenda/static/templates/agenda/slide-current-list-of-speakers-overlay.html new file mode 100644 index 000000000..02de80af5 --- /dev/null +++ b/openslides/agenda/static/templates/agenda/slide-current-list-of-speakers-overlay.html @@ -0,0 +1,19 @@ +
+ {{ speaker.user.get_full_name() }} +
+ {{ speaker.user.get_full_name() }} +
+ + {{ nextSpeakers.length - 3 }} +