Merge pull request #899 from ostcar/projector

Added projector.api.register_slide_model
This commit is contained in:
Oskar Hahn 2013-10-10 09:49:46 -07:00
commit a9487c22a7
15 changed files with 195 additions and 180 deletions

View File

@ -18,22 +18,31 @@ from django.utils.datastructures import SortedDict
from openslides.utils.person import PersonField from openslides.utils.person import PersonField
from openslides.utils.utils import html_strong from openslides.utils.utils import html_strong
from openslides.config.api import config from openslides.config.api import config
from openslides.projector.models import SlideMixin from openslides.projector.models import SlideMixin, RelatedModelMixin
from openslides.poll.models import ( from openslides.poll.models import (
BasePoll, CountInvalid, CountVotesCast, BaseOption, PublishPollMixin, BaseVote) BasePoll, CountInvalid, CountVotesCast, BaseOption, PublishPollMixin, BaseVote)
class AssignmentCandidate(models.Model): class AssignmentCandidate(RelatedModelMixin, models.Model):
"""
Many2Many table between an assignment and the candidates.
"""
assignment = models.ForeignKey("Assignment") assignment = models.ForeignKey("Assignment")
person = PersonField(db_index=True) person = PersonField(db_index=True)
elected = models.BooleanField(default=False) elected = models.BooleanField(default=False)
blocked = models.BooleanField(default=False) blocked = models.BooleanField(default=False)
class Meta:
unique_together = ("assignment", "person")
def __unicode__(self): def __unicode__(self):
return unicode(self.person) return unicode(self.person)
class Meta: def get_related_model(self):
unique_together = ("assignment", "person") """
Returns the assignment
"""
return self.assignment
class Assignment(SlideMixin, models.Model): class Assignment(SlideMixin, models.Model):
@ -74,6 +83,12 @@ class Assignment(SlideMixin, models.Model):
return reverse('assignment_delete', args=[str(self.id)]) return reverse('assignment_delete', args=[str(self.id)])
return super(Assignment, self).get_absolute_url(link) return super(Assignment, self).get_absolute_url(link)
def get_slide_context(self, **context):
context.update({
'polls': self.poll_set.filter(published=True),
'vote_results': self.vote_results(only_published=True)})
return super(Assignment, self).get_slide_context(**context)
def set_status(self, status): def set_status(self, status):
status_dict = dict(self.STATUS) status_dict = dict(self.STATUS)
if status not in status_dict: if status not in status_dict:
@ -241,15 +256,29 @@ class AssignmentOption(BaseOption):
return unicode(self.candidate) return unicode(self.candidate)
class AssignmentPoll(BasePoll, CountInvalid, CountVotesCast, PublishPollMixin): class AssignmentPoll(RelatedModelMixin, CountInvalid, CountVotesCast,
PublishPollMixin, BasePoll):
option_class = AssignmentOption option_class = AssignmentOption
assignment = models.ForeignKey(Assignment, related_name='poll_set') assignment = models.ForeignKey(Assignment, related_name='poll_set')
yesnoabstain = models.NullBooleanField() yesnoabstain = models.NullBooleanField()
def __unicode__(self):
return _("Ballot %d") % self.get_ballot()
@models.permalink
def get_absolute_url(self, link='detail'):
if link == 'view' or link == 'detail' or link == 'update':
return ('assignment_poll_view', [str(self.pk)])
if link == 'delete':
return ('assignment_poll_delete', [str(self.pk)])
def get_assignment(self): def get_assignment(self):
return self.assignment return self.assignment
def get_related_model(self):
return self.assignment
def get_vote_values(self): def get_vote_values(self):
if self.yesnoabstain is None: if self.yesnoabstain is None:
if config['assignment_poll_vote_values'] == 'votes': if config['assignment_poll_vote_values'] == 'votes':
@ -274,13 +303,3 @@ class AssignmentPoll(BasePoll, CountInvalid, CountVotesCast, PublishPollMixin):
def get_ballot(self): def get_ballot(self):
return self.assignment.poll_set.filter(id__lte=self.id).count() return self.assignment.poll_set.filter(id__lte=self.id).count()
@models.permalink
def get_absolute_url(self, link='detail'):
if link == 'view' or link == 'detail' or link == 'update':
return ('assignment_poll_view', [str(self.id)])
if link == 'delete':
return ('assignment_poll_delete', [str(self.id)])
def __unicode__(self):
return _("Ballot %d") % self.get_ballot()

View File

@ -10,29 +10,8 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from django.template.loader import render_to_string from openslides.projector.api import register_slide_model
from openslides.config.api import config
from openslides.projector.api import register_slide
from .models import Assignment from .models import Assignment
def assignment_slide(**kwargs): register_slide_model(Assignment, 'assignment/slide.html')
"""
Slide for an Assignment
"""
assignment_pk = kwargs.get('pk', None)
try:
assignment = Assignment.objects.get(pk=assignment_pk)
except Assignment.DoesNotExist:
return ''
polls = assignment.poll_set
context = {
'polls': polls.filter(published=True),
'vote_results': assignment.vote_results(only_published=True),
'assignment': assignment}
return render_to_string('assignment/slide.html', context)
register_slide(Assignment.slide_callback_name, assignment_slide)

View File

@ -179,7 +179,7 @@
{% endfor %} {% endfor %}
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %} {% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
<th class="span1 nobr"> <th class="span1 nobr">
<a href="{% url 'assignment_poll_create' assignment.id %}" class="btn btn-mini"> <a href="{% url 'assignment_poll_create' assignment.pk %}" class="btn btn-mini">
<i class="icon-plus"></i> {% trans 'New ballot' %} <i class="icon-plus"></i> {% trans 'New ballot' %}
</a> </a>
</th> </th>

View File

@ -99,6 +99,8 @@ urlpatterns = patterns('openslides.assignment.views',
name='assignment_poll_delete', name='assignment_poll_delete',
), ),
# TODO: use seperate urls to publish and unpublish the poll
# see assignment_user_elected
url(r'^poll/(?P<pk>\d+)/pub/$', url(r'^poll/(?P<pk>\d+)/pub/$',
SetPublishStatusView.as_view(), SetPublishStatusView.as_view(),
name='assignment_poll_publish_status', name='assignment_poll_publish_status',

View File

@ -246,10 +246,10 @@ class PollUpdateView(PollFormView):
class SetPublishStatusView(SingleObjectMixin, RedirectView): class SetPublishStatusView(SingleObjectMixin, RedirectView):
model = AssignmentPoll model = AssignmentPoll
permission_required = 'assignment.can_manage_assignment' permission_required = 'assignment.can_manage_assignment'
url_name = 'assignment_list' url_name = 'assignment_detail'
allow_ajax = True allow_ajax = True
def get_ajax_context(self): def get_ajax_context(self, **kwargs):
return {'published': self.object.published} return {'published': self.object.published}
def pre_redirect(self, *args, **kwargs): def pre_redirect(self, *args, **kwargs):
@ -258,15 +258,11 @@ class SetPublishStatusView(SingleObjectMixin, RedirectView):
except self.model.DoesNotExist: except self.model.DoesNotExist:
messages.error(self.request, _('Ballot ID %d does not exist.') % messages.error(self.request, _('Ballot ID %d does not exist.') %
int(kwargs['poll_id'])) int(kwargs['poll_id']))
return else:
if self.object.published: if self.object.published:
self.object.set_published(False) self.object.set_published(False)
else: else:
self.object.set_published(True) self.object.set_published(True)
if self.object.published:
messages.success(self.request, _("Ballot successfully published."))
else:
messages.success(self.request, _("Ballot successfully unpublished."))
class SetElectedView(SingleObjectMixin, RedirectView): class SetElectedView(SingleObjectMixin, RedirectView):
@ -281,14 +277,14 @@ class SetElectedView(SingleObjectMixin, RedirectView):
self.elected = kwargs['elected'] self.elected = kwargs['elected']
self.object.set_elected(self.person, self.elected) self.object.set_elected(self.person, self.elected)
def get_ajax_context(self): def get_ajax_context(self, **kwargs):
if self.elected: if self.elected:
link = reverse('assignment_user_not_elected', link = reverse('assignment_user_not_elected',
args=[self.object.id, self.person.person_id]) args=[self.object.id, self.person.person_id])
text = _('not elected') text = _('not elected')
else: else:
link = reverse('assignment_user_elected', link = reverse('assignment_user_elected',
args=[self.self.object.id, self.person.person_id]) args=[self.object.id, self.person.person_id])
text = _('elected') text = _('elected')
return {'elected': self.elected, 'link': link, 'text': text} return {'elected': self.elected, 'link': link, 'text': text}

View File

@ -23,14 +23,15 @@ from django.utils import formats
from django.utils.translation import pgettext from django.utils.translation import pgettext
from django.utils.translation import ugettext as _, ugettext_lazy, ugettext_noop from django.utils.translation import ugettext as _, ugettext_lazy, ugettext_noop
from openslides.utils.jsonfield import JSONField from openslides.agenda.models import Item
from openslides.utils.person import PersonField
from openslides.config.api import config from openslides.config.api import config
from openslides.participant.models import User
from openslides.poll.models import ( from openslides.poll.models import (
BaseOption, BasePoll, CountVotesCast, CountInvalid, BaseVote) BaseOption, BasePoll, CountVotesCast, CountInvalid, BaseVote)
from openslides.participant.models import User from openslides.projector.models import SlideMixin, RelatedModelMixin
from openslides.projector.models import SlideMixin from openslides.projector.api import (update_projector, get_active_slide)
from openslides.agenda.models import Item from openslides.utils.jsonfield import JSONField
from openslides.utils.person import PersonField
from .exceptions import MotionError, WorkflowError from .exceptions import MotionError, WorkflowError
@ -584,7 +585,7 @@ class MotionVersion(models.Model):
return self.active_version.exists() return self.active_version.exists()
class MotionSubmitter(models.Model): class MotionSubmitter(RelatedModelMixin, models.Model):
"""Save the submitter of a Motion.""" """Save the submitter of a Motion."""
motion = models.ForeignKey('Motion', related_name="submitter") motion = models.ForeignKey('Motion', related_name="submitter")
@ -597,6 +598,9 @@ class MotionSubmitter(models.Model):
"""Return the name of the submitter as string.""" """Return the name of the submitter as string."""
return unicode(self.person) return unicode(self.person)
def get_related_model(self):
return self.motion
class MotionSupporter(models.Model): class MotionSupporter(models.Model):
"""Save the submitter of a Motion.""" """Save the submitter of a Motion."""
@ -695,7 +699,7 @@ class MotionOption(BaseOption):
"""The VoteClass, to witch this Class links.""" """The VoteClass, to witch this Class links."""
class MotionPoll(CountInvalid, CountVotesCast, BasePoll): class MotionPoll(RelatedModelMixin, CountInvalid, CountVotesCast, BasePoll):
"""The Class to saves the poll results for a motion poll.""" """The Class to saves the poll results for a motion poll."""
motion = models.ForeignKey(Motion, related_name='polls') motion = models.ForeignKey(Motion, related_name='polls')
@ -722,7 +726,8 @@ class MotionPoll(CountInvalid, CountVotesCast, BasePoll):
return _('Vote %d') % self.poll_number return _('Vote %d') % self.poll_number
def get_absolute_url(self, link='edit'): def get_absolute_url(self, link='edit'):
"""Return an URL for the poll. """
Return an URL for the poll.
The keyargument 'link' can be 'edit' or 'delete'. The keyargument 'link' can be 'edit' or 'delete'.
""" """
@ -744,9 +749,13 @@ class MotionPoll(CountInvalid, CountVotesCast, BasePoll):
CountInvalid.append_pollform_fields(self, fields) CountInvalid.append_pollform_fields(self, fields)
CountVotesCast.append_pollform_fields(self, fields) CountVotesCast.append_pollform_fields(self, fields)
def get_related_model(self):
return self.motion
class State(models.Model): class State(models.Model):
"""Defines a state for a motion. """
Defines a state for a motion.
Every state belongs to a workflow. All states of a workflow are linked together Every state belongs to a workflow. All states of a workflow are linked together
via 'next_states'. One of these states is the first state, but this via 'next_states'. One of these states is the first state, but this

View File

@ -10,26 +10,7 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from django.template.loader import render_to_string from openslides.projector.api import register_slide_model
from openslides.projector.api import register_slide
from .models import Motion from .models import Motion
register_slide_model(Motion, 'motion/slide.html')
def motion_slide(**kwargs):
"""
Slide for the motion app.
"""
motion_pk = kwargs.get('pk', None)
try:
motion = Motion.objects.get(pk=motion_pk)
except Motion.DoesNotExist:
return ''
context = {
'motion': motion,
'title': motion.title}
return render_to_string('motion/slide.html', context)
register_slide(Motion.slide_callback_name, motion_slide)

View File

@ -11,36 +11,36 @@
:copyright: (c) 20112013 by the OpenSlides team, see AUTHORS. :copyright: (c) 20112013 by the OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from reportlab.platypus import SimpleDocTemplate
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib import messages from django.contrib import messages
from django.db import transaction from django.db import transaction
from django.db.models import Model from django.db.models import Model
from django.http import Http404, HttpResponseRedirect
from django.utils.text import slugify from django.utils.text import slugify
from django.utils.translation import ugettext as _, ugettext_lazy, ugettext_noop from django.utils.translation import ugettext as _, ugettext_lazy, ugettext_noop
from django.http import Http404, HttpResponseRedirect
from reportlab.platypus import SimpleDocTemplate
from openslides.agenda.views import (
CreateRelatedAgendaItemView as _CreateRelatedAgendaItemView)
from openslides.config.api import config
from openslides.poll.views import PollFormView
from openslides.projector.api import get_active_slide, update_projector
from openslides.projector.projector import Widget
from openslides.utils.pdf import stylesheet from openslides.utils.pdf import stylesheet
from openslides.utils.template import Tab
from openslides.utils.utils import html_strong, htmldiff
from openslides.utils.views import ( from openslides.utils.views import (
TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView, TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView,
DetailView, ListView, FormView, QuestionMixin, SingleObjectMixin) DetailView, ListView, FormView, QuestionMixin, SingleObjectMixin)
from openslides.utils.template import Tab
from openslides.utils.utils import html_strong, htmldiff
from openslides.poll.views import PollFormView
from openslides.projector.api import get_active_slide
from openslides.projector.projector import Widget
from openslides.config.api import config
from openslides.agenda.views import CreateRelatedAgendaItemView as _CreateRelatedAgendaItemView
from .models import (Motion, MotionSubmitter, MotionSupporter, MotionPoll, from .csv_import import import_motions
MotionVersion, State, WorkflowError, Category)
from .forms import (BaseMotionForm, MotionSubmitterMixin, MotionSupporterMixin, from .forms import (BaseMotionForm, MotionSubmitterMixin, MotionSupporterMixin,
MotionDisableVersioningMixin, MotionCategoryMixin, MotionDisableVersioningMixin, MotionCategoryMixin,
MotionIdentifierMixin, MotionWorkflowMixin, MotionImportForm) MotionIdentifierMixin, MotionWorkflowMixin, MotionImportForm)
from .models import (Motion, MotionSubmitter, MotionSupporter, MotionPoll,
MotionVersion, State, WorkflowError, Category)
from .pdf import motions_to_pdf, motion_to_pdf, motion_poll_to_pdf from .pdf import motions_to_pdf, motion_to_pdf, motion_poll_to_pdf
from .csv_import import import_motions
class MotionListView(ListView): class MotionListView(ListView):
@ -127,6 +127,15 @@ class MotionEditMixin(object):
MotionSupporter.objects.bulk_create( MotionSupporter.objects.bulk_create(
[MotionSupporter(motion=self.object, person=person) [MotionSupporter(motion=self.object, person=person)
for person in form.cleaned_data['supporter']]) for person in form.cleaned_data['supporter']])
# Update the projector if the motion is on it. This can not be done in
# the model, because bulk_create does not call the save method.
active_slide = get_active_slide()
active_slide_pk = active_slide.get('pk', None)
if (active_slide['callback'] == 'motion' and
unicode(self.object.pk) == unicode(active_slide_pk)):
update_projector()
messages.success(self.request, self.get_success_message()) messages.success(self.request, self.get_success_message())
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())

View File

@ -80,6 +80,11 @@ class User(SlideMixin, PersonMixin, Person, DjangoUser):
return reverse('user_delete', args=[str(self.id)]) return reverse('user_delete', args=[str(self.id)])
return super(User, self).get_absolute_url(link) return super(User, self).get_absolute_url(link)
def get_slide_context(self, **context):
# Does not call super. In this case the context would override the name
# 'user'.
return {'shown_user': self}
@property @property
def clean_name(self): def clean_name(self):
if self.title: if self.title:

View File

@ -10,39 +10,8 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from django.template.loader import render_to_string from openslides.projector.api import register_slide_model
from openslides.projector.api import register_slide
from .models import User, Group from .models import User, Group
register_slide_model(User, 'participant/user_slide.html')
def user_slide(**kwargs): register_slide_model(Group, 'participant/group_slide.html')
"""
Slide for the user model.
"""
user_pk = kwargs.get('pk', None)
try:
user = User.objects.get(pk=user_pk)
except User.DoesNotExist:
return ''
context = {'shown_user': user}
return render_to_string('participant/user_slide.html', context)
register_slide(User.slide_callback_name, user_slide)
def group_slide(**kwargs):
"""
Slide for the group model.
"""
group_pk = kwargs.get('pk', None)
try:
group = Group.objects.get(pk=group_pk)
except Group.DoesNotExist:
return ''
context = {'group': group}
return render_to_string('participant/group_slide.html', context)
register_slide(Group.slide_callback_name, group_slide)

View File

@ -40,18 +40,17 @@ def update_projector():
def update_projector_overlay(overlay): def update_projector_overlay(overlay):
""" """
Update one overlay on the projector. Update one or all overlay on the projector.
Checks if the overlay is activated and updates it in this case. Checks if the overlay is activated and updates it in this case.
'overlay' has to be an overlay object, the name of a ovleray or None. The argument 'overlay' has to be an overlay object, the name of a
ovleray or None. If it is None, all overlays will be updated.
If 'overlay' is None, then all overlays are updated.
""" """
if isinstance(overlay, basestring):
overlay = get_overlays()[overlay]
if overlay is None: if overlay is None:
overlays = [overlay for overlay in get_overlays().values()] overlays = [overlay for overlay in get_overlays().values()]
elif isinstance(overlay, basestring):
overlays = [get_overlays()[overlay]]
else: else:
overlays = [overlay] overlays = [overlay]
@ -132,6 +131,33 @@ def register_slide(name, callback):
slide_callback[name] = callback slide_callback[name] = callback
def register_slide_model(SlideModel, template):
"""
Shortcut for register_slide for a Model with the SlideMixin.
The Argument 'SlideModel' has to be a Django-Model-Class, which is a subclass
of SlideMixin. Template has to be a string to the path of a template.
"""
def model_slide(**kwargs):
"""
Return the html code for the model slide.
"""
slide_pk = kwargs.get('pk', None)
try:
slide = SlideModel.objects.get(pk=slide_pk)
except SlideModel.DoesNotExist:
slide = None
context = {'slide': None}
else:
context = slide.get_slide_context()
return render_to_string(template, context)
register_slide(SlideModel.slide_callback_name, model_slide)
def set_active_slide(callback, kwargs={}): def set_active_slide(callback, kwargs={}):
""" """
Set the active Slide. Set the active Slide.
@ -147,7 +173,7 @@ def set_active_slide(callback, kwargs={}):
def get_active_slide(): def get_active_slide():
""" """
Returns the dictonary, witch defindes the active slide. Returns the dictonary, which defines the active slide.
""" """
return config['projector_active_slide'] return config['projector_active_slide']

View File

@ -19,6 +19,39 @@ from django.core.urlresolvers import reverse
from openslides.utils.utils import int_or_none from openslides.utils.utils import int_or_none
class RelatedModelMixin(object):
"""
Mixin for motion related models, that appear on the motion slide.
"""
def save(self, *args, **kwargs):
"""
Saves the model and updates the projector, if the motion in on it.
"""
from .api import update_projector
value = super(RelatedModelMixin, self).save(*args, **kwargs)
if self.get_related_model().is_active_slide():
update_projector()
return value
def delete(self, *args, **kwargs):
"""
Deletes the model and updates the projector, if the motion in on it.
"""
from .api import update_projector
value = super(RelatedModelMixin, self).delete(*args, **kwargs)
if self.get_related_model().is_active_slide():
update_projector()
return value
def get_related_model(self):
"""
Return the pk of the related model.
"""
raise ImproperlyConfigured(
'%s has to have a method "get_related_model_pk"' % type(self))
class SlideMixin(object): class SlideMixin(object):
""" """
A Mixin for a Django-Model, for making the model a slide. A Mixin for a Django-Model, for making the model a slide.
@ -34,42 +67,32 @@ class SlideMixin(object):
Updates the projector, if 'self' is the active slide. Updates the projector, if 'self' is the active slide.
""" """
from openslides.projector.api import update_projector from openslides.projector.api import update_projector
super(SlideMixin, self).save(*args, **kwargs) value = super(SlideMixin, self).save(*args, **kwargs)
if self.is_active_slide(): if self.is_active_slide():
update_projector() update_projector()
return value
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
from openslides.projector.api import update_projector from openslides.projector.api import update_projector
super(SlideMixin, self).delete(*args, **kwargs) value = super(SlideMixin, self).delete(*args, **kwargs)
if self.is_active_slide(): if self.is_active_slide():
update_projector() update_projector()
return value
def get_slide_callback_name(self):
"""
Returns the name of the slide callback, which is used to render the slide.
"""
if self.slide_callback_name is None:
raise ImproperlyConfigured(
"SlideMixin requires either a definition of 'slide_callback_name'"
" or an implementation of 'get_slide_callback_name()'")
else:
return self.slide_callback_name
def get_absolute_url(self, link='projector'): def get_absolute_url(self, link='projector'):
""" """
Return the url to activate the slide, if link == 'projector' Return the url to activate the slide, if link == 'projector'.
""" """
if link == 'projector':
url_name = 'projector_activate_slide'
elif link == 'projector_preview':
url_name = 'projector_preview'
if link in ('projector', 'projector_preview'): if link in ('projector', 'projector_preview'):
return '%s?pk=%d' % ( url_name = {'projector': 'projector_activate_slide',
'projector_preview': 'projector_preview'}[link]
value = '%s?pk=%d' % (
reverse(url_name, reverse(url_name,
args=[self.get_slide_callback_name()]), args=[self.slide_callback_name]),
self.pk) self.pk)
return super(SlideMixin, self).get_absolute_url(link) else:
value = super(SlideMixin, self).get_absolute_url(link)
return value
def is_active_slide(self): def is_active_slide(self):
""" """
@ -78,15 +101,24 @@ class SlideMixin(object):
from openslides.projector.api import get_active_slide from openslides.projector.api import get_active_slide
active_slide = get_active_slide() active_slide = get_active_slide()
pk = int_or_none(active_slide.get('pk', None)) pk = int_or_none(active_slide.get('pk', None))
return (active_slide['callback'] == self.slide_callback_name and
return (active_slide['callback'] == self.get_slide_callback_name() and
self.pk == pk) self.pk == pk)
def get_slide_context(self, **context):
"""
Returns the context for the template which renders the slide.
"""
slide_name = self._meta.object_name.lower()
context.update({'slide': self,
slide_name: self})
return context
class ProjectorSlide(SlideMixin, models.Model): class ProjectorSlide(SlideMixin, models.Model):
""" """
Model for Slides, only for the projector. Also called custom slides. Model for Slides, only for the projector. Also called custom slides.
""" """
# TODO: Rename it to CustomSlide
slide_callback_name = 'projector_slide' slide_callback_name = 'projector_slide'
title = models.CharField(max_length=256, verbose_name=ugettext_lazy("Title")) title = models.CharField(max_length=256, verbose_name=ugettext_lazy("Title"))

View File

@ -102,7 +102,7 @@ class Overlay(object):
def set_active(self, active): def set_active(self, active):
""" """
Publish or depublish the ovleray on the projector. Publish or depublish the overlay on the projector.
publish, if active is true, publish, if active is true,
depublish, if active is false. depublish, if active is false.

View File

@ -10,27 +10,9 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from django.template.loader import render_to_string from openslides.projector.api import register_slide_model
from openslides.config.api import config
from openslides.projector.api import register_slide
from .models import ProjectorSlide from .models import ProjectorSlide
def projector_slide(**kwargs): register_slide_model(ProjectorSlide, 'projector/slide_projectorslide.html')
"""
Return the html code for a custom slide.
"""
slide_pk = kwargs.get('pk', None)
try:
slide = ProjectorSlide.objects.get(pk=slide_pk)
except ProjectorSlide.DoesNotExist:
slide = None
context = {'slide': slide}
return render_to_string('projector/slide_projectorslide.html', context)
register_slide('projector_slide', projector_slide)

View File

@ -39,8 +39,14 @@ class DjangoStaticFileHandler(StaticFileHandler):
class ProjectorSocketHandler(WebSocketHandler): class ProjectorSocketHandler(WebSocketHandler):
"""
Handels the websocket for the projector.
"""
waiters = set() waiters = set()
# The following lines can be uncommented, if there are any problems with
# websockts in iOS Safari 5.0
## def allow_draft76(self): ## def allow_draft76(self):
## # for iOS 5.0 Safari ## # for iOS 5.0 Safari
## return True ## return True