diff --git a/openslides/agenda/__init__.py b/openslides/agenda/__init__.py index c72be1dc6..320161958 100644 --- a/openslides/agenda/__init__.py +++ b/openslides/agenda/__init__.py @@ -6,7 +6,7 @@ The OpenSlides agenda app appends the functionality to OpenSlides to manage agendas. - It includes time-management and list of speakers. + It includes time-management and lists of speakers. :copyright: (c) 2011–2013 by the OpenSlides team, see AUTHORS. :license: GNU GPL, see LICENSE for more details. diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py index d2a027ecf..9de46ee4d 100644 --- a/openslides/agenda/models.py +++ b/openslides/agenda/models.py @@ -99,10 +99,44 @@ class Item(MPTTModel, SlideMixin): True, if the list of speakers is closed. """ + class Meta: + permissions = ( + ('can_see_agenda', ugettext_noop("Can see agenda")), + ('can_manage_agenda', ugettext_noop("Can manage agenda")), + ('can_see_orga_items', ugettext_noop("Can see orga items and time scheduling of agenda"))) + + class MPTTMeta: + order_insertion_by = ['weight'] + + def __unicode__(self): + return self.get_title() + + def get_absolute_url(self, link='view'): + """ + Return the URL to this item. By default it is the link to its + view or the view of a related object. + + The link can be: + * view + * edit + * delete + """ + if link == 'view': + if self.related_sid: + return self.get_related_slide().get_absolute_url(link) + return reverse('item_view', args=[str(self.id)]) + if link == 'edit': + if self.related_sid: + return self.get_related_slide().get_absolute_url(link) + return reverse('item_edit', args=[str(self.id)]) + if link == 'delete': + return reverse('item_delete', args=[str(self.id)]) + def get_related_slide(self): """ - return the object, of which the item points. + Return the object at which the item points. """ + # TODO: Rename it to 'get_related_object' object = get_slide_from_sid(self.related_sid, element=True) if object is None: self.title = 'Item for deleted slide: %s' % self.related_sid @@ -114,7 +148,7 @@ class Item(MPTTModel, SlideMixin): def get_related_type(self): """ - return the type of the releated slide. + Return the type of the releated slide. """ return self.get_related_slide().prefix @@ -129,7 +163,7 @@ class Item(MPTTModel, SlideMixin): def get_title(self): """ - return the title of this item. + Return the title of this item. """ if self.related_sid is None: return self.title @@ -137,7 +171,7 @@ class Item(MPTTModel, SlideMixin): def get_title_supplement(self): """ - return a supplement for the title. + Return a supplement for the title. """ if self.related_sid is None: return '' @@ -148,45 +182,36 @@ class Item(MPTTModel, SlideMixin): def slide(self): """ - Return a map with all Data for the Slide + Return a map with all data for the slide. + + There are four cases: + * summary slide + * list of speakers + * related slide, i. e. the slide of the related object + * normal slide of the item + + The method returns only one of them according to the config value + 'presentation_argument' and the attribut 'related_sid'. """ if config['presentation_argument'] == 'summary': - data = { - 'title': self.get_title(), - 'items': self.get_children(), - 'template': 'projector/AgendaSummary.html', - } + data = {'title': self.get_title(), + 'items': self.get_children(), + 'template': 'projector/AgendaSummary.html'} + elif config['presentation_argument'] == 'show_list_of_speakers': - - speaker_query = Speaker.objects.filter(item=self) - - coming_speakers = speaker_query.filter(begin_time=None).order_by('weight') - - old_speakers_count = config['agenda_show_last_speakers'] - if old_speakers_count > 0: - old_speakers = speaker_query.exclude(end_time=None) - old_speakers = old_speakers[max(0, old_speakers.count()) - old_speakers_count:] - else: - old_speakers = speaker_query.none() - - try: - actual_speaker = speaker_query.filter(end_time=None).exclude(begin_time=None).get() - except Speaker.DoesNotExist: - actual_speaker = None - speakers = list(old_speakers) + [actual_speaker] + list(coming_speakers) + list_of_speakers = self.get_list_of_speakers( + old_speakers_count=config['agenda_show_last_speakers']) data = {'title': self.get_title(), 'template': 'projector/agenda_list_of_speaker.html', - 'speakers': speakers, - 'actual_speaker': actual_speaker, - 'old_speakers_count': -(old_speakers_count + 1)} + 'list_of_speakers': list_of_speakers} elif self.related_sid: data = self.get_related_slide().slide() + else: - data = { - 'item': self, - 'title': self.get_title(), - 'template': 'projector/AgendaText.html', - } + data = {'item': self, + 'title': self.get_title(), + 'template': 'projector/AgendaText.html'} + return data def set_closed(self, closed=True): @@ -224,39 +249,67 @@ class Item(MPTTModel, SlideMixin): super(Item, self).delete() Item.objects.rebuild() - def get_absolute_url(self, link='view'): + def get_list_of_speakers(self, old_speakers_count=None, coming_speakers_count=None): """ - Return the URL to this item. By default it is the Link to its - slide - - link can be: - * view - * edit - * delete + Returns the list of speakers as a list of dictionaries. Each + dictionary contains a prefix, the speaker and its type. Types + are old_speaker, actual_speaker and coming_speaker. """ - if link == 'view': - if self.related_sid: - return self.get_related_slide().get_absolute_url(link) - return reverse('item_view', args=[str(self.id)]) - if link == 'edit': - if self.related_sid: - return self.get_related_slide().get_absolute_url(link) - return reverse('item_edit', args=[str(self.id)]) - if link == 'delete': - return reverse('item_delete', args=[str(self.id)]) + speaker_query = Speaker.objects.filter(item=self) + list_of_speakers = [] - def __unicode__(self): - return self.get_title() + # Parse old speakers + old_speakers = speaker_query.exclude(begin_time=None).exclude(end_time=None).order_by('end_time') + if old_speakers_count is None: + old_speakers_count = old_speakers.count() + last_old_speakers_count = max(0, old_speakers.count() - old_speakers_count) + old_speakers = old_speakers[last_old_speakers_count:] + for number, speaker in enumerate(old_speakers): + prefix = old_speakers_count - number + speaker_dict = { + 'prefix': '-%d' % prefix, + 'speaker': speaker, + 'type': 'old_speaker', + 'first_in_group': False, + 'last_in_group': False} + if number == 0: + speaker_dict['first_in_group'] = True + if number == old_speakers_count - 1: + speaker_dict['last_in_group'] = True + list_of_speakers.append(speaker_dict) - class Meta: - permissions = ( - ('can_see_agenda', ugettext_noop("Can see agenda")), - ('can_manage_agenda', ugettext_noop("Can manage agenda")), - ('can_see_orga_items', ugettext_noop("Can see orga items and time scheduling of agenda")), - ) + # Parse actual speaker + try: + actual_speaker = speaker_query.filter(end_time=None).exclude(begin_time=None).get() + except Speaker.DoesNotExist: + pass + else: + list_of_speakers.append({ + 'prefix': '0', + 'speaker': actual_speaker, + 'type': 'actual_speaker', + 'first_in_group': True, + 'last_in_group': True}) - class MPTTMeta: - order_insertion_by = ['weight'] + # Parse coming speakers + coming_speakers = speaker_query.filter(begin_time=None).order_by('weight') + if coming_speakers_count is None: + coming_speakers_count = coming_speakers.count() + coming_speakers = coming_speakers[:max(0, coming_speakers_count)] + for number, speaker in enumerate(coming_speakers): + speaker_dict = { + 'prefix': number + 1, + 'speaker': speaker, + 'type': 'coming_speaker', + 'first_in_group': False, + 'last_in_group': False} + if number == 0: + speaker_dict['first_in_group'] = True + if number == coming_speakers_count - 1: + speaker_dict['last_in_group'] = True + list_of_speakers.append(speaker_dict) + + return list_of_speakers class SpeakerManager(models.Manager): diff --git a/openslides/agenda/signals.py b/openslides/agenda/signals.py index d607b2a8b..e7f92afed 100644 --- a/openslides/agenda/signals.py +++ b/openslides/agenda/signals.py @@ -16,7 +16,7 @@ from django.utils.translation import ugettext_lazy, ugettext_noop, ugettext as _ from django.template.loader import render_to_string from openslides.config.signals import config_signal -from openslides.config.api import ConfigVariable, ConfigPage, config +from openslides.config.api import config, ConfigVariable, ConfigPage from openslides.projector.signals import projector_overlays from openslides.projector.projector import Overlay @@ -45,10 +45,10 @@ def setup_agenda_config_page(sender, **kwargs): agenda_show_last_speakers = ConfigVariable( name='agenda_show_last_speakers', - default_value=0, + default_value=1, form_field=forms.IntegerField( min_value=0, - label=_('Number of last speakers, to show on the projector'))) + label=_('Number of last speakers to be shown on the projector'))) extra_stylefiles = ['styles/timepicker.css', 'styles/jquery-ui/jquery-ui.custom.min.css'] extra_javascript = ['javascript/jquery-ui.custom.min.js', @@ -87,27 +87,10 @@ def agenda_list_of_speakers(sender, **kwargs): # Only show list of speakers on Agenda-Items return None clear_projector_cache() - - speaker_query = Speaker.objects.filter(item=slide) - try: - actual_speaker = speaker_query.filter(end_time=None).exclude(begin_time=None).get() - except Speaker.DoesNotExist: - actual_speaker = None - - coming_speakers = speaker_query.filter(begin_time=None)[:5] - - old_speakers_count = config['agenda_show_last_speakers'] - if old_speakers_count > 0: - old_speakers = speaker_query.exclude(end_time=None) - old_speakers = old_speakers[max(0, old_speakers.count()) - old_speakers_count:] - else: - old_speakers = speaker_query.none() - - speakers = list(old_speakers) + [actual_speaker] + list(coming_speakers) - context = { - 'actual_speaker': actual_speaker, - 'speakers': speakers, - 'old_speakers_count': -(old_speakers_count + 1)} + list_of_speakers = slide.get_list_of_speakers( + old_speakers_count=config['agenda_show_last_speakers'], + coming_speakers_count=5) + context = {'list_of_speakers': list_of_speakers} return render_to_string('agenda/overlay_speaker_projector.html', context) return Overlay(name, get_widget_html, get_projector_html) diff --git a/openslides/agenda/static/javascript/agenda.js b/openslides/agenda/static/javascript/agenda.js index fd12a897d..068f5fb2e 100644 --- a/openslides/agenda/static/javascript/agenda.js +++ b/openslides/agenda/static/javascript/agenda.js @@ -24,8 +24,8 @@ function hideClosedSlides(hide) { return false; } -$('#speaker_list_changed_form').submit(function() { - $('#sort_order').val($('#list_of_speakers').sortable("toArray")); +$('#coming_speakers_changed_form').submit(function() { + $('#sort_order').val($('#coming_speakers').sortable("toArray")); }); $(function() { @@ -76,10 +76,10 @@ $(function() { //# $('#hide_closed_items').attr('checked', true); //# } - if ($('#list_of_speakers').length > 0) { - $('#list_of_speakers').sortable({axis: "y", containment: "parent", update: function(event, ui) { - $('#speaker_list_changed_form').show(); + if ($('#coming_speakers').length > 0) { + $('#coming_speakers').sortable({axis: "y", containment: "parent", update: function(event, ui) { + $('#coming_speakers_changed_form').show(); }}); - $('#list_of_speakers').disableSelection(); + $('#coming_speakers').disableSelection(); } }); diff --git a/openslides/agenda/static/styles/agenda.css b/openslides/agenda/static/styles/agenda.css index f5d1e311b..682330f15 100644 --- a/openslides/agenda/static/styles/agenda.css +++ b/openslides/agenda/static/styles/agenda.css @@ -22,15 +22,15 @@ table#agendatime td { white-space: nowrap; } -#list_of_speakers li { - line-height: 30px; -} - -#list_of_speakers { +div#complete_list_of_speakers li { list-style-type: none; } -#list_of_speakers span.ui-icon { +div#complete_list_of_speakers li { + line-height: 30px; +} + +#coming_speakers span.ui-icon { position: absolute; margin-left: -15px; margin-top: 6px; diff --git a/openslides/agenda/templates/agenda/overlay_speaker_projector.html b/openslides/agenda/templates/agenda/overlay_speaker_projector.html index 362dbf4f7..287536aa0 100644 --- a/openslides/agenda/templates/agenda/overlay_speaker_projector.html +++ b/openslides/agenda/templates/agenda/overlay_speaker_projector.html @@ -35,18 +35,18 @@
- {% if speakers %} + {% if list_of_speakers %}

{% trans "List of speakers" %}: