diff --git a/openslides/participant/views.py b/openslides/participant/views.py index 4255806e8..82058ee63 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -241,7 +241,7 @@ class ParticipantsPasswordsPDF(PDFView): img_stream = StringIO() qrcode_img.save(img_stream, 'PNG') img_stream.seek(0) - size = 2*cm + size = 2 * cm I = Image(img_stream, width=size, height=size) for user in User.objects.all().order_by(sort): cell = [] diff --git a/openslides/projector/api.py b/openslides/projector/api.py index 13035d916..9e634a076 100644 --- a/openslides/projector/api.py +++ b/openslides/projector/api.py @@ -120,28 +120,6 @@ def register_slidefunc(key, func, control_template=None, weight=0, name=''): name=name,) -def projector_message_set(message, sid=None): - """ - Set the overlay-message. - if sid is set, only show the message on the sid-slide. - """ - from models import ProjectorOverlay - config['projector_message'] = message - try: - overlay = ProjectorOverlay.objects.get(def_name='Message') - except ProjectorOverlay.DoesNotExist: - overlay = ProjectorOverlay(def_name='Message', active=False) - overlay.sid = sid - overlay.save() - - -def projector_message_delete(): - """ - Delete the overlay-message. - """ - config['projector_message'] = '' - - def get_all_widgets(request, session=False): widgets = SortedDict() session_widgets = request.session.get('widgets', {}) diff --git a/openslides/projector/models.py b/openslides/projector/models.py index e2260cf2a..8705181c3 100644 --- a/openslides/projector/models.py +++ b/openslides/projector/models.py @@ -54,17 +54,3 @@ class ProjectorSlide(models.Model, SlideMixin): register_slidemodel(ProjectorSlide, control_template='projector/control_customslide.html') - - -class ProjectorOverlay(models.Model): - """ - Save information for a overlay. - """ - active = models.BooleanField(verbose_name=_('Active')) - def_name = models.CharField(max_length=64) - sid = models.CharField(max_length=64, null=True, blank=True) - - def __unicode__(self): - if self.sid: - return "%s on %s" % (self.def_name, self.sid) - return self.def_name diff --git a/openslides/projector/projector.py b/openslides/projector/projector.py index ba6b930ea..537bfc40d 100644 --- a/openslides/projector/projector.py +++ b/openslides/projector/projector.py @@ -16,7 +16,6 @@ from django.dispatch import receiver from django.template.loader import render_to_string from openslides.config.api import config -from openslides.projector.signals import projector_overlays SLIDE = {} @@ -146,35 +145,26 @@ class Widget(object): return unicode(self.display_name) -@receiver(projector_overlays, dispatch_uid="projector_countdown") -def countdown(sender, **kwargs): - name = 'Countdown' - if kwargs['register']: - return name - if name in kwargs['call']: - if config['countdown_state'] == 'active': - seconds = max(0, int(config['countdown_start_stamp'] + config['countdown_time'] - time())) - elif config['countdown_state'] == 'paused': - seconds = max(0, int(config['countdown_start_stamp'] + config['countdown_time'] - config['countdown_pause_stamp'])) - elif config['countdown_state'] == 'inactive': - seconds = max(0, int(config['countdown_time'])) - else: - seconds = 0 +class Overlay(object): + """ + Represents an overlay which can be seen on the projector. + """ - if seconds == 0: - config['countdown_state'] = 'expired' + def __init__(self, name, get_widget_html, get_projector_html): + self.name = name + self.widget_html_callback = get_widget_html + self.projector_html_callback = get_projector_html - return (name, '%02d:%02d' % (seconds / 60, seconds % 60)) - return None + def get_widget_html(self): + return self.widget_html_callback() + def get_projector_html(self): + try: + return self._projector_html + except AttributeError: + self._projector_html = self.projector_html_callback() + return self.get_projector_html() -@receiver(projector_overlays, dispatch_uid="projector_message") -def projector_message(sender, **kwargs): - name = 'Message' - if kwargs['register']: - return name - if name in kwargs['call']: - message = config['projector_message'] - if message != '': - return (name, message) - return None + def is_active(self): + return (self.name in config['projector_active_overlays'] and + self.get_projector_html() is not None) diff --git a/openslides/projector/signals.py b/openslides/projector/signals.py index af38e4596..b8136e797 100644 --- a/openslides/projector/signals.py +++ b/openslides/projector/signals.py @@ -9,16 +9,22 @@ :copyright: 2011–2013 by OpenSlides team, see AUTHORS. :license: GNU GPL, see LICENSE for more details. """ +from time import time from django.dispatch import Signal, receiver from django import forms from django.utils.translation import ugettext_lazy, ugettext as _ +from django.template.loader import render_to_string +from django.core.context_processors import csrf +from openslides.config.api import config from openslides.config.signals import config_signal from openslides.config.api import ConfigVariable, ConfigPage +from .projector import Overlay -projector_overlays = Signal(providing_args=['register', 'call']) + +projector_overlays = Signal(providing_args=['request']) @receiver(config_signal, dispatch_uid='setup_projector_config_variables') @@ -64,8 +70,80 @@ def setup_projector_config_variables(sender, **kwargs): name='up', default_value=0) - return ConfigPage(title='No title here', - url='bar', - required_permission=None, - variables=(presentation, presentation_argument, projector_message, countdown_time, - countdown_start_stamp, countdown_pause_stamp, countdown_state, bigger, up)) + projector_active_overlays = ConfigVariable( + name='projector_active_overlays', + default_value=[]) + + return ConfigPage( + title='No title here', url='bar', required_permission=None, variables=( + presentation, presentation_argument, projector_message, + countdown_time, countdown_start_stamp, countdown_pause_stamp, + countdown_state, bigger, up, projector_active_overlays)) + + +@receiver(projector_overlays, dispatch_uid="projector_countdown") +def countdown(sender, **kwargs): + """ + Reveiver for the countdown. + """ + name = 'projector_countdown' + request = kwargs.get('request', None) + + def get_widget_html(): + """ + Returns the the html-code to show in the overly-widget. + """ + context = { + 'countdown_time': config['countdown_time'], + 'countdown_state': config['countdown_state']} + context.update(csrf(request)) + return render_to_string('projector/overlay_countdown_widget.html', context) + + def get_projector_html(): + """ + Returns an html-code to show on the projector. + """ + start = config['countdown_start_stamp'] + duration = config['countdown_time'] + pause = config['countdown_pause_stamp'] + if config['countdown_state'] == 'active': + seconds = max(0, int(start + duration - time())) + elif config['countdown_state'] == 'paused': + seconds = max(0, int(start + duration - pause)) + elif config['countdown_state'] == 'inactive': + seconds = max(0, int(duration)) + else: + seconds = 0 + if seconds == 0: + config['countdown_state'] = 'expired' + return render_to_string('projector/overlay_countdown_projector.html', + {'seconds': '%02d:%02d' % (seconds / 60, seconds % 60)}) + + return Overlay(name, get_widget_html, get_projector_html) + + +@receiver(projector_overlays, dispatch_uid="projector_message") +def projector_message(sender, **kwargs): + """ + Receiver to show the overlay_message on the projector or the form in the + overlay-widget on the dashboard. + """ + name = 'projector_message' + request = kwargs.get('request', None) + + def get_widget_html(): + """ + Returns the the html-code to show in the overly-widget. + """ + return render_to_string('projector/overlay_message_widget.html', csrf(request)) + + def get_projector_html(): + """ + Returns an html-code to show on the projector. + """ + if config['projector_message']: + return render_to_string('projector/overlay_message_projector.html', + {'message': config['projector_message']}) + return None + + return Overlay(name, get_widget_html, get_projector_html) diff --git a/openslides/projector/static/javascript/dashboard.js b/openslides/projector/static/javascript/dashboard.js index 454accbff..c1aed73be 100644 --- a/openslides/projector/static/javascript/dashboard.js +++ b/openslides/projector/static/javascript/dashboard.js @@ -88,11 +88,11 @@ $(function() { dataType: 'json', success: function(data) { if (data['active']) { - $('#' + data['def_name'] + '_active').show(); - $('#' + data['def_name'] + '_inactive').hide(); + $('#' + data['name'] + '_active').show(); + $('#' + data['name'] + '_inactive').hide(); } else { - $('#' + data['def_name'] + '_active').hide(); - $('#' + data['def_name'] + '_inactive').show(); + $('#' + data['name'] + '_active').hide(); + $('#' + data['name'] + '_inactive').show(); } } }); diff --git a/openslides/projector/static/javascript/projector.js b/openslides/projector/static/javascript/projector.js index 4e0ee8714..9078dd148 100644 --- a/openslides/projector/static/javascript/projector.js +++ b/openslides/projector/static/javascript/projector.js @@ -8,7 +8,6 @@ content_hash = null; function presentation_reload() { - if ($('#config > #ajax').html() == 'on') { $.ajax({ type: 'GET', @@ -33,11 +32,8 @@ function presentation_reload() { $('#scrollcontent').animate({'margin-top': data.up + 'em'}, 200); // overlays $('#overlays div').remove(); - $('#overlays span').remove(); - $.each(data['overlays'], function (index, value){ - if (value[0] != "Countdown") - $('#overlays').append('') - $('#overlays').append('
' + value[1] + '
'); + $.each(data['overlays'], function (index, overlay){ + $('#overlays').append('
' + overlay['html'] + '
'); }); setTimeout("presentation_reload()", 1000); }, diff --git a/openslides/projector/static/styles/projector.css b/openslides/projector/static/styles/projector.css index 2f22b4550..b956d7b6d 100644 --- a/openslides/projector/static/styles/projector.css +++ b/openslides/projector/static/styles/projector.css @@ -73,32 +73,6 @@ body{ width: 100%; height: 100%; } -#overlays div { -} - -#overlay_Countdown { - position: absolute; - right: 40px; - top: 0; - font-size: 4em; - font-weight: bold; - border-bottom-left-radius: 0.5em; - border-bottom-right-radius: 0.5em; - background: #DDD9D9; - padding: 0 1em; -} - -#overlay_Message { - position: absolute; - top: 35%; - left: 10%; - width: 80%; - text-align: center; - border-radius: 0.2em; - background: #FFFFFF; - font-size: 2.75em; - padding: 0.2em 0; -} /*** CONTENT ***/ #contentwrapper { diff --git a/openslides/projector/templates/base-projector.html b/openslides/projector/templates/base-projector.html index af2845b92..d75172e31 100644 --- a/openslides/projector/templates/base-projector.html +++ b/openslides/projector/templates/base-projector.html @@ -32,10 +32,9 @@
{% for overlay in overlays %} - {% if overlay.0 != "Countdown" %} - - {% endif %} -
{{ overlay.1|safe }}
+
+ {{ overlay.html|safe }} +
{% endfor %}
diff --git a/openslides/projector/templates/projector/control_countdown.html b/openslides/projector/templates/projector/control_countdown.html deleted file mode 100644 index 837666093..000000000 --- a/openslides/projector/templates/projector/control_countdown.html +++ /dev/null @@ -1,21 +0,0 @@ -{% load i18n %} -{% load tags %} - -
-
- - {% trans "s" context "seconds" %} -
- - - - - - - - -
diff --git a/openslides/projector/templates/projector/control_overlay_message.html b/openslides/projector/templates/projector/control_overlay_message.html deleted file mode 100644 index ee10ace99..000000000 --- a/openslides/projector/templates/projector/control_overlay_message.html +++ /dev/null @@ -1,14 +0,0 @@ -{% load i18n %} -{% load tags %} - -
{% csrf_token %} -
- - - -
-
diff --git a/openslides/projector/templates/projector/overlay_countdown_projector.html b/openslides/projector/templates/projector/overlay_countdown_projector.html new file mode 100644 index 000000000..48eeb8cbd --- /dev/null +++ b/openslides/projector/templates/projector/overlay_countdown_projector.html @@ -0,0 +1,17 @@ + + +
+ {{ seconds }} +
diff --git a/openslides/projector/templates/projector/overlay_countdown_widget.html b/openslides/projector/templates/projector/overlay_countdown_widget.html new file mode 100644 index 000000000..902be3666 --- /dev/null +++ b/openslides/projector/templates/projector/overlay_countdown_widget.html @@ -0,0 +1,24 @@ +{% load i18n %} +{% load tags %} + + + {% trans "Countdown for speaking time" %}: +
+
+ + {% trans "s" context "seconds" %} +
+ + + + + + + + +
+
diff --git a/openslides/projector/templates/projector/overlay_message_projector.html b/openslides/projector/templates/projector/overlay_message_projector.html new file mode 100644 index 000000000..7178e84ad --- /dev/null +++ b/openslides/projector/templates/projector/overlay_message_projector.html @@ -0,0 +1,19 @@ + + + + +
+ {{ message }} + diff --git a/openslides/projector/templates/projector/overlay_message_widget.html b/openslides/projector/templates/projector/overlay_message_widget.html new file mode 100644 index 000000000..813c10ceb --- /dev/null +++ b/openslides/projector/templates/projector/overlay_message_widget.html @@ -0,0 +1,17 @@ +{% load i18n %} +{% load tags %} + + + {% trans "Message" %}: +
{% csrf_token %} +
+ + + +
+
+
diff --git a/openslides/projector/templates/projector/overlay_widget.html b/openslides/projector/templates/projector/overlay_widget.html index b0cb79205..006136248 100644 --- a/openslides/projector/templates/projector/overlay_widget.html +++ b/openslides/projector/templates/projector/overlay_widget.html @@ -4,28 +4,19 @@ diff --git a/openslides/projector/views.py b/openslides/projector/views.py index 13f7c9faa..76a92561d 100644 --- a/openslides/projector/views.py +++ b/openslides/projector/views.py @@ -28,11 +28,10 @@ from openslides.utils.views import ( TemplateView, RedirectView, CreateView, UpdateView, DeleteView, AjaxMixin) from openslides.config.api import config from .api import ( - get_active_slide, set_active_slide, projector_message_set, - projector_message_delete, get_slide_from_sid, get_all_widgets, + get_active_slide, set_active_slide, get_slide_from_sid, get_all_widgets, clear_projector_cache) from .forms import SelectWidgetsForm -from .models import ProjectorOverlay, ProjectorSlide +from .models import ProjectorSlide from .projector import Widget from .signals import projector_overlays @@ -80,18 +79,17 @@ class Projector(TemplateView, AjaxMixin): 'title': config['event_name'], 'template': 'projector/default.html', } - data['overlays'] = [] data['ajax'] = ajax - # Projector Overlays + # Projector overlays + data['overlays'] = [] + # Do not show overlays on slide preview if self.kwargs['sid'] is None: - active_defs = ProjectorOverlay.objects.filter(active=True) \ - .filter(Q(sid=active_sid) | Q(sid=None)).values_list( - 'def_name', flat=True) - for receiver, response in projector_overlays.send( - sender=sid, register=False, call=active_defs): - if response is not None: - data['overlays'].append(response) + for receiver, overlay in projector_overlays.send(sender=self): + if overlay.is_active(): + data['overlays'].append({'name': overlay.name, + 'html': overlay.get_projector_html()}) + self._data = data return data @@ -290,9 +288,9 @@ class OverlayMessageView(RedirectView): def pre_post_redirect(self, request, *args, **kwargs): if 'message' in request.POST: - projector_message_set(request.POST['message_text']) + config['projector_message'] = request.POST['message_text'] elif 'message-clean' in request.POST: - projector_message_delete() + config['projector_message'] = '' def get_ajax_context(self, **kwargs): clear_projector_cache() @@ -309,28 +307,23 @@ class ActivateOverlay(RedirectView): allow_ajax = True permission_required = 'projector.can_manage_projector' - @property - def overlay(self): - try: - return self._overlay - except AttributeError: - self._overlay = ProjectorOverlay.objects.get( - def_name=self.kwargs['name']) - return self._overlay - def pre_redirect(self, request, *args, **kwargs): + self.name = kwargs['name'] + active_overlays = config['projector_active_overlays'] if kwargs['activate']: - self.overlay.active = True - else: - self.overlay.active = False - self.overlay.save() + if self.name not in active_overlays: + active_overlays.append(self.name) + config['projector_active_overlays'] = active_overlays + self.active = True + elif not kwargs['activate']: + if self.name in active_overlays: + active_overlays.remove(self.name) + config['projector_active_overlays'] = active_overlays + self.active = False def get_ajax_context(self, **kwargs): clear_projector_cache() - return { - 'active': self.overlay.active, - 'def_name': self.overlay.def_name, - } + return {'active': self.active, 'name': self.name} class CustomSlideCreateView(CreateView): @@ -406,21 +399,10 @@ def get_widgets(request): # Overlay Widget overlays = [] - for receiver, name in projector_overlays.send(sender='registerer', - register=True): - if name is not None: - try: - projector_overlay = ProjectorOverlay.objects.get( - def_name=name) - except ProjectorOverlay.DoesNotExist: - projector_overlay = ProjectorOverlay(def_name=name, active=False) - projector_overlay.save() - overlays.append(projector_overlay) + for receiver, overlay in projector_overlays.send(sender='overlay_widget', request=request): + overlays.append(overlay) - context = { - 'overlays': overlays, - 'countdown_time': config['countdown_time'], - 'countdown_state': config['countdown_state']} + context = {'overlays': overlays} context.update(csrf(request)) widgets.append(Widget( name='overlays',