Merge branch 'new-schedule'

This commit is contained in:
Luke Hatcher 2012-08-31 02:32:52 -04:00
commit 63e922a87d
15 changed files with 844 additions and 40 deletions

View file

@ -106,6 +106,10 @@ class ProposalBase(models.Model):
def can_edit(self):
return True
@property
def section(self):
return self.kind.section
@property
def speaker_email(self):
return self.speaker.email

View file

@ -11,7 +11,7 @@ from django.contrib.auth.models import User
from markitup.fields import MarkupField
from symposion.proposals.models import ProposalBase
# from symposion.schedule.models import Presentation
from symposion.schedule.models import Presentation
class ProposalScoreExpression(object):
@ -279,26 +279,31 @@ class Comment(models.Model):
def promote_proposal(proposal):
raise NotImplementedError()
# presentation, created = Presentation.objects.get_or_create(
# pk=proposal.pk,
# defaults=dict(
# title=proposal.title,
# description=proposal.description,
# kind=proposal.kind,
# category=proposal.category,
# duration=proposal.duration,
# abstract=proposal.abstract,
# audience_level=proposal.audience_level,
# submitted=proposal.submitted,
# speaker=proposal.speaker,
# )
# )
# if created:
# for speaker in proposal.additional_speakers.all():
# presentation.additional_speakers.add(speaker)
# presentation.save()
# return presentation
if hasattr(proposal, "presentation") and proposal.presentation:
# already promoted
presentation = proposal.presentation
else:
presentation = Presentation(
title = proposal.title,
description = proposal.description,
abstract = proposal.abstract,
speaker = proposal.speaker,
section = proposal.section,
_proposal = proposal,
)
presentation.save()
for speaker in proposal.additional_speakers.all():
presentation.additional_speakers.add(speaker)
presentation.save()
return presentation
def unpromote_proposal(proposal):
if hasattr(proposal, "presentation") and proposal.presentation:
proposal.presentation.delete()
def accepted_proposal(sender, instance=None, **kwargs):
@ -306,4 +311,6 @@ def accepted_proposal(sender, instance=None, **kwargs):
return
if instance.accepted == True:
promote_proposal(instance.proposal)
else:
unpromote_proposal(instance.proposal)
post_save.connect(accepted_proposal, sender=ProposalResult)

View file

View file

@ -0,0 +1,12 @@
from django.contrib import admin
from symposion.schedule.models import Schedule, Day, Room, SlotKind, Slot, SlotRoom, Presentation
admin.site.register(Schedule)
admin.site.register(Day)
admin.site.register(Room)
admin.site.register(SlotKind)
admin.site.register(Slot)
admin.site.register(SlotRoom)
admin.site.register(Presentation)

View file

@ -0,0 +1,12 @@
from django import forms
from symposion.schedule.models import Presentation
class SlotEditForm(forms.Form):
presentation = forms.ModelChoiceField(
queryset=Presentation.objects.filter(slot__isnull=True),
required=True,
empty_label=None,
)

View file

@ -0,0 +1,86 @@
from django.db import models
from markitup.fields import MarkupField
from symposion.proposals.models import ProposalBase
from symposion.conference.models import Section
class Schedule(models.Model):
section = models.OneToOneField(Section)
slug = models.SlugField(unique=True)
class Day(models.Model):
schedule = models.ForeignKey(Schedule)
date = models.DateField()
class Meta:
unique_together = [("schedule", "date")]
class Room(models.Model):
schedule = models.ForeignKey(Schedule)
name = models.CharField(max_length=65)
order = models.PositiveIntegerField()
class SlotKind(models.Model):
"""
A slot kind represents what kind a slot is. For example, a slot can be a
break, lunch, or X-minute talk.
"""
schedule = models.ForeignKey(Schedule)
label = models.CharField(max_length=50)
class Slot(models.Model):
day = models.ForeignKey(Day)
kind = models.ForeignKey(SlotKind)
start = models.TimeField()
end = models.TimeField()
class SlotRoom(models.Model):
"""
Links a slot with a room.
"""
slot = models.ForeignKey(Slot)
room = models.ForeignKey(Room)
class Meta:
unique_together = [("slot", "room")]
class Presentation(models.Model):
slot = models.OneToOneField(Slot, null=True, blank=True, related_name="presentation")
title = models.CharField(max_length=100)
description = MarkupField()
abstract = MarkupField()
speaker = models.ForeignKey("speakers.Speaker", related_name="presentations")
additional_speakers = models.ManyToManyField("speakers.Speaker", blank=True)
cancelled = models.BooleanField(default=False)
_proposal = models.OneToOneField(ProposalBase, related_name="presentation")
section = models.ForeignKey(Section, related_name="presentations")
@property
def proposal(self):
if self._proposal:
proposal = ProposalBase.objects.get_subclass(pk=self._proposal.pk)
return proposal
return None
def speakers(self):
yield self.speaker
for speaker in self.additional_speakers.all():
yield speaker
def __unicode__(self):
return self.title

View file

@ -0,0 +1,49 @@
import itertools
import operator
from django.db.models import Count
from symposion.schedule.models import Room, Slot, SlotRoom
class TimeTable(object):
def __init__(self, day):
self.day = day
def slots_qs(self):
qs = Slot.objects.all()
qs = qs.filter(day=self.day)
return qs
def rooms(self):
qs = Room.objects.all()
qs = qs.filter(schedule=self.day.schedule)
qs = qs.filter(pk__in=SlotRoom.objects.filter(slot__in=self.slots_qs().values("pk")).values("room"))
qs = qs.order_by("order")
return qs
def __iter__(self):
times = sorted(set(itertools.chain(*self.slots_qs().values_list("start", "end"))))
slots = Slot.objects.filter(pk__in=self.slots_qs().order_by("start", "slotroom__room__order").values("pk"))
slots = slots.annotate(room_count=Count("slotroom"))
row = []
for time, next_time in pairwise(times):
row = {"time": time, "slots": []}
for slot in slots:
if slot.start == time:
slot.rowspan = TimeTable.rowspan(times, slot.start, slot.end)
slot.colspan = slot.room_count
row["slots"].append(slot)
if row["slots"] or next_time is None:
yield row
@staticmethod
def rowspan(times, start, end):
return times.index(end) - times.index(start)
def pairwise(iterable):
a, b = itertools.tee(iterable)
b.next()
return itertools.izip_longest(a, b)

View file

@ -0,0 +1,11 @@
from django.conf.urls.defaults import url, patterns
urlpatterns = patterns("symposion.schedule.views",
url(r"^$", "schedule_detail", name="schedule_detail_singleton"),
url(r"^edit/$", "schedule_edit", name="schedule_edit_singleton"),
url(r"^(\w+)/edit/$", "schedule_detail", name="schedule_detail"),
url(r"^(\w+)/edit/$", "schedule_edit", name="schedule_edit"),
url(r"^edit/slot/(?P<slot_pk>\d+)/", "schedule_slot_edit", name="schedule_slot_edit"),
url(r"^list/$", "schedule_list", name="schedule_list"),
)

View file

@ -0,0 +1,74 @@
from django.http import Http404
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from symposion.schedule.forms import SlotEditForm
from symposion.schedule.models import Schedule, Day, Slot, Presentation
from symposion.schedule.timetable import TimeTable
def schedule_detail(request, slug=None):
qs = Schedule.objects.all()
if slug is None:
schedule = next(iter(qs), None)
if schedule is None:
raise Http404()
else:
schedule = get_object_or_404(qs, slug=slug)
ctx = {
"schedule": schedule,
}
return render(request, "schedule/schedule_detail.html", ctx)
def schedule_list(request):
presentations = Presentation.objects.order_by("id")
ctx = {
"presentations": presentations,
}
return render(request, "schedule/schedule_list.html", ctx)
@login_required
def schedule_edit(request, slug=None):
if not request.user.is_staff:
raise Http404()
qs = Schedule.objects.all()
if slug is None:
schedule = next(iter(qs), None)
if schedule is None:
raise Http404()
else:
schedule = get_object_or_404(qs, slug=slug)
days_qs = Day.objects.filter(schedule=schedule)
days = [TimeTable(day) for day in days_qs]
form = SlotEditForm()
ctx = {
"schedule": schedule,
"days": days,
"form": form,
}
return render(request, "schedule/schedule_edit.html", ctx)
@login_required
def schedule_slot_edit(request, slot_pk):
if not request.user.is_staff:
raise Http404()
slot = get_object_or_404(Slot, pk=slot_pk)
form = SlotEditForm(request.POST)
if form.is_valid():
presentation = form.cleaned_data["presentation"]
presentation.slot = slot
presentation.save()
return redirect("schedule_edit_singleton")

View file

@ -0,0 +1,384 @@
/* @group Base */
.chzn-container {
font-size: 13px;
position: relative;
display: inline-block;
zoom: 1;
*display: inline;
}
.chzn-container .chzn-drop {
background: #fff;
border: 1px solid #aaa;
border-top: 0;
position: absolute;
top: 29px;
left: 0;
-webkit-box-shadow: 0 4px 5px rgba(0,0,0,.15);
-moz-box-shadow : 0 4px 5px rgba(0,0,0,.15);
box-shadow : 0 4px 5px rgba(0,0,0,.15);
z-index: 1010;
}
/* @end */
/* @group Single Chosen */
.chzn-container-single .chzn-single {
background-color: #ffffff;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0 );
background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4));
background-image: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
background-image: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
background-image: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
background-image: linear-gradient(#ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
-webkit-border-radius: 5px;
-moz-border-radius : 5px;
border-radius : 5px;
-moz-background-clip : padding;
-webkit-background-clip: padding-box;
background-clip : padding-box;
border: 1px solid #aaaaaa;
-webkit-box-shadow: 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1);
-moz-box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1);
box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1);
display: block;
overflow: hidden;
white-space: nowrap;
position: relative;
height: 23px;
line-height: 24px;
padding: 0 0 0 8px;
color: #444444;
text-decoration: none;
}
.chzn-container-single .chzn-default {
color: #999;
}
.chzn-container-single .chzn-single span {
margin-right: 26px;
display: block;
overflow: hidden;
white-space: nowrap;
-o-text-overflow: ellipsis;
-ms-text-overflow: ellipsis;
text-overflow: ellipsis;
}
.chzn-container-single .chzn-single abbr {
display: block;
position: absolute;
right: 26px;
top: 6px;
width: 12px;
height: 13px;
font-size: 1px;
background: url('chosen-sprite.png') right top no-repeat;
}
.chzn-container-single .chzn-single abbr:hover {
background-position: right -11px;
}
.chzn-container-single.chzn-disabled .chzn-single abbr:hover {
background-position: right top;
}
.chzn-container-single .chzn-single div {
position: absolute;
right: 0;
top: 0;
display: block;
height: 100%;
width: 18px;
}
.chzn-container-single .chzn-single div b {
background: url('chosen-sprite.png') no-repeat 0 0;
display: block;
width: 100%;
height: 100%;
}
.chzn-container-single .chzn-search {
padding: 3px 4px;
position: relative;
margin: 0;
white-space: nowrap;
z-index: 1010;
}
.chzn-container-single .chzn-search input {
background: #fff url('chosen-sprite.png') no-repeat 100% -22px;
background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-gradient(linear, 0 0, 0 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat 100% -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat 100% -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat 100% -22px, linear-gradient(#eeeeee 1%, #ffffff 15%);
margin: 1px 0;
padding: 4px 20px 4px 5px;
outline: 0;
border: 1px solid #aaa;
font-family: sans-serif;
font-size: 1em;
}
.chzn-container-single .chzn-drop {
-webkit-border-radius: 0 0 4px 4px;
-moz-border-radius : 0 0 4px 4px;
border-radius : 0 0 4px 4px;
-moz-background-clip : padding;
-webkit-background-clip: padding-box;
background-clip : padding-box;
}
/* @end */
.chzn-container-single-nosearch .chzn-search input {
position: absolute;
left: -9000px;
}
/* @group Multi Chosen */
.chzn-container-multi .chzn-choices {
background-color: #fff;
background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
background-image: -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background-image: -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background-image: -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background-image: linear-gradient(#eeeeee 1%, #ffffff 15%);
border: 1px solid #aaa;
margin: 0;
padding: 0;
cursor: text;
overflow: hidden;
height: auto !important;
height: 1%;
position: relative;
}
.chzn-container-multi .chzn-choices li {
float: left;
list-style: none;
}
.chzn-container-multi .chzn-choices .search-field {
white-space: nowrap;
margin: 0;
padding: 0;
}
.chzn-container-multi .chzn-choices .search-field input {
color: #666;
background: transparent !important;
border: 0 !important;
font-family: sans-serif;
font-size: 100%;
height: 15px;
padding: 5px;
margin: 1px 0;
outline: 0;
-webkit-box-shadow: none;
-moz-box-shadow : none;
box-shadow : none;
}
.chzn-container-multi .chzn-choices .search-field .default {
color: #999;
}
.chzn-container-multi .chzn-choices .search-choice {
-webkit-border-radius: 3px;
-moz-border-radius : 3px;
border-radius : 3px;
-moz-background-clip : padding;
-webkit-background-clip: padding-box;
background-clip : padding-box;
background-color: #e4e4e4;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0 );
background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05);
-moz-box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05);
box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05);
color: #333;
border: 1px solid #aaaaaa;
line-height: 13px;
padding: 3px 20px 3px 5px;
margin: 3px 0 3px 5px;
position: relative;
cursor: default;
}
.chzn-container-multi .chzn-choices .search-choice-focus {
background: #d4d4d4;
}
.chzn-container-multi .chzn-choices .search-choice .search-choice-close {
display: block;
position: absolute;
right: 3px;
top: 4px;
width: 12px;
height: 13px;
font-size: 1px;
background: url('chosen-sprite.png') right top no-repeat;
}
.chzn-container-multi .chzn-choices .search-choice .search-choice-close:hover {
background-position: right -11px;
}
.chzn-container-multi .chzn-choices .search-choice-focus .search-choice-close {
background-position: right -11px;
}
/* @end */
/* @group Results */
.chzn-container .chzn-results {
margin: 0 4px 4px 0;
max-height: 240px;
padding: 0 0 0 4px;
position: relative;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.chzn-container-multi .chzn-results {
margin: -1px 0 0;
padding: 0;
}
.chzn-container .chzn-results li {
display: none;
line-height: 15px;
padding: 5px 6px;
margin: 0;
list-style: none;
}
.chzn-container .chzn-results .active-result {
cursor: pointer;
display: list-item;
}
.chzn-container .chzn-results .highlighted {
background-color: #3875d7;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3875d7', endColorstr='#2a62bc', GradientType=0 );
background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
background-image: -webkit-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
background-image: -moz-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
background-image: -o-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
color: #fff;
}
.chzn-container .chzn-results li em {
background: #feffde;
font-style: normal;
}
.chzn-container .chzn-results .highlighted em {
background: transparent;
}
.chzn-container .chzn-results .no-results {
background: #f4f4f4;
display: list-item;
}
.chzn-container .chzn-results .group-result {
cursor: default;
color: #999;
font-weight: bold;
}
.chzn-container .chzn-results .group-option {
padding-left: 15px;
}
.chzn-container-multi .chzn-drop .result-selected {
display: none;
}
.chzn-container .chzn-results-scroll {
background: white;
margin: 0 4px;
position: absolute;
text-align: center;
width: 321px; /* This should by dynamic with js */
z-index: 1;
}
.chzn-container .chzn-results-scroll span {
display: inline-block;
height: 17px;
text-indent: -5000px;
width: 9px;
}
.chzn-container .chzn-results-scroll-down {
bottom: 0;
}
.chzn-container .chzn-results-scroll-down span {
background: url('chosen-sprite.png') no-repeat -4px -3px;
}
.chzn-container .chzn-results-scroll-up span {
background: url('chosen-sprite.png') no-repeat -22px -3px;
}
/* @end */
/* @group Active */
.chzn-container-active .chzn-single {
-webkit-box-shadow: 0 0 5px rgba(0,0,0,.3);
-moz-box-shadow : 0 0 5px rgba(0,0,0,.3);
box-shadow : 0 0 5px rgba(0,0,0,.3);
border: 1px solid #5897fb;
}
.chzn-container-active .chzn-single-with-drop {
border: 1px solid #aaa;
-webkit-box-shadow: 0 1px 0 #fff inset;
-moz-box-shadow : 0 1px 0 #fff inset;
box-shadow : 0 1px 0 #fff inset;
background-color: #eee;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0 );
background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff));
background-image: -webkit-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
background-image: -moz-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
background-image: -o-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
background-image: linear-gradient(#eeeeee 20%, #ffffff 80%);
-webkit-border-bottom-left-radius : 0;
-webkit-border-bottom-right-radius: 0;
-moz-border-radius-bottomleft : 0;
-moz-border-radius-bottomright: 0;
border-bottom-left-radius : 0;
border-bottom-right-radius: 0;
}
.chzn-container-active .chzn-single-with-drop div {
background: transparent;
border-left: none;
}
.chzn-container-active .chzn-single-with-drop div b {
background-position: -18px 1px;
}
.chzn-container-active .chzn-choices {
-webkit-box-shadow: 0 0 5px rgba(0,0,0,.3);
-moz-box-shadow : 0 0 5px rgba(0,0,0,.3);
box-shadow : 0 0 5px rgba(0,0,0,.3);
border: 1px solid #5897fb;
}
.chzn-container-active .chzn-choices .search-field input {
color: #111 !important;
}
/* @end */
/* @group Disabled Support */
.chzn-disabled {
cursor: default;
opacity:0.5 !important;
}
.chzn-disabled .chzn-single {
cursor: default;
}
.chzn-disabled .chzn-choices .search-choice .search-choice-close {
cursor: default;
}
/* @group Right to Left */
.chzn-rtl { text-align: right; }
.chzn-rtl .chzn-single { padding: 0 8px 0 0; overflow: visible; }
.chzn-rtl .chzn-single span { margin-left: 26px; margin-right: 0; direction: rtl; }
.chzn-rtl .chzn-single div { left: 3px; right: auto; }
.chzn-rtl .chzn-single abbr {
left: 26px;
right: auto;
}
.chzn-rtl .chzn-choices .search-field input { direction: rtl; }
.chzn-rtl .chzn-choices li { float: right; }
.chzn-rtl .chzn-choices .search-choice { padding: 3px 5px 3px 19px; margin: 3px 5px 3px 0; }
.chzn-rtl .chzn-choices .search-choice .search-choice-close { left: 4px; right: auto; background-position: right top;}
.chzn-rtl.chzn-container-single .chzn-results { margin: 0 0 4px 4px; padding: 0 4px 0 0; }
.chzn-rtl .chzn-results .group-option { padding-left: 0; padding-right: 15px; }
.chzn-rtl.chzn-container-active .chzn-single-with-drop div { border-right: none; }
.chzn-rtl .chzn-search input {
background: #fff url('chosen-sprite.png') no-repeat -38px -22px;
background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-gradient(linear, 0 0, 0 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat -38px -22px, linear-gradient(#eeeeee 1%, #ffffff 15%);
padding: 4px 5px 4px 20px;
direction: rtl;
}
/* @end */

10
symposion/static/chosen/chosen.jquery.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View file

@ -16,25 +16,36 @@
{% endblock %}
{% block body %}
{% comment %}
{% if request.user.is_staff %}
<div class="pull-right">
<form class="result-form form-inline" method="POST" action="">
{% csrf_token %}
<div class="btn-group">
{% if proposal.result.get_accepted_display == "accepted" %}
<input type="submit" name="result_submit" value="reject" class="btn btn-danger" />
<input type="submit" name="result_submit" value="undecide" class="btn" />
<a class="btn dropdown-toggle btn-success" data-toggle="dropdown" href="#">Accepted <span class="caret"></span></a>
<ul class="dropdown-menu pull-right">
<li><input type="submit" name="result_submit" value="reject" class="btn btn-danger" /></li>
<li><input type="submit" name="result_submit" value="undecide" class="btn" /></li>
</ul>
{% else %}
{% if proposal.result.get_accepted_display == "rejected" %}
<input type="submit" name="result_submit" value="accept" class="btn btn-success" />
<input type="submit" name="result_submit" value="undecide" class="btn" />
<a class="btn dropdown-toggle btn-danger" data-toggle="dropdown" href="#">Rejected <span class="caret"></span></a>
<ul class="dropdown-menu pull-right">
<li><input type="submit" name="result_submit" value="accept" class="btn btn-success" /></li>
<li><input type="submit" name="result_submit" value="undecide" class="btn" /></li>
</ul>
{% else %}
<input type="submit" name="result_submit" value="accept" class="btn btn-success" />
<input type="submit" name="result_submit" value="reject" class="btn btn-danger" />
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">Undecided <span class="caret"></span></a>
<ul class="dropdown-menu pull-right">
<li><input type="submit" name="result_submit" value="accept" class="btn btn-success" /></li>
<li><input type="submit" name="result_submit" value="reject" class="btn btn-danger" /></li>
</ul>
{% endif %}
{% endif %}
</div>
</form>
</div>
{% endcomment %}
{% endif %}
<h3>#{{ proposal.number }}: {{ proposal.title }} ({{ proposal.speaker }}, Track: {{ proposal.track }})</h3>

View file

@ -0,0 +1,31 @@
<table class="table table-bordered table-condensed">
<tr>
<th>&nbsp;</th>
{% for room in timetable.rooms %}
<th>{{ room.name }}</th>
{% endfor %}
</tr>
{% for row in timetable %}
<tr>
<td class="time">{{ row.time|date:"h:iA" }}</td>
{% for slot in row.slots %}
<td class="slot slot-{{ slot.kind.label }}" colspan="{{ slot.colspan }}" rowspan="{{ slow.rowspan }}">
{% if slot.kind.label == "talk" %}
{% if not slot.presentation %}
<a class="btn btn-mini edit-slot" data-action="{% url schedule_slot_edit slot.pk %}" href="#">+</a>
{% else %}
<div class="title">{{ slot.presentation.title }}</div>
<div class="speaker">{{ slot.presentation.speaker }}</div>
<span class="schedule-controls">
<a class="btn btn-mini edit-slot" data-action="{% url schedule_slot_edit slot.pk %}" href="#">Edit</a>
</span>
{% endif %}
{% else %}
{{ slot.kind.label }}
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>

View file

@ -0,0 +1,94 @@
{% extends "site_base.html" %}
{% load i18n %}
{% load bootstrap_tags %}
{% block head_title %}Conference Schedule Edit{% endblock %}
{% block body_class %}full{% endblock %}
{% block right %}
{% endblock %}
{% block extra_head %}
<link rel="stylesheet" href="{{ STATIC_URL }}chosen/chosen.css" />
<style>
td {
font-size: 9pt;
}
td.slot {
text-align: center;
vertical-align: middle;
}
td.time {
vertical-align: top;
width: 50px;
font-size: 8pt;
padding-top: 0;
}
td.slot:hover .schedule-controls {
display: block;
}
.schedule-controls {
display: none;
font-size: 8pt;
}
.schedule-controls a {
text-decoration: none;
color: #000;
}
.schedule-controls a:hover {
color: #999;
}
td.slot .title {
font-weight: bold;
line-height: 10pt;
}
#id_presentation {
width:400px;
}
</style>
{% endblock %}
{% block body_outer %}
<div class="row">
<div class="span12">
<h1>Schedule Edit</h1>
{% for timetable in days %}
<h2>{{ timetable.day.date }}</h2>
{% include "schedule/_grid.html" %}
{% endfor %}
</div>
<div class="modal fade hide in" id="slotEditModal">
<form id="slotEditForm" class="modal-form" method="POST">
<div class="modal-header">
<a class="close" data-dismiss="modal">&times;</a>
<h3>{% trans "Edit Slot" %}</h3>
</div>
<div class="modal-body" style="height:300px">
{% csrf_token %}
{{ form|as_bootstrap }}
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script src="{{ STATIC_URL }}chosen/chosen.jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
$("a.edit-slot").click(function() {
$("#slotEditForm").get(0).setAttribute("action", $(this).data("action"));
$("#slotEditModal").modal("show");
});
$("#id_presentation").chosen();
});
</script>
{% endblock %}

View file

@ -0,0 +1,19 @@
{% extends "site_base.html" %}
{% load i18n %}
{% block head_title %}Presentation Listing{% endblock %}
{% block body %}
{% for presentation in presentations %}
<div class="row">
<div class="span8 well">
<h3>{{ presentation.title }}</h3>
<h4>{{ presentation.speaker }} in {{ presentation.proposal.track }}</h4>
<p>
{{ presentation.description }}
</p>
</div>
</div>
{% endfor %}
{% endblock %}