Skip to content
Snippets Groups Projects
Verified Commit b385fc4c authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Start migrating the timetable view to SchoolApps' templates

Current status: Time and weekday headings are shown

- Add custom stylesheets from SchoolApps to timetable.css
- Customize plan.html for new data structure
- Change sorting of lessons from column-based to row-based system to support CSS and HTML structures better
- Add plan.html instead of tt_week.html to timetable view
- Add short variants of weekday names
parent cccf3fc9
No related branches found
No related tags found
1 merge request!31Biscuit merge. Closes #53.
...@@ -158,6 +158,16 @@ class TimePeriod(models.Model): ...@@ -158,6 +158,16 @@ class TimePeriod(models.Model):
(6, _("Saturday")), (6, _("Saturday")),
] ]
WEEKDAY_CHOICES_SHORT = [
(0, _("Sun")),
(1, _("Mon")),
(2, _("Tue")),
(3, _("Wed")),
(4, _("Thu")),
(5, _("Fri")),
(6, _("Sat")),
]
weekday = models.PositiveSmallIntegerField(verbose_name=_("Week day"), choices=WEEKDAY_CHOICES) weekday = models.PositiveSmallIntegerField(verbose_name=_("Week day"), choices=WEEKDAY_CHOICES)
period = models.PositiveSmallIntegerField(verbose_name=_("Number of period")) period = models.PositiveSmallIntegerField(verbose_name=_("Number of period"))
......
.chronos-lesson { /*+++++++++++*/
height: 6em; /* Timetable */
/*+++++++++++*/
.smart-plan-badge {
margin: 5px 20px 5px 0;
} }
ul#timetable_select_form li { li.active > a > .sidenav-badge {
dispaly: inline; background-color: whitesmoke !important;
color: #DA3D56 !important;
}
.timetable-plan .row, .timetable-plan .col {
display: flex;
padding: 0 .25rem;
}
.timetable-plan .row {
margin-bottom: .25rem;
}
.lesson-card, .timetable-title-card {
margin: 0;
display: flex;
flex-grow: 1;
min-height: 65px;
}
.lesson-card .card-content {
padding: 0;
text-align: center;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.lesson-card .card-content div {
padding: 3px;
flex: auto;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.timetable-title-card .card-content {
padding: 10px;
text-align: center;
width: 100%;
}
.timetable-mobile-title-card {
margin-top: 50px;
margin-bottom: .60rem;
}
.timetable-mobile-title-card:first-child {
margin-top: -10px;
margin-bottom: .60rem;
}
.timetable-mobile-title-card .card-content {
padding: 10px;
text-align: center;
width: 100%;
}
.timetable-mobile-title-card .card-content .card-title {
font-weight: bold;
}
table.substitutions td, table.substitutions th {
padding: 10px 5px;
} }
.chronos-lesson-cancelled { .lesson-with-sub {
background-color: inherit !important; border: 3px solid red;
text-decoration: line-through; border-radius: 3px;
} }
.lesson-with-sub .badge {
margin: 0;
}
.lesson-with-event {
border: 3px solid #9c27b0;
border-radius: 3px;
}
.lesson-card a, .substitutions a {
color: inherit;
}
/*.timetable-time {*/
/*margin-right: 20px;*/
/*}*/
{% extends 'core/base.html' %} {% extends 'core/base.html' %}
{% load copy_filter %}
<script type="text/javascript"> {% load data_helpers static %}
{% block extra_head %}
<link rel="stylesheet" href="{% static 'css/chronos/timetable.css' %}">
{% endblock %}
{% block content %}
<script type="text/javascript">
{% if smart %} {% if smart %}
var week = {{ selected_week }}; var week = {{ selected_week }};
var year = {{ selected_year }}; var year = {{ selected_year }};
function goToCalendarWeek(cw, year) { function goToCalendarWeek(cw, year) {
window.location.href = "{% url "timetable_smart_plan" raw_type id %}/" + year + "/" + cw; window.location.href = "{% url "timetable_smart_plan" type pk %}/" + year + "/" + cw;
} }
function onCalendarWeekChanged(where) { function onCalendarWeekChanged(where) {
goToCalendarWeek($(where).val(), year); goToCalendarWeek($(where).val(), year);
} }
function weekBefore() { function weekBefore() {
if (week > 1) { if (week > 1) {
goToCalendarWeek(week - 1, year) goToCalendarWeek(week - 1, year)
} else { } else {
goToCalendarWeek(52, year - 1) goToCalendarWeek(52, year - 1)
}
} }
}
function weekNext() { function weekNext() {
if (week < 52) { if (week < 52) {
goToCalendarWeek(week + 1, year); goToCalendarWeek(week + 1, year);
} else { } else {
goToCalendarWeek(1, year + 1); goToCalendarWeek(1, year + 1);
}
} }
}
$(document).ready(function () { $(document).ready(function () {
$("#calendar-week-1").change(function () { $("#calendar-week-1").change(function () {
onCalendarWeekChanged("#calendar-week-1"); onCalendarWeekChanged("#calendar-week-1");
}); });
$("#calendar-week-2").change(function () { $("#calendar-week-2").change(function () {
onCalendarWeekChanged("#calendar-week-2"); onCalendarWeekChanged("#calendar-week-2");
});
$("#calendar-week-3").change(function () {
onCalendarWeekChanged("#calendar-week-3");
});
$("#week-before").click(weekBefore);
$("#week-next").click(weekNext);
}); });
$("#calendar-week-3").change(function () {
onCalendarWeekChanged("#calendar-week-3");
});
$("#week-before").click(weekBefore);
$("#week-next").click(weekNext);
});
{% endif %} {% endif %}
</script> </script>
{% block content %} <div class="row no-margin">
<div class="row no-margin"> <div class="col s8 m6 l8 xl9">
<div class="col s8 m6 l8 xl9"> <h4>
<h3> Stundenplan <i>{{ el }}</i>
Stundenplan <i>{{ el }}</i> </h4>
</h3>
{# Show class teacher and deputy class teacher #} {# Show class teacher and deputy class teacher #}
{% if type == 2 and el.teachers %} {% if type == 2 and el.teachers %}
<h5>Klassenlehrkräfte: <h5>Klassenlehrkräfte:
{% for teacher in el.teachers %} {% for teacher in el.teachers %}
<span data-position="bottom" class="tooltipped" <span data-position="bottom" class="tooltipped"
data-tooltip="{{ teacher }}"> data-tooltip="{{ teacher }}">
<a href="{% url "timetable_smart_plan" "teacher" teacher.id %}"> <a href="{% url "timetable" "teacher" teacher.id %}">
{{ teacher.shortcode }}</a></span>{% if not forloop.last %},{% endif %} {{ teacher.shortcode }}</a></span>{% if not forloop.last %},{% endif %}
{% endfor %} {% endfor %}
</h5> </h5>
{% endif %} {% endif %}
</div>
{# Show print button only if not on mobile #}
<div class="col s4 m6 l4 xl3 right align-right no-print">
<a class="waves-effect waves-teal btn-flat btn-flat-medium right hide-on-small-and-down" id="print">
<i class="material-icons center">print</i>
</a>
</div>
</div> </div>
<div class="row"> {# Show print button only if not on mobile #}
{% if smart %} <div class="col s4 m6 l4 xl3 right align-right no-print">
{# Show if smart #} <a class="waves-effect waves-teal btn-flat btn-flat-medium right hide-on-small-and-down" id="print">
{# Toggle button to regular and smart plan badge #} <i class="material-icons center">print</i>
<div class="row s12 m6 left"> </a>
<span class="badge new primary-color left smart-plan-badge">SMART PLAN</span> </div>
</div>
<div class="row">
{% if smart %}
{# Show if smart #}
{# Toggle button to regular and smart plan badge #}
<div class="row s12 m6 left">
<span class="badge new primary-color left smart-plan-badge">SMART PLAN</span>
<a class="waves-effect waves-light btn-flat no-print" style="padding-left: 3px; padding-right: 3px;" <a class="waves-effect waves-light btn-flat no-print" style="padding-left: 3px; padding-right: 3px;"
href="{% url "timetable_regular_plan" raw_type id "regular" %}"> href="#{# url "timetable_regular_plan" raw_type id "regular" #}">
<i class="material-icons left">slideshow</i> <i class="material-icons left">slideshow</i>
REGELPLAN ANZEIGEN REGELPLAN ANZEIGEN
</a> </a>
</div> </div>
{# Week select #} {# Week select #}
<div class="col s12 m6 right"> <div class="col s12 m6 right">
<div class="col s2 no-print"> <div class="col s2 no-print">
<a class="waves-effect waves-teal btn-flat btn-flat-medium right" id="week-before"> <a class="waves-effect waves-teal btn-flat btn-flat-medium right" id="week-before">
<i class="material-icons center">navigate_before</i> <i class="material-icons center">navigate_before</i>
</a> </a>
</div> </div>
<div class="input-field col s8 no-margin hide-on-med-and-up"> <div class="input-field col s8 no-margin hide-on-med-and-up">
<select id="calendar-week-1"> <select id="calendar-week-1">
{% for week in weeks %} {% for week in weeks %}
<option value="{{ week.calendar_week }}" {% if week.calendar_week == selected_week %} <option value="{{ week.calendar_week }}" {% if week.calendar_week == selected_week %}
selected {% endif %}> KW {{ week.calendar_week }} selected {% endif %}> KW {{ week.calendar_week }}
({{ week.first_day|date:"j.n" }}–{{ week.last_day|date:"j.n" }}) ({{ week.first_day|date:"j.n" }}–{{ week.last_day|date:"j.n" }})
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="input-field col s8 no-margin hide-on-med-and-down"> <div class="input-field col s8 no-margin hide-on-med-and-down">
<select id="calendar-week-2"> <select id="calendar-week-2">
{% for week in weeks %} {% for week in weeks %}
<option value="{{ week.calendar_week }}" {% if week.calendar_week == selected_week %} <option value="{{ week.calendar_week }}" {% if week.calendar_week == selected_week %}
selected {% endif %}> KW {{ week.calendar_week }} ({{ week.first_day|date:"j.n.Y" }}–{{ week.last_day|date:"j.n.Y" }}) selected {% endif %}> KW {{ week.calendar_week }}
</option> ({{ week.first_day|date:"j.n.Y" }}–{{ week.last_day|date:"j.n.Y" }})
{% endfor %} </option>
</select> {% endfor %}
</div> </select>
<div class="input-field col s8 no-margin hide-on-small-and-down hide-on-large-only"> </div>
<select id="calendar-week-3"> <div class="input-field col s8 no-margin hide-on-small-and-down hide-on-large-only">
{% for week in weeks %} <select id="calendar-week-3">
<option value="{{ week.calendar_week }}" {% if week.calendar_week == selected_week %} {% for week in weeks %}
selected {% endif %}> KW {{ week.calendar_week }} <option value="{{ week.calendar_week }}" {% if week.calendar_week == selected_week %}
({{ week.first_day|date:"j.n" }}–{{ week.last_day|date:"j.n.Y" }}) selected {% endif %}> KW {{ week.calendar_week }}
</option> ({{ week.first_day|date:"j.n" }}–{{ week.last_day|date:"j.n.Y" }})
{% endfor %} </option>
</select> {% endfor %}
</div> </select>
<div class="col s2 no-print"> </div>
<a class="waves-effect waves-teal btn-flat btn-flat-medium left" id="week-next"> <div class="col s2 no-print">
<i class="material-icons center">navigate_next</i> <a class="waves-effect waves-teal btn-flat btn-flat-medium left" id="week-next">
</a> <i class="material-icons center">navigate_next</i>
</div> </a>
</div> </div>
</div>
{% else %} {% else %}
{# Show if regular #} {# Show if regular #}
<a class="waves-effect waves-light btn-flat no-print" <a class="waves-effect waves-light btn-flat no-print"
href="{% url "timetable_smart_plan" raw_type id %}"> href="{% url "timetable" type pk %}">
<i class="material-icons left">slideshow</i> <i class="material-icons left">slideshow</i>
SMART PLAN ANZEIGEN SMART PLAN ANZEIGEN
</a> </a>
{% endif %} {% endif %}
</div> </div>
{% include "timetable/hintsinplan.html" %} {# {% include "chronos/hintsinplan.html" %}#}
{# show full timetable on tablets, laptops and pcs #} {# show full timetable on tablets, laptops and pcs #}
<div class="timetable-plan hide-on-small-and-down"> <div class="timetable-plan hide-on-small-and-down">
{# Week days #} {# Week days #}
<div class="row"> <div class="row">
<div class="col s2"> <div class="col s2">
</div> </div>
{# Show short weekdays on tablets #} {# Show short weekdays on tablets #}
{% for day in short_week_days|deepcopy %} {% for day in weekdays_short.items %}
<div class="col s2 hide-on-large-only"> <div class="col s2 hide-on-large-only">
<div class="card timetable-title-card"> <div class="card timetable-title-card">
<div class="card-content"> <div class="card-content">
<span class="card-title"> <span class="card-title">
{{ day.0 }} {{ day.1 }}
</span> </span>
{% if day.1 %} {# {% if day.1 %}#}
<span class="badge new blue center-align holiday-badge">{{ day.1.0 }}</span> {# <span class="badge new blue center-align holiday-badge">{{ day.1.0 }}</span>#}
{% endif %} {# {% endif %}#}
</div> </div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
{# Show long weekdays elsewere #}
{% for day in long_week_days|deepcopy %} {# Show long weekdays elsewere #}
<div class="col s2 hide-on-med-only"> {% for day in weekdays.items %}
<div class="card timetable-title-card"> <div class="col s2 hide-on-med-only">
<div class="card-content"> <div class="card timetable-title-card">
<div class="card-content">
<span class="card-title"> <span class="card-title">
{{ day.0.0 }} {{ day.1 }}
</span> </span>
{% if day.1 %} {# {% if day.1 %}#}
<span class="badge new blue center-align holiday-badge">{{ day.1.0 }}</span> {# <span class="badge new blue center-align holiday-badge">{{ day.1.0 }}</span>#}
{% endif %} {# {% endif %}#}
</div> </div>
</div> </div>
</div>
{% endfor %}
</div> </div>
{% endfor %}
</div>
{# Lessons #} {# Lessons #}
{% for row, time in plan|deepcopy %} {% for period, lesson_periods_period in lesson_periods.items %}
<div class="row">
<div class="col s2">
<div class="card timetable-title-card">
<div class="card-content">
{# Lesson number #} <div class="row">
<span class="card-title left"> <div class="col s2">
{{ time.number_format }} <div class="card timetable-title-card">
</span> <div class="card-content">
{# Time dimension of lesson #} {# Lesson number #}
<div class="right timetable-time grey-text text-darken-2"> <span class="card-title left">
<span>{{ time.start|date:"H:i" }}</span> {{ period }}.
<br> </span>
<span>{{ time.end|date:"H:i" }}</span>
</div>
</div>
</div>
</div> {# Time dimension of lesson #}
{% for col in row %} <div class="right timetable-time grey-text text-darken-2">
{# A lesson #} {% with period_obj=periods|get_dict:period %}
<div class="col s2"> <span>{{ period_obj.0|date:"H:i" }}</span>
{% include "timetable/lesson.html" %} <br>
</div> <span>{{ period_obj.1|date:"H:i" }}</span>
{% endfor %} {% endwith %}
</div>
</div> </div>
</div>
</div>
{% for col in row %}
{# A lesson #}
<div class="col s2">
{% include "timetable/lesson.html" %}
</div>
{% endfor %} {% endfor %}
</div> </div>
{% endfor %}
</div>
{# show 5 seperate ones on mobiles #} {# show 5 seperate ones on mobiles #}
<div class="timetable-plan hide-on-med-and-up"> <div class="timetable-plan hide-on-med-and-up">
{% for day in long_week_days|deepcopy %} {% for day in long_week_days %}
<div class="card timetable-mobile-title-card"> <div class="card timetable-mobile-title-card">
<div class="card-content"> <div class="card-content">
<span class="card-title"> <span class="card-title">
{{ day.0.0 }} {{ day.0.0 }}
</span> </span>
{% if day.1 %} {% if day.1 %}
<span class="badge new blue center-align holiday-badge">{{ day.1.0 }}</span> <span class="badge new blue center-align holiday-badge">{{ day.1.0 }}</span>
{% endif %} {% endif %}
&nbsp; &nbsp;
</div> </div>
</div> </div>
{% for row, time in plan|deepcopy %} {% for row, time in plan %}
<div class="row"> <div class="row">
<div class="col s4"> <div class="col s4">
<div class="card timetable-title-card"> <div class="card timetable-title-card">
<div class="card-content"> <div class="card-content">
{# Lesson number #} {# Lesson number #}
<span class="card-title left"> <span class="card-title left">
{{ time.number_format }} {{ time.number_format }}
</span> </span>
{# Time dimension of lesson #} {# Time dimension of lesson #}
<div class="right timetable-time grey-text text-darken-2"> <div class="right timetable-time grey-text text-darken-2">
<span>{{ time.start|date:"H:i" }}</span> <span>{{ time.start|date:"H:i" }}</span>
<br> <br>
<span>{{ time.end|date:"H:i" }}</span> <span>{{ time.end|date:"H:i" }}</span>
</div>
</div>
</div>
</div>
{% for col in row|deepcopy %}
{% if forloop.counter0 == day.0.1 %}
<div class="col s8">
{# A lesson #}
{% include "timetable/lesson.html" %}
</div>
{% endif %}
{% endfor %}
</div> </div>
{% endfor %} </div>
{% endfor %} </div>
</div>
</div>
{% for col in row %}
{% if forloop.counter0 == day.0.1 %}
<div class="col s8">
{# A lesson #}
{% include "timetable/lesson.html" %}
</div>
{% endif %}
{% endfor %}
</div>
{% endfor %}
{% endfor %}
</div>
{% endblock %} {% endblock %}
...@@ -23,7 +23,6 @@ from .util import CalendarWeek ...@@ -23,7 +23,6 @@ from .util import CalendarWeek
@login_required @login_required
def all(request: HttpRequest) -> HttpResponse: def all(request: HttpRequest) -> HttpResponse:
context = {} context = {}
teachers = Person.objects.annotate(lessons_count=Count("lessons_as_teacher")).filter(lessons_count__gt=0) teachers = Person.objects.annotate(lessons_count=Count("lessons_as_teacher")).filter(lessons_count__gt=0)
...@@ -69,53 +68,61 @@ def timetable( ...@@ -69,53 +68,61 @@ def timetable(
# return redirect(reverse("timetable") + "?teacher=%d" % request.user.person.pk) # return redirect(reverse("timetable") + "?teacher=%d" % request.user.person.pk)
# Regroup lesson periods per weekday # Regroup lesson periods per weekday
per_day = {} per_period = {}
for lesson_period in lesson_periods: for lesson_period in lesson_periods:
per_day.setdefault(lesson_period.period.weekday, {})[ print(lesson_period.period)
lesson_period.period.period per_period.setdefault(lesson_period.period.period, {})[
lesson_period.period.weekday
] = lesson_period ] = lesson_period
print(per_period)
# Determine overall first and last day and period # Determine overall first and last day and period
min_max = TimePeriod.objects.aggregate( min_max = TimePeriod.objects.aggregate(
Min("period"), Max("period"), Min("weekday"), Max("weekday") Min("period"), Max("period"), Min("weekday"), Max("weekday")
) )
period_min = min_max.get("period__min", 1)
period_max = min_max.get("period__max", 7)
weekday_min = min_max.get("weekday__min", 0)
weekday_max = min_max.get("weekday__max", 6)
# Fill in empty lessons # Fill in empty lessons
for weekday_num in range(min_max.get("weekday__min", 0), min_max.get("weekday__max", 6) + 1): for period_num in range(period_min, period_max + 1):
print(period_num)
# Fill in empty weekdays # Fill in empty weekdays
if weekday_num not in per_day.keys(): if period_num not in per_period.keys():
per_day[weekday_num] = {} per_period[period_num] = {}
# Fill in empty lessons on this workday # Fill in empty lessons on this workday
for period_num in range(min_max.get("period__min", 1), min_max.get("period__max", 7) + 1): for weekday_num in range(weekday_min, weekday_max + 1):
if period_num not in per_day[weekday_num].keys(): if weekday_num not in per_period[period_num].keys():
per_day[weekday_num][period_num] = None per_period[period_num][weekday_num] = None
# Order this weekday by periods # Order this weekday by periods
per_day[weekday_num] = OrderedDict(sorted(per_day[weekday_num].items())) per_period[period_num] = OrderedDict(sorted(per_period[period_num].items()))
# Add a form to filter the view
select_form = SelectForm(request.GET or None)
context["current_head"] = _("Timetable") print(lesson_periods)
context["lesson_periods"] = OrderedDict(sorted(per_day.items())) context["lesson_periods"] = OrderedDict(sorted(per_period.items()))
context["periods"] = TimePeriod.get_times_dict() context["periods"] = TimePeriod.get_times_dict()
context["weekdays"] = dict(TimePeriod.WEEKDAY_CHOICES) context["weekdays"] = dict(TimePeriod.WEEKDAY_CHOICES[weekday_min:weekday_max + 1])
context["weekdays_short"] = dict(TimePeriod.WEEKDAY_CHOICES_SHORT[weekday_min:weekday_max + 1])
context["week"] = wanted_week context["week"] = wanted_week
context["select_form"] = select_form context["type"] = _type
context["pk"] = pk
week_prev = wanted_week - 1 week_prev = wanted_week - 1
week_next = wanted_week + 1 week_next = wanted_week + 1
context["url_prev"] = "%s?%s" % ( context["url_prev"] = "%s?%s" % (
reverse("timetable_by_week", args=[week_prev.year, week_prev.week]), reverse("timetable_by_week", args=[_type, pk, week_prev.year, week_prev.week]),
request.GET.urlencode(), request.GET.urlencode(),
) )
context["url_next"] = "%s?%s" % ( context["url_next"] = "%s?%s" % (
reverse("timetable_by_week", args=[week_next.year, week_next.week]), reverse("timetable_by_week", args=[_type, pk, week_next.year, week_next.week]),
request.GET.urlencode(), request.GET.urlencode(),
) )
return render(request, "chronos/tt_week.html", context) return render(request, "chronos/plan.html", context)
@login_required @login_required
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment