Merge pull request #916 from ostcar/projector

Send js to the projector
This commit is contained in:
Oskar Hahn 2013-10-21 05:05:40 -07:00
commit 9682a48da2
14 changed files with 193 additions and 140 deletions

View File

@ -5,6 +5,8 @@
<hr> <hr>
</h1> </h1>
{% if item.text %} <div class="scroll">
{{ item.text|safe|linebreaks }} {% if item.text %}
{% endif %} {{ item.text|safe|linebreaks }}
{% endif %}
</div>

View File

@ -21,7 +21,7 @@
{% if item.speaker_list_closed %}(<span class="closed">{% trans 'closed' %}</span>){% endif %} {% if item.speaker_list_closed %}(<span class="closed">{% trans 'closed' %}</span>){% endif %}
</h3> </h3>
<p> <div class="scroll">
{% if list_of_speakers %} {% if list_of_speakers %}
<ul id="list_of_speakers"> <ul id="list_of_speakers">
{% for speaker_dict in list_of_speakers %} {% for speaker_dict in list_of_speakers %}
@ -36,5 +36,5 @@
{% else %} {% else %}
<i>{% trans 'The list of speakers is empty.' %}</i> <i>{% trans 'The list of speakers is empty.' %}</i>
{% endif %} {% endif %}
</p> </div>

View File

@ -19,92 +19,94 @@
</small> </small>
<hr> <hr>
</h1> </h1>
{% if not assignment.candidates %} <div class="scroll">
<p> {% if not assignment.candidates %}
<div class="text">{{ assignment.description|linebreaks }}</div> <p>
</p> <div class="text">{{ assignment.description|linebreaks }}</div>
{% endif %} </p>
{% endif %}
{% if assignment.candidates and assignment.status != "fin" %} {% if assignment.candidates and assignment.status != "fin" %}
<h3>{% trans "Candidates" %}</h3> <h3>{% trans "Candidates" %}</h3>
<ol> <ol>
{% for candidate in assignment.candidates %} {% for candidate in assignment.candidates %}
<li>{{ candidate }} </li> <li>{{ candidate }} </li>
{% empty %} {% empty %}
<li style="list-style: none outside none;"> <li style="list-style: none outside none;">
<i>{% trans "No candidates available." %}</i> <i>{% trans "No candidates available." %}</i>
</li> </li>
{% endfor %} {% endfor %}
</ol> </ol>
<p><br></p> <p><br></p>
{% endif %} {% endif %}
{% if polls.exists %} {% if polls.exists %}
<h3>{% trans "Election results" %}</h3> <h3>{% trans "Election results" %}</h3>
<table class="table-striped table-bordered"> <table class="table-striped table-bordered">
<tr>
<th>{% trans "Candidates" %}</th>
{% for poll in polls %}
<th>
<nobr>{{ poll.get_ballot }}. {% trans "ballot" %}</nobr>
</th>
{% endfor %}
</tr>
{% for candidate, poll_list in vote_results.items %}
<tr> <tr>
<td class="{% if candidate in assignment.elected %} elected{% endif %}"> <th>{% trans "Candidates" %}</th>
{% if candidate in assignment.elected %} {% for poll in polls %}
<a class="elected"> <th>
<img src="{% static 'img/voting-yes.png' %}" title="{% trans 'Candidate is elected' %}"> <nobr>{{ poll.get_ballot }}. {% trans "ballot" %}</nobr>
</a> </th>
{% endif %} {% endfor %}
{{ candidate }} </tr>
</td> {% for candidate, poll_list in vote_results.items %}
{% for vote in poll_list %} <tr>
<td style="white-space:nowrap;"{% if candidate in assignment.elected %} class="elected"{% endif %}> <td class="{% if candidate in assignment.elected %} elected{% endif %}">
{% if not "assignment_publish_winner_results_only"|get_config or candidate in assignment.elected %} {% if candidate in assignment.elected %}
{% if 'Yes' in vote and 'No' in vote and 'Abstain' in vote %} <a class="elected">
<img src="{% static 'img/voting-yes.png' %}" title="{% trans 'Yes' %}"> {{ vote.Yes }}<br> <img src="{% static 'img/voting-yes.png' %}" title="{% trans 'Candidate is elected' %}">
<img src="{% static 'img/voting-no.png' %}" title="{% trans 'No' %}"> {{ vote.No }}<br> </a>
<img src="{% static 'img/voting-abstention.png' %}" title="{% trans 'Abstention' %}"> {{ vote.Abstain }}<br> {% endif %}
{% elif 'Votes' in vote %} {{ candidate }}
<img src="{% static 'img/voting-yes.png' %}" title="{% trans 'Yes' %}"> {{ vote.Votes }} </td>
{% elif vote == None %} {% for vote in poll_list %}
{% trans 'was not a <br> candidate'%} <td style="white-space:nowrap;"{% if candidate in assignment.elected %} class="elected"{% endif %}>
{% if not "assignment_publish_winner_results_only"|get_config or candidate in assignment.elected %}
{% if 'Yes' in vote and 'No' in vote and 'Abstain' in vote %}
<img src="{% static 'img/voting-yes.png' %}" title="{% trans 'Yes' %}"> {{ vote.Yes }}<br>
<img src="{% static 'img/voting-no.png' %}" title="{% trans 'No' %}"> {{ vote.No }}<br>
<img src="{% static 'img/voting-abstention.png' %}" title="{% trans 'Abstention' %}"> {{ vote.Abstain }}<br>
{% elif 'Votes' in vote %}
<img src="{% static 'img/voting-yes.png' %}" title="{% trans 'Yes' %}"> {{ vote.Votes }}
{% elif vote == None %}
{% trans 'was not a <br> candidate'%}
{% else %}
&nbsp;
{% endif %}
{% else %} {% else %}
&nbsp; &nbsp;
{% endif %} {% endif %}
{% else %} </td>
&nbsp; {% endfor %}
{% endif %} </tr>
</td>
{% endfor %} {% endfor %}
</tr> <tr>
{% endfor %} <td>{% trans 'Invalid votes' %}</td>
<tr> {% for poll in polls %}
<td>{% trans 'Invalid votes' %}</td> <td style="white-space:nowrap;">
{% for poll in polls %} {% if poll.has_votes %}
<td style="white-space:nowrap;"> <img src="{% static 'img/voting-invalid.png' %}" title="{% trans 'Invalid' %}">
{% if poll.has_votes %} {{ poll.print_votesinvalid }}
<img src="{% static 'img/voting-invalid.png' %}" title="{% trans 'Invalid' %}"> {% endif %}
{{ poll.print_votesinvalid }} </td>
{% endif %}
</td>
{% endfor %} {% endfor %}
</tr> </tr>
<tr class="total"> <tr class="total">
<td> <td>
<strong>{% trans 'Votes cast' %}</strong> <strong>{% trans 'Votes cast' %}</strong>
</td>
{% for poll in polls %}
<td style="white-space:nowrap;">
{% if poll.has_votes %}
<img src="{% static 'img/voting-total.png' %}" title="{% trans 'Votes cast' %}">
<strong>{{ poll.print_votescast }}</strong>
{% endif %}
</td> </td>
{% endfor %} {% for poll in polls %}
</tr> <td style="white-space:nowrap;">
</table> {% if poll.has_votes %}
{% endif %} <img src="{% static 'img/voting-total.png' %}" title="{% trans 'Votes cast' %}">
<strong>{{ poll.print_votescast }}</strong>
{% endif %}
</td>
{% endfor %}
</tr>
</table>
{% endif %}
</div>

View File

@ -61,11 +61,11 @@
<hr> <hr>
</h1> </h1>
<p> <div class="scroll">
<div class="text">{{ motion.active_version.text|safe }}</div> <div class="text">{{ motion.active_version.text|safe }}</div>
{% if motion.active_version.reason %} {% if motion.active_version.reason %}
<br> <br>
<div class="reason"><p><b>{% trans "Reason" %}:</b></p> <div class="reason"><p><b>{% trans "Reason" %}:</b></p>
{{ motion.active_version.reason|safe }}</div> {{ motion.active_version.reason|safe }}</div>
{% endif %} {% endif %}
</p> </div>

View File

@ -65,6 +65,16 @@ def update_projector_overlay(overlay):
ProjectorSocketHandler.send_updates({'overlays': overlay_dict}) ProjectorSocketHandler.send_updates({'overlays': overlay_dict})
def call_on_projector(calls):
"""
Sends data to the projector.
"""
projector_js_cache = config['projector_js_cache']
projector_js_cache.update(calls)
config['projector_js_cache'] = projector_js_cache
ProjectorSocketHandler.send_updates(json.dumps({'calls': calls}))
def get_projector_content(slide_dict=None): def get_projector_content(slide_dict=None):
""" """
Returns the HTML-Content block of the projector. Returns the HTML-Content block of the projector.

View File

@ -55,14 +55,18 @@ def config_variables(sender, **kwargs):
name='countdown_state', name='countdown_state',
default_value='inactive') default_value='inactive')
bigger = ConfigVariable( projector_scale = ConfigVariable(
name='bigger', name='projector_scale',
default_value=100) default_value=100)
projector_up = ConfigVariable( projector_scroll = ConfigVariable(
name='up', name='projector_scroll',
default_value=0) default_value=0)
projector_js_cache = ConfigVariable(
name='projector_js_cache',
default_value={})
projector_active_overlays = ConfigVariable( projector_active_overlays = ConfigVariable(
name='projector_active_overlays', name='projector_active_overlays',
default_value=[]) default_value=[])
@ -71,7 +75,8 @@ def config_variables(sender, **kwargs):
title='No title here', url='bar', required_permission=None, variables=( title='No title here', url='bar', required_permission=None, variables=(
projector, projector_message, projector, projector_message,
countdown_time, countdown_start_stamp, countdown_pause_stamp, countdown_time, countdown_start_stamp, countdown_pause_stamp,
countdown_state, bigger, projector_up, projector_active_overlays)) countdown_state, projector_scale, projector_scroll,
projector_active_overlays, projector_js_cache))
@receiver(projector_overlays, dispatch_uid="projector_countdown") @receiver(projector_overlays, dispatch_uid="projector_countdown")

View File

@ -6,6 +6,7 @@
*/ */
$(document).ready(function() { $(document).ready(function() {
$('#content .scroll').wrap('<div class="scrollwrapper"></div>');
if ($('#content.reload').length > 0) { if ($('#content.reload').length > 0) {
updater.start(); updater.start();
} }
@ -23,8 +24,17 @@ var projector = {
} }
}, },
scroll: function(value) {
$('#content .scroll').css('margin-top', value + 'em')
},
scale: function(value) {
$('#content').css('font-size', value + '%');
$('#content #sidebar').css('font-size', '18px');
},
update_data: function(data) { update_data: function(data) {
$.each(data, function (key, value) { $.each(data, function (key, value) {
if (key === 'load_file') if (key === 'load_file')
projector.load_file(value); projector.load_file(value);
else else
@ -48,20 +58,29 @@ var updater = {
}, },
updateProjector: function(data) { updateProjector: function(data) {
$('#content').html(data.content); if (data.content) {
var overlays = data.overlays; $('#content').html(data.content);
$.each(overlays, function (key, value) { $('#content .scroll').wrap('<div class="scrollwrapper"></div>');
var overlay = $('#overlays #overlay_' + key) }
if (!value) if (data.overlays) {
overlay.remove(); $.each(data.overlays, function (key, value) {
else { var overlay = $('#overlays #overlay_' + key)
if (overlay.length) { if (!value)
overlay.html(value.html) overlay.remove();
} else { else {
$('#overlays').append(value.html); if (overlay.length) {
overlay.html(value.html)
} else {
$('#overlays').append(value.html);
}
projector.update_data(value.javascript);
} }
projector.update_data(value.javascript); });
} }
}); if (data.calls) {
$.each(data.calls, function (call, argument) {
projector[call](argument);
});
}
} }
}; };

View File

@ -86,6 +86,13 @@ body{
top: 150px; top: 150px;
right: 40px; right: 40px;
z-index: -1; z-index: -1;
transition: all 2s;
}
#content .scroll {
transition: margin 2s;
}
#content .scrollwrapper {
overflow: hidden;
} }
h1 { h1 {
font-size: 45px !important; font-size: 45px !important;

View File

@ -40,6 +40,9 @@
{% for js in overlay_js %} {% for js in overlay_js %}
projector.update_data({{ js|safe }}); projector.update_data({{ js|safe }});
{% endfor %} {% endfor %}
{% for key, value in calls.items %}
projector.{{ key }}({{ value }});
{% endfor %}
</script> </script>
</body> </body>
</html> </html>

View File

@ -0,0 +1,9 @@
{% load i18n %}
<h1>{{ slide.title }}</h1>
<div class="scroll">
{% if slide.text %}
<span>{{ slide.text|safe|linebreaks }}</span>
{% endif %}
</div>

View File

@ -1,7 +0,0 @@
{% load i18n %}
<h1>{{ slide.title }}</h1>
{% if slide.text %}
<span>{{ slide.text|safe|linebreaks }}</span>
{% endif %}

View File

@ -58,47 +58,47 @@ urlpatterns = patterns(
name='customslide_delete'), name='customslide_delete'),
url(r'^bigger/$', url(r'^bigger/$',
views.ProjectorEdit.as_view(), views.ProjectorControllView.as_view(),
{'direction': 'bigger'}, {'direction': 'bigger'},
name='projector_bigger'), name='projector_bigger'),
url(r'^smaller/$', url(r'^smaller/$',
views.ProjectorEdit.as_view(), views.ProjectorControllView.as_view(),
{'direction': 'smaller'}, {'direction': 'smaller'},
name='projector_smaller'), name='projector_smaller'),
url(r'^up/$', url(r'^up/$',
views.ProjectorEdit.as_view(), views.ProjectorControllView.as_view(),
{'direction': 'up'}, {'direction': 'up'},
name='projector_up'), name='projector_up'),
url(r'^down/$', url(r'^down/$',
views.ProjectorEdit.as_view(), views.ProjectorControllView.as_view(),
{'direction': 'down'}, {'direction': 'down'},
name='projector_down'), name='projector_down'),
url(r'^clean/$', url(r'^clean/$',
views.ProjectorEdit.as_view(), views.ProjectorControllView.as_view(),
{'direction': 'clean'}, {'direction': 'clean'},
name='projector_clean'), name='projector_clean'),
url(r'^countdown/reset/$', url(r'^countdown/reset/$',
views.CountdownEdit.as_view(), views.CountdownControllView.as_view(),
{'command': 'reset'}, {'command': 'reset'},
name='countdown_reset'), name='countdown_reset'),
url(r'^countdown/start/$', url(r'^countdown/start/$',
views.CountdownEdit.as_view(), views.CountdownControllView.as_view(),
{'command': 'start'}, {'command': 'start'},
name='countdown_start'), name='countdown_start'),
url(r'^countdown/stop/$', url(r'^countdown/stop/$',
views.CountdownEdit.as_view(), views.CountdownControllView.as_view(),
{'command': 'stop'}, {'command': 'stop'},
name='countdown_stop'), name='countdown_stop'),
url(r'^countdown/set-default/$', url(r'^countdown/set-default/$',
views.CountdownEdit.as_view(), views.CountdownControllView.as_view(),
{'command': 'set-default'}, {'command': 'set-default'},
name='countdown_set_default'), name='countdown_set_default'),

View File

@ -22,8 +22,8 @@ from openslides.utils.template import Tab
from openslides.utils.views import (AjaxMixin, CreateView, DeleteView, from openslides.utils.views import (AjaxMixin, CreateView, DeleteView,
RedirectView, TemplateView, UpdateView) RedirectView, TemplateView, UpdateView)
from .api import (get_active_slide, get_all_widgets, get_overlays, from .api import (call_on_projector, get_active_slide, get_all_widgets,
get_projector_content, get_projector_overlays, get_overlays, get_projector_content, get_projector_overlays,
get_projector_overlays_js, reset_countdown, set_active_slide, get_projector_overlays_js, reset_countdown, set_active_slide,
start_countdown, stop_countdown, update_projector_overlay) start_countdown, stop_countdown, update_projector_overlay)
from .forms import SelectWidgetsForm from .forms import SelectWidgetsForm
@ -64,8 +64,8 @@ class Projector(TemplateView):
'content': get_projector_content(), 'content': get_projector_content(),
'overlays': get_projector_overlays(), 'overlays': get_projector_overlays(),
'overlay_js': get_projector_overlays_js(), 'overlay_js': get_projector_overlays_js(),
'reload': True}) 'reload': True,
'calls': config['projector_js_cache']})
# For the Preview # For the Preview
else: else:
kwargs.update({ kwargs.update({
@ -85,8 +85,8 @@ class ActivateView(RedirectView):
def pre_redirect(self, request, *args, **kwargs): def pre_redirect(self, request, *args, **kwargs):
set_active_slide(kwargs['callback'], kwargs=dict(request.GET.items())) set_active_slide(kwargs['callback'], kwargs=dict(request.GET.items()))
config['up'] = 0 config['projector_scroll'] = config.get_default('projector_scroll')
config['bigger'] = 100 config['projector_scale'] = config.get_default('projector_scale')
class SelectWidgetsView(TemplateView): class SelectWidgetsView(TemplateView):
@ -133,7 +133,7 @@ class SelectWidgetsView(TemplateView):
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
class ProjectorEdit(RedirectView): class ProjectorControllView(RedirectView):
""" """
Scale or scroll the projector. Scale or scroll the projector.
""" """
@ -144,20 +144,23 @@ class ProjectorEdit(RedirectView):
def pre_redirect(self, request, *args, **kwargs): def pre_redirect(self, request, *args, **kwargs):
direction = kwargs['direction'] direction = kwargs['direction']
if direction == 'bigger': if direction == 'bigger':
config['bigger'] = int(config['bigger']) + 20 config['projector_scale'] = int(config['projector_scale']) + 20
elif direction == 'smaller': elif direction == 'smaller':
config['bigger'] = int(config['bigger']) - 20 config['projector_scale'] = int(config['projector_scale']) - 20
elif direction == 'down': elif direction == 'down':
config['up'] = int(config['up']) - 5 config['projector_scroll'] = int(config['projector_scroll']) - 5
elif direction == 'up': elif direction == 'up':
if config['up'] < 0: if config['projector_scroll'] < 0:
config['up'] = int(config['up']) + 5 config['projector_scroll'] = int(config['projector_scroll']) + 5
elif direction == 'clean': elif direction == 'clean':
config['up'] = config.get_default('up') config['projector_scroll'] = config.get_default('projector_scroll')
config['bigger'] = config.get_default('bigger') config['projector_scale'] = config.get_default('projector_scale')
call_on_projector({'scroll': config['projector_scroll'],
'scale': config['projector_scale']})
class CountdownEdit(RedirectView): class CountdownControllView(RedirectView):
""" """
Start, stop or reset the countdown. Start, stop or reset the countdown.
""" """

View File

@ -57,9 +57,9 @@ class ProjectorSocketHandler(WebSocketHandler):
ProjectorSocketHandler.waiters.remove(self) ProjectorSocketHandler.waiters.remove(self)
@classmethod @classmethod
def send_updates(cls, slide): def send_updates(cls, data):
for waiter in cls.waiters: for waiter in cls.waiters:
waiter.write_message(slide) waiter.write_message(data)
def run_tornado(addr, port, reload=False): def run_tornado(addr, port, reload=False):