Ajout d'une page événements à venir
This commit is contained in:
parent
670961e6d0
commit
8eaee2b1a6
@ -2,6 +2,9 @@ from datetime import datetime, timedelta, date, time
|
||||
import calendar
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.template.defaultfilters import date as _date
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
@ -28,10 +31,12 @@ class DayInCalendar:
|
||||
|
||||
self.in_past = d < now
|
||||
self.today = d == now
|
||||
self.tomorrow = d == now + timedelta(days=+1)
|
||||
self.events = []
|
||||
self.on_requested_interval = on_requested_interval
|
||||
|
||||
self.events_by_category = {}
|
||||
self.time_intervals = None
|
||||
|
||||
def is_in_past(self):
|
||||
return self.in_past
|
||||
@ -39,6 +44,9 @@ class DayInCalendar:
|
||||
def is_today(self):
|
||||
return self.today
|
||||
|
||||
def is_tomorrow(self):
|
||||
return self.tomorrow
|
||||
|
||||
def is_ancestor_uuid_event_from_other(self, event):
|
||||
for e in self.events:
|
||||
if event.is_ancestor_by_uuid(e):
|
||||
@ -114,6 +122,51 @@ class DayInCalendar:
|
||||
result.append((c.name, self.events_by_category[c.name]))
|
||||
return result
|
||||
|
||||
def build_time_intervals(self, all_day_name, interval_names, interval_markers):
|
||||
self.time_intervals = [IntervalInDay(self.date, i, n) for i, n in enumerate([all_day_name] + interval_names)]
|
||||
|
||||
nm2 = datetime.now() + timedelta(hours=-2)
|
||||
for e in self.events:
|
||||
if e.start_time is None:
|
||||
self.time_intervals[0].add_event(e)
|
||||
else:
|
||||
dt = datetime.combine(e.start_day, e.start_time)
|
||||
if dt >= nm2:
|
||||
ok = False
|
||||
for i in range(len(interval_markers)):
|
||||
if dt < interval_markers[i]:
|
||||
self.time_intervals[i + 1].add_event(e)
|
||||
ok = True
|
||||
break
|
||||
if not ok:
|
||||
self.time_intervals[-1].add_event(e)
|
||||
|
||||
def get_time_intervals(self):
|
||||
if self.time_intervals is None:
|
||||
if self.is_today():
|
||||
all_day_name = _('All day today')
|
||||
interval_names = [_('This morning'), _('This noon'), _('This afternoon'), _('This evening')]
|
||||
elif self.is_tomorrow():
|
||||
name = _("Tomorrow")
|
||||
all_day_name = _('All day tomorrow')
|
||||
interval_names = [_('%s morning') % name, _('%s noon') % name, _('%s afternoon') % name, _('%s evening') % name]
|
||||
else:
|
||||
name = _date(self.date, "l")
|
||||
all_day_name = _('All day %s') % name
|
||||
interval_names = [_('%s morning') % name, _('%s noon') % name, _('%s afternoon') % name, _('%s evening') % name]
|
||||
interval_markers = [datetime.combine(self.date, time(h, m)) for h, m in [(11, 30), (13, 0), (18, 0)]]
|
||||
self.build_time_intervals(all_day_name, interval_names, interval_markers)
|
||||
|
||||
logger.error("hop " + str(len(self.time_intervals)))
|
||||
return self.time_intervals
|
||||
|
||||
|
||||
class IntervalInDay(DayInCalendar):
|
||||
|
||||
def __init__(self, d, id, name):
|
||||
self.name = name
|
||||
self.id = d.strftime('%Y-%m-%d') + '-' + str(id)
|
||||
super().__init__(d)
|
||||
|
||||
class CalendarList:
|
||||
def __init__(self, firstdate, lastdate, filter=None, exact=False):
|
||||
@ -208,6 +261,21 @@ class CalendarList:
|
||||
def calendar_days_list(self):
|
||||
return list(self.get_calendar_days().values())
|
||||
|
||||
def time_intervals_list(self, onlyfirst=False):
|
||||
ds = self.calendar_days_list()
|
||||
result = []
|
||||
for d in ds:
|
||||
tis = d.get_time_intervals()
|
||||
for t in tis:
|
||||
if len(t.events) > 0:
|
||||
result.append(t)
|
||||
if onlyfirst:
|
||||
break
|
||||
return result
|
||||
|
||||
def time_intervals_list_first(self):
|
||||
return self.time_intervals_list(True)
|
||||
|
||||
def export_to_ics(self):
|
||||
from .models import Event
|
||||
events = [event for day in self.get_calendar_days().values() for event in day.events]
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -253,7 +253,7 @@ svg {
|
||||
.illustration {
|
||||
width: 100%;
|
||||
padding: 0.3em;
|
||||
margin: 0;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 550px) {
|
||||
@ -526,6 +526,12 @@ article#filters {
|
||||
|
||||
.slide-buttons {
|
||||
float: right;
|
||||
margin-bottom: -2.8em;
|
||||
}
|
||||
@media only screen and (min-width: 992px) {
|
||||
.slide-buttons {
|
||||
margin-left: -3em;
|
||||
}
|
||||
}
|
||||
|
||||
.highlight {
|
||||
@ -1170,6 +1176,7 @@ article {
|
||||
}
|
||||
|
||||
#boutons-fixes {
|
||||
z-index: 1000;
|
||||
li {
|
||||
list-style: none;
|
||||
@extend [role="button"], .secondary;
|
||||
@ -1201,4 +1208,12 @@ article {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.a-venir {
|
||||
.day-interval>.sticky {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
{% extends "agenda_culturel/page.html" %}
|
||||
|
||||
|
||||
{% load i18n %}
|
||||
{% load cache %}
|
||||
{% load cat_extra %}
|
||||
{% load event_extra %}
|
||||
{% load utils_extra %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block entete_header %}
|
||||
{% css_categories %}
|
||||
<script src="{% static 'js/modal.js' %}"></script>
|
||||
<script src="{% static 'js/filters.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{% block og_title %}Événements à venir{% endblock %}{% endblock %}
|
||||
|
||||
{% block body-class %}a-venir{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
{% with cache_timeout=user.is_authenticated|yesno:"30,600" %}
|
||||
{% cache cache_timeout upcoming user.is_authenticated calendar.firstdate filter.to_str LANGUAGE_CODE %}
|
||||
|
||||
<article>
|
||||
<header><h1 id="index-avenir">Événements à venir</h1></header>
|
||||
|
||||
|
||||
{% include "agenda_culturel/filter-inc.html" with filter=filter %}
|
||||
|
||||
<footer>
|
||||
{% for ti in calendar.time_intervals_list_first %}
|
||||
<a href="#{{ ti.id }}" role="button">
|
||||
{% if ti.is_today %}Aujourd'hui
|
||||
{% else %}
|
||||
{% if ti.is_tomorrow %}Demain
|
||||
{% else %}
|
||||
{{ ti.date| date:"l j" }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% picto_from_name "chevrons-down" %}</a>
|
||||
{% endfor %}
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
|
||||
{% for ti in calendar.time_intervals_list %}
|
||||
<article class="day-interval" id="{{ ti.id }}">
|
||||
<header class="sticky">
|
||||
<a role="button" class="secondary slide-buttons" href="#index-avenir" data-placement="left" data-tooltip="Retour en haut">{% picto_from_name "chevrons-up" %}</a>
|
||||
<hgroup>
|
||||
<h2>{{ ti.name }}</h2>
|
||||
<h3>{{ ti.date }}</h3>
|
||||
</hgroup>
|
||||
</header>
|
||||
<div class="grid two-columns grid-reverse">
|
||||
<div>
|
||||
{% if ti.events|length > 1 %}
|
||||
<h3>Résumé</h3>
|
||||
<ul>
|
||||
{% for event in ti.events %}
|
||||
<li>{{ event.category | circle_cat:event.has_recurrences }}
|
||||
{% if event.start_time %}
|
||||
{{ event.start_time }}
|
||||
{% endif %}
|
||||
{{ event|picto_status }} <a href="#event-{{ event.id }}">{{ event.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
{% if ti.events|length > 1 %}
|
||||
<h3>Événements</h3>
|
||||
{% endif %}
|
||||
{% with indexti=ti.id %}
|
||||
{% for event in ti.events %}
|
||||
{% include "agenda_culturel/single-event/event-in-upcoming-inc.html" with event=event filter=filter day=day indexti=indexti %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endcache %}
|
||||
{% endwith %}
|
||||
|
||||
{% endblock %}
|
@ -33,7 +33,7 @@
|
||||
{% load utils_extra %}
|
||||
{% load duplicated_extra %}
|
||||
{% load rimports_extra %}
|
||||
<body>
|
||||
<body class="{% block body-class %}contenu{% endblock %}">
|
||||
<div id="boutons-fixes">
|
||||
<ul>
|
||||
{% block ajouter-bouton %}<li class="ajouter-bouton"><a href="{% url 'add_event' %}" aria-label="Ajouter un événement">{% picto_from_name "plus" %}</a></li>{% endblock %}
|
||||
@ -47,7 +47,7 @@
|
||||
<ul class="menu">
|
||||
{% block ajouter-menu %}<li id="menu-ajouter" class="ajouter-bouton"><a href="{% url 'add_event' %}">Ajouter un événement {% picto_from_name "plus-circle" %}</a></li>{% endblock %}
|
||||
{% block rechercher-menu %}<li id="menu-rechercher" class="rechercher-bouton"><a href="{% url 'event_search' %}">Rechercher {% picto_from_name "search" %}</a></li>{% endblock %}
|
||||
<li><a href="{% url 'aujourdhui' %}">Aujourd'hui</a></li>
|
||||
<li><a href="{% url 'a_venir' %}">À venir</a></li>
|
||||
<li><a href="{% url 'cette_semaine' %}">Cette semaine</a></li>
|
||||
<li><a href="{% url 'ce_mois_ci' %}">Ce mois-ci</a></li>
|
||||
</ul>
|
||||
|
@ -68,7 +68,7 @@
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% else %}
|
||||
<p><em>Cet événement est disponible uniquement sur les nuits énimagmatiques.</em></p>
|
||||
<p><em>À notre connaissance, cet événement n'est pas référencé autre part sur internet.</em></p>
|
||||
{% endif %}
|
||||
{% if event.has_recurrences %}
|
||||
<p class="footer">
|
||||
|
@ -0,0 +1,83 @@
|
||||
{% load static %}
|
||||
{% load cat_extra %}
|
||||
{% load utils_extra %}
|
||||
{% load event_extra %}
|
||||
{% load tag_extra %}
|
||||
|
||||
<article id="event-{{ event.pk}}">
|
||||
<a role="button" class="secondary slide-buttons" href="#{{ indexti }}" data-tooltip="Retour au résumé" data-placement="left">{% picto_from_name "arrow-up" %}</a>
|
||||
{% if event.image or event.local_image %}
|
||||
<article class='illustration'>
|
||||
<img src="{% if event.local_image %}{{ event.local_image.url }}{% else %}{{ event.image }}{% endif %}" alt="{{ event.image_alt }}" />
|
||||
</article>
|
||||
{% endif %}
|
||||
{% if event|can_show_start_time:day %}
|
||||
{% if event.start_time %}
|
||||
<article class='ephemeris-hour'>
|
||||
<span class="large">{{ event.start_time }}</span>
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if event|can_show_end_time:day %}
|
||||
{% if event.end_time %}
|
||||
<article class='ephemeris-hour'>
|
||||
jusqu'à <span class="large">{{ event.end_time }}</span>
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{{ event.category | small_cat_recurrent:event.has_recurrences }}
|
||||
{% if event.location or event.exact_location %}<hgroup>{% endif %}
|
||||
<h3>
|
||||
{{ event|picto_status }}
|
||||
<a href="{{ event.get_absolute_url }}">{{ event.title }}</a>
|
||||
</h3>
|
||||
{% if event.location or event.exact_location %}
|
||||
<h4>
|
||||
{% picto_from_name "map-pin" %}
|
||||
{% include "agenda_culturel/event-location-inc.html" with event=event %}
|
||||
</h4>
|
||||
</hgroup>
|
||||
{% endif %}
|
||||
|
||||
{% if event|need_complete_display:True %}<p>
|
||||
{% picto_from_name "calendar" %}
|
||||
|
||||
<em>{% if event.end_day and event.end_day != event.start_day %}Cet événement dure du {% else %}Cet événement a lieu le{% endif %}
|
||||
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
||||
</em></p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<p>{{ event.description |linebreaks2 | truncatewords:60 }}</p>
|
||||
|
||||
|
||||
<footer class="infos-and-buttons">
|
||||
<div class="infos">
|
||||
<p>
|
||||
{% for tag in event.tags %}
|
||||
<a href="{% url 'view_tag' tag %}" role="button" class="small-cat">{{ tag }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
{% if event.has_recurrences %}
|
||||
<p class="footer">
|
||||
{% picto_from_name "repeat" %}
|
||||
<!-- TODO: see https://forge.chapril.org/jmtrivial/agenda_culturel/issues/65 -->
|
||||
{% for r in event.recurrences.rrules %}
|
||||
{{ r.to_text }}{% if not forloop.first %}, {% endif %}{% endfor %}, depuis le {{ event.recurrences.dtstart.date }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if perms.agenda_culturel.change_event %}
|
||||
<div class="buttons">
|
||||
{% include "agenda_culturel/edit-buttons-inc.html" with event=event %}
|
||||
<a href="{{ event.get_absolute_url }}" role="button">Voir l'événement <svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-right" />
|
||||
</svg></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</footer>
|
||||
</article>
|
||||
|
@ -2,7 +2,7 @@ from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.urls import reverse_lazy
|
||||
from django.template.defaultfilters import pluralize, linebreaks, urlize
|
||||
|
||||
import re
|
||||
|
||||
from agenda_culturel.models import Event
|
||||
from django.db.models import Q
|
||||
@ -139,3 +139,9 @@ def add_url_category(url, c):
|
||||
@register.filter
|
||||
def robust_urlize(txt):
|
||||
return mark_safe(urlize(mark_safe(txt.replace("http", " http"))).replace(" <a ", "<a "))
|
||||
|
||||
@register.filter
|
||||
def linebreaks2(txt):
|
||||
res = linebreaks(txt)
|
||||
|
||||
return mark_safe(re.sub("(<br> )+", "<br>", res))
|
@ -14,6 +14,7 @@ urlpatterns = [
|
||||
path("mois/<int:year>/<int:month>/", month_view, name="month_view"),
|
||||
path("jour/<int:year>/<int:month>/<int:day>/", day_view, name="day_view"),
|
||||
path("aujourdhui/", day_view, name="aujourdhui"),
|
||||
path("a-venir/", upcoming_events, name="a_venir"),
|
||||
path("cette-semaine/", week_view, name="cette_semaine"),
|
||||
path("ce-mois-ci", month_view, name="ce_mois_ci"),
|
||||
path("tag/<t>/", view_tag, name="view_tag"),
|
||||
|
@ -473,6 +473,28 @@ def day_view(request, year=None, month=None, day=None):
|
||||
return render(request, "agenda_culturel/page-day.html", context)
|
||||
|
||||
|
||||
def upcoming_events(request, year=None, month=None, day=None):
|
||||
now = date.today()
|
||||
if year is None:
|
||||
year = now.year
|
||||
if month is None:
|
||||
month = now.month
|
||||
if day is None:
|
||||
day = now.day
|
||||
|
||||
day = date(year, month, day)
|
||||
|
||||
request = EventFilter.set_default_values(request)
|
||||
filter = EventFilter(request.GET, get_event_qs(request), request=request)
|
||||
cal = CalendarList(now, now + timedelta(days=4), filter, True)
|
||||
|
||||
context = {
|
||||
"calendar": cal,
|
||||
"now": now,
|
||||
"filter": filter,
|
||||
}
|
||||
return render(request, "agenda_culturel/page-upcoming.html", context)
|
||||
|
||||
def view_tag(request, t):
|
||||
events = Event.objects.filter(tags__contains=[t]).order_by(
|
||||
"start_day", "start_time"
|
||||
|
Loading…
x
Reference in New Issue
Block a user