Merge pull request #535 from ostcar/ticket_433

Ticket 433
This commit is contained in:
Oskar Hahn 2013-02-18 09:59:48 -08:00
commit 07e9f4a82d
41 changed files with 3308 additions and 918 deletions

View File

@ -7,3 +7,4 @@ Authors of OpenSlides in chronological order of first contribution:
Andy Kittner <andkit@gmx.net> Andy Kittner <andkit@gmx.net>
Moira Brülisauer <moira.bruelisauer@piratenpartei.ch> (French translation) Moira Brülisauer <moira.bruelisauer@piratenpartei.ch> (French translation)
Alexis Roussel <alexis.roussel@partipirate.ch> (French translation) Alexis Roussel <alexis.roussel@partipirate.ch> (French translation)
Stefan Frauenknecht <stefan@frauenknecht.net>

4
THANKS
View File

@ -8,9 +8,13 @@ OpenSlides uses parts of the following projects:
* jQuery * jQuery
<http://www.jquery.com/> <http://www.jquery.com/>
and some addons: cookie, form, once, templating
* jQuery UI * jQuery UI
<http://jqueryui.com/> <http://jqueryui.com/>
custom ui components: core, widget, mouse, sortable, datepicker, slider
with css theme 'smoothness'
and some addons: slider access, timepicker
* Twitter Bootstrap * Twitter Bootstrap
<http://twitter.github.com/bootstrap/> <http://twitter.github.com/bootstrap/>

View File

@ -10,14 +10,14 @@
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
import re
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from mptt.forms import TreeNodeChoiceField from mptt.forms import TreeNodeChoiceField
from openslides.utils.forms import CssClassMixin from openslides.utils.forms import CssClassMixin
from .models import Item
from openslides.agenda.models import Item
class ItemForm(forms.ModelForm, CssClassMixin): class ItemForm(forms.ModelForm, CssClassMixin):
@ -27,6 +27,13 @@ class ItemForm(forms.ModelForm, CssClassMixin):
parent = TreeNodeChoiceField( parent = TreeNodeChoiceField(
queryset=Item.objects.all(), label=_("Parent item"), required=False) queryset=Item.objects.all(), label=_("Parent item"), required=False)
duration = forms.RegexField(
regex=re.compile('[0-99]:[0-5][0-9]'),
error_message=_("Invalid format. Hours from 0 to 99 and minutes from 00 to 59"),
max_length=5,
required=False,
label=_("Duration (hh:mm)"))
class Meta: class Meta:
model = Item model = Item
exclude = ('closed', 'weight', 'related_sid') exclude = ('closed', 'weight', 'related_sid')
@ -45,11 +52,15 @@ class ItemOrderForm(forms.Form, CssClassMixin):
""" """
weight = forms.ChoiceField( weight = forms.ChoiceField(
choices=gen_weight_choices(), choices=gen_weight_choices(),
widget=forms.Select(attrs={'class': 'menu-weight'}), widget=forms.Select(attrs={'class': 'menu-weight'}))
)
self = forms.IntegerField( self = forms.IntegerField(
widget=forms.HiddenInput(attrs={'class': 'menu-mlid'}), widget=forms.HiddenInput(attrs={'class': 'menu-mlid'}))
)
parent = forms.IntegerField( parent = forms.IntegerField(
widget=forms.HiddenInput(attrs={'class': 'menu-plid'}), widget=forms.HiddenInput(attrs={'class': 'menu-plid'}))
)
class ConfigForm(CssClassMixin, forms.Form):
agenda_start_event_date_time = forms.CharField(
widget=forms.DateTimeInput(format='%d.%m.%Y %H:%M'),
required=False,
label=_("Begin of event"))

View File

@ -20,7 +20,7 @@ from openslides.config.models import config
from openslides.projector.projector import SlideMixin from openslides.projector.projector import SlideMixin
from openslides.projector.api import ( from openslides.projector.api import (
register_slidemodel, get_slide_from_sid, register_slidefunc) register_slidemodel, get_slide_from_sid, register_slidefunc)
from openslides.agenda.slides import agenda_show from .slides import agenda_show
class Item(MPTTModel, SlideMixin): class Item(MPTTModel, SlideMixin):
@ -31,6 +31,13 @@ class Item(MPTTModel, SlideMixin):
""" """
prefix = 'item' prefix = 'item'
AGENDA_ITEM = 1
ORGANIZATIONAL_ITEM = 2
ITEM_TYPE = (
(AGENDA_ITEM, _('Agenda item')),
(ORGANIZATIONAL_ITEM, _('Organizational item')))
title = models.CharField(null=True, max_length=255, verbose_name=_("Title")) title = models.CharField(null=True, max_length=255, verbose_name=_("Title"))
text = models.TextField(null=True, blank=True, verbose_name=_("Text")) text = models.TextField(null=True, blank=True, verbose_name=_("Text"))
comment = models.TextField(null=True, blank=True, verbose_name=_("Comment")) comment = models.TextField(null=True, blank=True, verbose_name=_("Comment"))
@ -38,6 +45,8 @@ class Item(MPTTModel, SlideMixin):
weight = models.IntegerField(default=0, verbose_name=_("Weight")) weight = models.IntegerField(default=0, verbose_name=_("Weight"))
parent = TreeForeignKey('self', null=True, blank=True, parent = TreeForeignKey('self', null=True, blank=True,
related_name='children') related_name='children')
type = models.IntegerField(max_length=1, choices=ITEM_TYPE, default=AGENDA_ITEM, verbose_name=_("Type"))
duration = models.CharField(null=True, blank=True, max_length=5, verbose_name=_("Duration (hh:mm)"))
related_sid = models.CharField(null=True, blank=True, max_length=63) related_sid = models.CharField(null=True, blank=True, max_length=63)
def get_related_slide(self): def get_related_slide(self):
@ -170,6 +179,7 @@ class Item(MPTTModel, SlideMixin):
permissions = ( permissions = (
('can_see_agenda', ugettext_noop("Can see agenda")), ('can_see_agenda', ugettext_noop("Can see agenda")),
('can_manage_agenda', ugettext_noop("Can manage 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: class MPTTMeta:

View File

@ -16,7 +16,7 @@ from django.utils.translation import ugettext as _
def agenda_show(): def agenda_show():
from openslides.agenda.models import Item from openslides.agenda.models import Item
data = {} data = {}
items = Item.objects.filter(parent=None) items = Item.objects.filter(parent=None, type__exact=Item.AGENDA_ITEM)
data['title'] = _("Agenda") data['title'] = _("Agenda")
data['items'] = items data['items'] = items
data['template'] = 'projector/AgendaSummary.html' data['template'] = 'projector/AgendaSummary.html'

View File

@ -0,0 +1,89 @@
/*
* jQuery UI Slider Access
* By: Trent Richardson [http://trentrichardson.com]
* Version 0.3
* Last Modified: 10/20/2012
*
* Copyright 2011 Trent Richardson
* Dual licensed under the MIT and GPL licenses.
* http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
* http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
*
*/
(function($){
$.fn.extend({
sliderAccess: function(options){
options = options || {};
options.touchonly = options.touchonly !== undefined? options.touchonly : true; // by default only show it if touch device
if(options.touchonly === true && !("ontouchend" in document))
return $(this);
return $(this).each(function(i,obj){
var $t = $(this),
o = $.extend({},{
where: 'after',
step: $t.slider('option','step'),
upIcon: 'ui-icon-plus',
downIcon: 'ui-icon-minus',
text: false,
upText: '+',
downText: '-',
buttonset: true,
buttonsetTag: 'span',
isRTL: false
}, options),
$buttons = $('<'+ o.buttonsetTag +' class="ui-slider-access">'+
'<button data-icon="'+ o.downIcon +'" data-step="'+ (o.isRTL? o.step : o.step*-1) +'">'+ o.downText +'</button>'+
'<button data-icon="'+ o.upIcon +'" data-step="'+ (o.isRTL? o.step*-1 : o.step) +'">'+ o.upText +'</button>'+
'</'+ o.buttonsetTag +'>');
$buttons.children('button').each(function(j, jobj){
var $jt = $(this);
$jt.button({
text: o.text,
icons: { primary: $jt.data('icon') }
})
.click(function(e){
var step = $jt.data('step'),
curr = $t.slider('value'),
newval = curr += step*1,
minval = $t.slider('option','min'),
maxval = $t.slider('option','max'),
slidee = $t.slider("option", "slide") || function(){},
stope = $t.slider("option", "stop") || function(){};
e.preventDefault();
if(newval < minval || newval > maxval)
return;
$t.slider('value', newval);
slidee.call($t, null, { value: newval });
stope.call($t, null, { value: newval });
});
});
// before or after
$t[o.where]($buttons);
if(o.buttonset){
$buttons.removeClass('ui-corner-right').removeClass('ui-corner-left').buttonset();
$buttons.eq(0).addClass('ui-corner-left');
$buttons.eq(1).addClass('ui-corner-right');
}
// adjust the width so we don't break the original layout
var bOuterWidth = $buttons.css({
marginLeft: ((o.where == 'after' && !o.isRTL) || (o.where == 'before' && o.isRTL)? 10:0),
marginRight: ((o.where == 'before' && !o.isRTL) || (o.where == 'after' && o.isRTL)? 10:0)
}).outerWidth(true) + 5;
var tOuterWidth = $t.outerWidth(true);
$t.css('display','inline-block').width(tOuterWidth-bOuterWidth);
});
}
});
})(jQuery);

File diff suppressed because it is too large Load Diff

View File

@ -9,3 +9,15 @@ tr.topline td {
border-bottom: 1px solid #333333; border-bottom: 1px solid #333333;
background-color: #CDCDCD; background-color: #CDCDCD;
} }
table#agendatime {
float: right;
width: auto;
margin-bottom: 1em;
font-size: 12px;
}
table#agendatime td {
padding: 3px;
white-space: nowrap;
}

View File

@ -0,0 +1,46 @@
/**
* OpenSlides timepicker style
*
* :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
* :license: GNU GPL, see LICENSE for more details.
*/
.ui-timepicker-div .ui-widget-header {
margin-bottom: 8px;
}
.ui-timepicker-div dl {
text-align: left;
}
.ui-timepicker-div dl dt {
height: 25px;
margin-bottom: -25px;
}
.ui-timepicker-div dl dd {
margin: 0 10px 10px 65px;
}
.ui-timepicker-div td {
font-size: 90%;
}
.ui-tpicker-grid-label {
background: none;
border: none;
margin: 0;
padding: 0;
}
.ui-timepicker-rtl{
direction: rtl;
}
.ui-timepicker-rtl dl {
text-align: right;
}
.ui-timepicker-rtl dl dd {
margin: 0 65px 10px 10px;
}

View File

@ -1,24 +1,85 @@
{% extends "config/base_config.html" %} {% extends "config/base_config.html" %}
{% load i18n %} {% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% load staticfiles %}
{% block header %}
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/jquery-ui/jquery-ui.custom.min.css' %}" />
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/timepicker.css' %}" />
{% endblock %}
{% block javascript %}
<script type="text/javascript" src="{% static 'javascript/jquery-ui.custom.min.js' %}"></script>
<script type="text/javascript" src="{% static 'javascript/jquery-ui-timepicker-addon.js' %}"></script>
<script type="text/javascript" src="{% static 'javascript/jquery-ui-sliderAccess.js' %}"></script>
<script type="text/javascript">
$(function() {
$.datepicker.regional['{{ LANGUAGE_CODE }}'] = {
prevText: 'previous month',
nextText: 'next month',
monthNames: [
'{% trans 'January' %}', '{% trans 'February' %}', '{% trans 'March' %}',
'{% trans 'April' %}', '{% trans 'May' %}', '{% trans 'June' %}',
'{% trans 'July' %}', '{% trans 'August' %}', '{% trans 'September' %}',
'{% trans 'October' %}', '{% trans 'November' %}', '{% trans 'December' %}'
],
monthNamesShort: [
'{% trans 'Jan' %}', '{% trans 'Feb' %}', '{% trans 'Mar' %}',
'{% trans 'Apr' %}', '{% trans 'May' %}', '{% trans 'Jun' %}',
'{% trans 'Jul' %}', '{% trans 'Aug' %}', '{% trans 'Sep' %}',
'{% trans 'Oct' %}', '{% trans 'Nov' %}', '{% trans 'Dec' %}'
],
dayNames: [
'{% trans 'Sunday' %}', '{% trans 'Monday' %}', '{% trans 'Tuesdey' %}', '{% trans 'Wednesday' %}',
'{% trans 'Thursday' %}', '{% trans 'Friday' %}', '{% trans 'Saturday' %}'
],
dayNamesMin: [
'{% trans 'Su' %}', '{% trans 'Mo' %}', '{% trans 'Tu' %}', '{% trans 'We' %}',
'{% trans 'Th' %}', '{% trans 'Fr' %}', '{% trans 'Sa' %}'
],
dayNamesShort: [
'{% trans 'Su' %}', '{% trans 'Mo' %}', '{% trans 'Tu' %}', '{% trans 'We' %}',
'{% trans 'Th' %}', '{% trans 'Fr' %}', '{% trans 'Sa' %}'
],
dateFormat: 'dd.mm.yy', firstDay: 1, isRTL: false
};
$.datepicker.setDefaults($.datepicker.regional['{{ LANGUAGE_CODE }}']);
$("#id_agenda_start_event_date_time").datetimepicker (
{
hour: 12,
timeFormat: "HH:mm",
timeText: '{% trans 'Time' %}',
hourText: '{% trans 'Hour' %}',
minuteText: '{% trans 'Minute' %}',
currentText: '{% trans 'current time' %}',
closeText: '{% trans 'close' %}'
}
);
});
</script>
{% endblock %}
{% block title %}{{ block.super }} {% trans "Agenda settings" %}{% endblock %} {% block title %}{{ block.super }} {% trans "Agenda settings" %}{% endblock %}
{% block content %} {% block content %}
<h1>{% trans "Configuration" %}: {% trans "Agenda" %} <h1>
{% trans "Configuration" %}
<small>{% trans "Agenda" %}</small>
{% block config_submenu %}{{ block.super }}{% endblock %} {% block config_submenu %}{{ block.super }}{% endblock %}
</h1> </h1>
<form action="" method="post">{% csrf_token %} <form action="" method="post">{% csrf_token %}
{{ form.as_p }} {% include "form.html" %}
<p> <p>
<button class="button" type="submit"> {% include "formbuttons_save.html" %}
<span class="icon ok">{% trans 'Save' %}</span> <a href="{% url 'config_agenda' %}" class="btn">
</button> {% trans 'Cancel' %}
<a href="{% url 'config_agenda' %}"> </a>
<button class="button" type="button" onclick="window.location='{% url 'config_agenda' %}'"> </p>
<span class="icon cancel">{% trans 'Cancel' %}</span> <small>* {% trans "required" %}</small>
</button>
</a>
</p>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -20,7 +20,7 @@
{% if perms.agenda.can_manage_agenda %} {% if perms.agenda.can_manage_agenda %}
<div class="dragcell"></div> <div class="dragcell"></div>
{% endif %} {% endif %}
<a href="{% model_url item 'view' %}">{{ item }}</a> <a href="{% model_url item 'view' %}">{% if item.type == item.ORGANIZATIONAL_ITEM %}<i>[{% endif %}{{ item }}{% if item.type == item.ORGANIZATIONAL_ITEM %}]</i>{% endif %}</a>
{{ item.get_title_supplement|safe }} {{ item.get_title_supplement|safe }}
</td> </td>
{% if perms.agenda.can_manage_agenda %} {% if perms.agenda.can_manage_agenda %}
@ -28,6 +28,13 @@
{{ item.comment|first_line }} {{ item.comment|first_line }}
</td> </td>
{% endif %} {% endif %}
{% if perms.agenda.can_see_orga_items %}
<td>
{% if item.duration %}
{{ item.duration }}h <a {% if item.tooltip %}rel="tooltip" data-original-title="{% trans 'End' %}: {{ item.tooltip|date:"DATETIME_FORMAT" }}"{% endif %}><i class="icon-clock"></i></a>
{% endif %}
</td>
{% endif %}
{% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %} {% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %}
<td> <td>
<span style="width: 1px; white-space: nowrap;"> <span style="width: 1px; white-space: nowrap;">

View File

@ -61,6 +61,20 @@
</small> </small>
</h1> </h1>
{% if perms.agenda.can_see_orga_items %}
{% if start and end %}
<table id="agendatime" class="table table-bordered">
<tr>
<td>{% trans "Start of event" %}:</td>
<td>{{ start|date:"DATETIME_FORMAT" }}</td>
</tr>
<tr>
<td>{% trans "Estimated end" %}:</td>
<td>{{ end|date:"DATETIME_FORMAT" }}</td>
</tr>
</table>
{% endif %}
{% endif %}
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" id="hide_closed_items"> {% trans "Hide closed items" %} <input type="checkbox" id="hide_closed_items"> {% trans "Hide closed items" %}
</label> </label>
@ -75,6 +89,9 @@
{% if perms.agenda.can_manage_agenda %} {% if perms.agenda.can_manage_agenda %}
<th width="200" class="optional">{% trans "Comment" %}</th> <th width="200" class="optional">{% trans "Comment" %}</th>
{% endif %} {% endif %}
{% if perms.agenda.can_see_orga_items %}
<th width="50">{% trans "Duration" %}</th>
{% endif %}
{% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %} {% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %}
<th class="mini_width">{% trans "Actions" %}</th> <th class="mini_width">{% trans "Actions" %}</th>
{% endif %} {% endif %}
@ -90,6 +107,9 @@
{% if perms.agenda.can_manage_agenda %} {% if perms.agenda.can_manage_agenda %}
<td class="optional"></td> <td class="optional"></td>
{% endif %} {% endif %}
{% if perms.agenda.can_see_orga_items %}
<td>{{ duration }}h</td>
{% endif %}
{% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %} {% if perms.agenda.can_manage_agenda or perms.projector.can_manage_projector %}
<td> <td>
{% if perms.projector.can_manage_projector %} {% if perms.projector.can_manage_projector %}
@ -110,7 +130,7 @@
{% endfor %} {% endfor %}
{% else %} {% else %}
<tr> <tr>
<td colspan="4"><i>{% trans "No items available." %}</i></td> <td colspan="5"><i>{% trans "No items available." %}</i></td>
</tr> </tr>
{% endif %} {% endif %}
</table> </table>

View File

@ -33,7 +33,7 @@
{% for p in item.get_ancestors %} {% for p in item.get_ancestors %}
<span class="indentation"></span> <span class="indentation"></span>
{% endfor %} {% endfor %}
<a href="{% model_url item 'view' %}">{{ item }}</a> <a href="{% model_url item 'view' %}">{% if item.type == item.ORGANIZATIONAL_ITEM %}<i>[{% endif %}{{ item }}{% if item.type == item.ORGANIZATIONAL_ITEM %}]</i>{% endif %}</a>
{{ item.get_title_supplement|safe }} {{ item.get_title_supplement|safe }}
</li> </li>
{% empty %} {% empty %}

View File

@ -11,10 +11,12 @@
""" """
from django.conf.urls import url, patterns from django.conf.urls import url, patterns
from openslides.agenda.views import (Overview, View, SetClosed, ItemUpdate, from openslides.agenda.views import (
Overview, View, SetClosed, ItemUpdate,
ItemCreate, ItemDelete, AgendaPDF) ItemCreate, ItemDelete, AgendaPDF)
urlpatterns = patterns('', urlpatterns = patterns(
'',
url(r'^$', url(r'^$',
Overview.as_view(), Overview.as_view(),
name='item_overview', name='item_overview',

View File

@ -9,7 +9,9 @@
:copyright: 2011, 2012 by the OpenSlides team, see AUTHORS. :copyright: 2011, 2012 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 Paragraph from reportlab.platypus import Paragraph
from datetime import datetime, timedelta
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib import messages from django.contrib import messages
@ -18,10 +20,12 @@ from django.db.models import Model
from django.utils.translation import ugettext as _, ugettext_lazy from django.utils.translation import ugettext as _, ugettext_lazy
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from openslides.config.models import config
from openslides.agenda.forms import ConfigForm
from openslides.utils.pdf import stylesheet from openslides.utils.pdf import stylesheet
from openslides.utils.views import ( from openslides.utils.views import (
TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView, TemplateView, RedirectView, UpdateView, CreateView, DeleteView, PDFView,
DetailView) DetailView, FormView)
from openslides.utils.template import Tab from openslides.utils.template import Tab
from openslides.utils.utils import html_strong from openslides.utils.utils import html_strong
from openslides.projector.api import get_active_slide from openslides.projector.api import get_active_slide
@ -39,10 +43,44 @@ class Overview(TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(Overview, self).get_context_data(**kwargs) context = super(Overview, self).get_context_data(**kwargs)
if self.request.user.has_perm('agenda.can_see_orga_items'):
items = Item.objects.all()
else:
items = Item.objects.filter(type__exact=Item.AGENDA_ITEM)
start = config['agenda_start_event_date_time']
if start is None or len(start) == 0:
start = None
else:
start = datetime.strptime(start, '%d.%m.%Y %H:%M')
duration = timedelta()
for item in items:
if not item.closed and (item.duration is not None
and len(item.duration) > 0):
duration_list = item.duration.split(':')
duration += timedelta(hours=int(duration_list[0]),
minutes=int(duration_list[1]))
if not start is None:
item.tooltip = start + duration
if start is None:
end = None
else:
end = start + duration
duration = u'%d:%02d' % (
(duration.days * 24 + duration.seconds / 3600.0),
(duration.seconds / 60.0 % 60))
context.update({ context.update({
'items': Item.objects.all(), 'items': items,
'active_sid': get_active_slide(only_sid=True), 'active_sid': get_active_slide(only_sid=True),
}) 'duration': duration,
'start': start,
'end': end})
return context return context
@transaction.commit_manually @transaction.commit_manually
@ -103,8 +141,7 @@ class SetClosed(RedirectView, SingleObjectMixin):
link = reverse('item_close', args=[self.object.id]) link = reverse('item_close', args=[self.object.id])
context.update({ context.update({
'closed': kwargs['closed'], 'closed': kwargs['closed'],
'link': link, 'link': link})
})
return context return context
def pre_redirect(self, request, *args, **kwargs): def pre_redirect(self, request, *args, **kwargs):
@ -157,12 +194,14 @@ class ItemDelete(DeleteView):
if self.get_answer() == 'all': if self.get_answer() == 'all':
self.object.delete(with_children=True) self.object.delete(with_children=True)
messages.success( messages.success(
request, _("Item %s and his children were successfully deleted.") request,
_("Item %s and his children were successfully deleted.")
% html_strong(self.object)) % html_strong(self.object))
elif self.get_answer() == 'yes': elif self.get_answer() == 'yes':
self.object.delete(with_children=False) self.object.delete(with_children=False)
messages.success( messages.success(
request, _("Item %s was successfully deleted.") request,
_("Item %s was successfully deleted.")
% html_strong(self.object)) % html_strong(self.object))
@ -175,7 +214,7 @@ class AgendaPDF(PDFView):
document_title = ugettext_lazy('Agenda') document_title = ugettext_lazy('Agenda')
def append_to_pdf(self, story): def append_to_pdf(self, story):
for item in Item.objects.all(): for item in Item.objects.filter(type__exact=Item.AGENDA_ITEM):
ancestors = item.get_ancestors() ancestors = item.get_ancestors()
if ancestors: if ancestors:
space = "&nbsp;" * 6 * ancestors.count() space = "&nbsp;" * 6 * ancestors.count()
@ -186,6 +225,26 @@ class AgendaPDF(PDFView):
story.append(Paragraph(item.get_title(), stylesheet['Item'])) story.append(Paragraph(item.get_title(), stylesheet['Item']))
class Config(FormView):
"""
Config page for the agenda app.
"""
permission_required = 'config.can_manage_config'
form_class = ConfigForm
template_name = 'agenda/config.html'
success_url_name = 'config_agenda'
def get_initial(self):
return {
'agenda_start_event_date_time': config['agenda_start_event_date_time'],
}
def form_valid(self, form):
config['agenda_start_event_date_time'] = form.cleaned_data['agenda_start_event_date_time']
messages.success(self.request, _('Agenda settings successfully saved.'))
return super(Config, self).form_valid(form)
def register_tab(request): def register_tab(request):
""" """
register the agenda tab. register the agenda tab.

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: OpenSlides 1.3\n" "Project-Id-Version: OpenSlides 1.3\n"
"Report-Msgid-Bugs-To: support@openslides.org\n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-12-09 11:12+0100\n" "POT-Creation-Date: 2013-02-05 14:24+0100\n"
"PO-Revision-Date: 2012-07-28 11:07+0200\n" "PO-Revision-Date: 2012-07-28 11:07+0200\n"
"Last-Translator: Oskar Hahn <mail@oshahn.de>\n" "Last-Translator: Oskar Hahn <mail@oshahn.de>\n"
"Language: de\n" "Language: de\n"

View File

@ -195,7 +195,7 @@ class VersionPermitView(GetVersionMixin, SingleObjectMixin, QuestionMixin, Redir
def case_yes(self): def case_yes(self):
"""Activate the version, if the user chooses 'yes'.""" """Activate the version, if the user chooses 'yes'."""
self.object.activate_version(self.object.version) self.object.activate_version(self.object.version) # TODO: Write log message
self.object.save() self.object.save()
version_permit = VersionPermitView.as_view() version_permit = VersionPermitView.as_view()
@ -221,7 +221,7 @@ class VersionRejectView(GetVersionMixin, SingleObjectMixin, QuestionMixin, Redir
def case_yes(self): def case_yes(self):
"""Reject the version, if the user chooses 'yes'.""" """Reject the version, if the user chooses 'yes'."""
self.object.reject_version(self.object.version) self.object.reject_version(self.object.version) # TODO: Write log message
self.object.save() self.object.save()
version_reject = VersionRejectView.as_view() version_reject = VersionRejectView.as_view()

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/dashboard.css' %}" /> <link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/dashboard.css' %}" />
{% endblock %} {% endblock %}
{% block javascript %} {% block javascript %}
<script type="text/javascript" src="{% static 'javascript/jquery-ui.min.js' %}"></script> <script type="text/javascript" src="{% static 'javascript/jquery-ui.custom.min.js' %}"></script>
<script type="text/javascript" src="{% static 'javascript/jquery.cookie.js' %}"></script> <script type="text/javascript" src="{% static 'javascript/jquery.cookie.js' %}"></script>
<script type="text/javascript" src="{% static 'javascript/jquery.form.js' %}"></script> <script type="text/javascript" src="{% static 'javascript/jquery.form.js' %}"></script>
<script type="text/javascript" src="{% static 'javascript/dashboard.js' %}"></script> <script type="text/javascript" src="{% static 'javascript/dashboard.js' %}"></script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

File diff suppressed because one or more lines are too long

View File

@ -311,7 +311,10 @@ legend + .control-group {
background-image: url("../img/glyphicons_006_user_add.png"); background-image: url("../img/glyphicons_006_user_add.png");
background-position: 0; background-position: 0;
} }
.icon-clock {
background-image: url("../img/glyphicons_054_clock.png");
background-position: 0;
}
/** Responsive **/ /** Responsive **/

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because one or more lines are too long

View File

@ -179,7 +179,8 @@ class ViewTest(TestCase):
response = c.get('/agenda/%d/edit/' % 1000) response = c.get('/agenda/%d/edit/' % 1000)
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
data = {'title': 'newitem1', 'text': 'item1-text', 'weight': '0'} data = {'title': 'newitem1', 'text': 'item1-text', 'weight': '0',
'type': 1}
response = c.post('/agenda/%d/edit/' % self.item1.id, data) response = c.post('/agenda/%d/edit/' % self.item1.id, data)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.refreshItems() self.refreshItems()