Merge branch 'new-schedule'
This commit is contained in:
commit
63e922a87d
15 changed files with 844 additions and 40 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
0
symposion/schedule/__init__.py
Normal file
0
symposion/schedule/__init__.py
Normal file
12
symposion/schedule/admin.py
Normal file
12
symposion/schedule/admin.py
Normal 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)
|
12
symposion/schedule/forms.py
Normal file
12
symposion/schedule/forms.py
Normal 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,
|
||||
)
|
86
symposion/schedule/models.py
Normal file
86
symposion/schedule/models.py
Normal 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
|
49
symposion/schedule/timetable.py
Normal file
49
symposion/schedule/timetable.py
Normal 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)
|
11
symposion/schedule/urls.py
Normal file
11
symposion/schedule/urls.py
Normal 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"),
|
||||
)
|
74
symposion/schedule/views.py
Normal file
74
symposion/schedule/views.py
Normal 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")
|
384
symposion/static/chosen/chosen.css
Executable file
384
symposion/static/chosen/chosen.css
Executable 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
10
symposion/static/chosen/chosen.jquery.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
|
@ -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>
|
||||
|
||||
|
|
31
symposion/templates/schedule/_grid.html
Normal file
31
symposion/templates/schedule/_grid.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
<table class="table table-bordered table-condensed">
|
||||
<tr>
|
||||
<th> </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>
|
94
symposion/templates/schedule/schedule_edit.html
Normal file
94
symposion/templates/schedule/schedule_edit.html
Normal 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">×</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 %}
|
19
symposion/templates/schedule/schedule_list.html
Normal file
19
symposion/templates/schedule/schedule_list.html
Normal 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 %}
|
Loading…
Reference in a new issue