forked from rc/aircox
		
	allow only one program or diffusion for pages;
in cms.signals, manage cases when Diffusion.initial is set/changed & clean up; fix bug in loglist nav when max_age is 0 (no limit); work on design for date lists; fix bug in player on item removal;
This commit is contained in:
		@ -922,7 +922,7 @@ class Diffusion(models.Model):
 | 
			
		||||
            return super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        if self.initial:
 | 
			
		||||
            # force link to the top initial diffusion
 | 
			
		||||
            # force link to the first diffusion
 | 
			
		||||
            if self.initial.initial:
 | 
			
		||||
                self.initial = self.initial.initial
 | 
			
		||||
            self.program = self.initial.program
 | 
			
		||||
 | 
			
		||||
@ -420,7 +420,7 @@ class Publication(BasePage):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramPage(Publication):
 | 
			
		||||
    program = models.ForeignKey(
 | 
			
		||||
    program = models.OneToOneField(
 | 
			
		||||
        aircox.models.Program,
 | 
			
		||||
        verbose_name = _('program'),
 | 
			
		||||
        related_name = 'page',
 | 
			
		||||
@ -515,11 +515,11 @@ class Track(aircox.models.Track,Orderable):
 | 
			
		||||
class DiffusionPage(Publication):
 | 
			
		||||
    order_field = 'diffusion__start'
 | 
			
		||||
 | 
			
		||||
    diffusion = models.ForeignKey(
 | 
			
		||||
    diffusion = models.OneToOneField(
 | 
			
		||||
        aircox.models.Diffusion,
 | 
			
		||||
        verbose_name = _('diffusion'),
 | 
			
		||||
        related_name = 'page',
 | 
			
		||||
        null=True,
 | 
			
		||||
        null=True, blank = True,
 | 
			
		||||
        # not blank because we enforce the connection to a diffusion
 | 
			
		||||
        #   (still users always tend to break sth)
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
@ -548,6 +548,9 @@ class DiffusionPage(Publication):
 | 
			
		||||
        ], heading=_('Content')),
 | 
			
		||||
        InlinePanel('links', label=_('Links'))
 | 
			
		||||
    ] + Page.promote_panels
 | 
			
		||||
    settings_panels = Publication.settings_panels + [
 | 
			
		||||
        FieldPanel('diffusion')
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_diffusion(cl, diff, model = None, **kwargs):
 | 
			
		||||
@ -572,8 +575,8 @@ class DiffusionPage(Publication):
 | 
			
		||||
        """
 | 
			
		||||
        initial = diff.initial or diff
 | 
			
		||||
 | 
			
		||||
        if initial.page.all().count():
 | 
			
		||||
            item = initial.page.all().first()
 | 
			
		||||
        if hasattr(initial, 'page'):
 | 
			
		||||
            item = initial.page
 | 
			
		||||
        else:
 | 
			
		||||
            item = cl.from_diffusion(diff, ListItem)
 | 
			
		||||
            item.live = True
 | 
			
		||||
@ -590,6 +593,13 @@ class DiffusionPage(Publication):
 | 
			
		||||
 | 
			
		||||
        item.date = diff.start
 | 
			
		||||
        item.css_class = 'diffusion'
 | 
			
		||||
 | 
			
		||||
        now = tz.now()
 | 
			
		||||
        if diff.start <= now <= diff.end:
 | 
			
		||||
            print('now!', diff)
 | 
			
		||||
            item.css_class = ' now'
 | 
			
		||||
            item.now = True
 | 
			
		||||
 | 
			
		||||
        return item
 | 
			
		||||
 | 
			
		||||
    def get_archive(self):
 | 
			
		||||
@ -721,7 +731,7 @@ class LogsPage(DatedListPage):
 | 
			
		||||
        on_delete = models.SET_NULL,
 | 
			
		||||
        help_text = _('(required) related station')
 | 
			
		||||
    )
 | 
			
		||||
    age_max = models.IntegerField(
 | 
			
		||||
    max_age = models.IntegerField(
 | 
			
		||||
        _('maximum age'),
 | 
			
		||||
        default=15,
 | 
			
		||||
        help_text = _('maximum days in the past allowed to be shown. '
 | 
			
		||||
@ -740,7 +750,7 @@ class LogsPage(DatedListPage):
 | 
			
		||||
    content_panels = DatedListPage.content_panels + [
 | 
			
		||||
        MultiFieldPanel([
 | 
			
		||||
            FieldPanel('station'),
 | 
			
		||||
            FieldPanel('age_max'),
 | 
			
		||||
            FieldPanel('max_age'),
 | 
			
		||||
            FieldPanel('reverse'),
 | 
			
		||||
        ], heading=_('Configuration')),
 | 
			
		||||
    ]
 | 
			
		||||
@ -749,20 +759,21 @@ class LogsPage(DatedListPage):
 | 
			
		||||
        """
 | 
			
		||||
        Return a list of dates availables for the navigation
 | 
			
		||||
        """
 | 
			
		||||
        # there might be a bug if age_max < nav_days
 | 
			
		||||
        # there might be a bug if max_age < nav_days
 | 
			
		||||
        today = tz.now().date()
 | 
			
		||||
        first = min(date, today)
 | 
			
		||||
        first = max( first - tz.timedelta(days = self.nav_days-1),
 | 
			
		||||
                     today - tz.timedelta(days = self.age_max))
 | 
			
		||||
        first = first - tz.timedelta(days = self.nav_days-1)
 | 
			
		||||
        if self.max_age:
 | 
			
		||||
             first = max(first, today - tz.timedelta(days = self.max_age))
 | 
			
		||||
        return [ first + tz.timedelta(days=i)
 | 
			
		||||
                    for i in range(0, self.nav_days) ]
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self, request, context):
 | 
			
		||||
        today = tz.now().date()
 | 
			
		||||
        if context['nav_dates']['next'] > today:
 | 
			
		||||
        if self.max_age and context['nav_dates']['next'] > today:
 | 
			
		||||
            context['nav_dates']['next'] = None
 | 
			
		||||
        if context['nav_dates']['prev'] < \
 | 
			
		||||
                today - tz.timedelta(days = self.age_max):
 | 
			
		||||
        if self.max_age and context['nav_dates']['prev'] < \
 | 
			
		||||
                today - tz.timedelta(days = self.max_age):
 | 
			
		||||
            context['nav_dates']['prev'] = None
 | 
			
		||||
 | 
			
		||||
        logs = []
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.db.models.signals import post_save, pre_delete
 | 
			
		||||
from django.dispatch import receiver
 | 
			
		||||
from django.utils.translation import ugettext as _, ugettext_lazy
 | 
			
		||||
@ -142,17 +143,49 @@ def program_post_saved(sender, instance, created, *args, **kwargs):
 | 
			
		||||
    parent.add_child(instance = page)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def void_pages_of(page_set):
 | 
			
		||||
    """
 | 
			
		||||
    Return a queryset from page_set that select only empty pages. If
 | 
			
		||||
    `inverse` is True, select only pages that are not empty.
 | 
			
		||||
 | 
			
		||||
    Empty is defined on theses parameters:
 | 
			
		||||
        - `numchild = 0` => no children
 | 
			
		||||
        - no headline
 | 
			
		||||
        - no body
 | 
			
		||||
    """
 | 
			
		||||
    if not page_set.count():
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    page_set = page_set.filter(numchild = 0)
 | 
			
		||||
 | 
			
		||||
    # as publications
 | 
			
		||||
    page_set = models.Publication.objects.filter(
 | 
			
		||||
        page_ptr_id__in = page_set.values('pk')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # only empty
 | 
			
		||||
    q = (Q(headline__isnull = True) | Q(headline = '')) & \
 | 
			
		||||
        (Q(body__isnull = True) | Q(body = ''))
 | 
			
		||||
    return page_set.filter(q)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@receiver(pre_delete, sender=aircox.Program)
 | 
			
		||||
def program_post_deleted(sender, instance, *args, **kwargs):
 | 
			
		||||
    for page in instance.page.all():
 | 
			
		||||
        if page.specific.body or Page.objects.descendant_of(page).count():
 | 
			
		||||
            continue
 | 
			
		||||
        page.delete()
 | 
			
		||||
    void_pages_of(instance.page).delete()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@receiver(post_save, sender=aircox.Diffusion)
 | 
			
		||||
def diffusion_post_saved(sender, instance, created, *args, **kwargs):
 | 
			
		||||
    if not created or instance.page.count():
 | 
			
		||||
    initial = instance.initial
 | 
			
		||||
    if initial:
 | 
			
		||||
        if not created and hasattr(instance, 'page'):
 | 
			
		||||
            # fuck it
 | 
			
		||||
            page = instance.page
 | 
			
		||||
            page.diffusion = None
 | 
			
		||||
            page.save()
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    if instance.page:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    page = models.DiffusionPage.from_diffusion(
 | 
			
		||||
@ -164,9 +197,5 @@ def diffusion_post_saved(sender, instance, created, *args, **kwargs):
 | 
			
		||||
 | 
			
		||||
@receiver(pre_delete, sender=aircox.Diffusion)
 | 
			
		||||
def diffusion_pre_deleted(sender, instance, *args, **kwargs):
 | 
			
		||||
    for page in instance.page.all():
 | 
			
		||||
        if page.specific.body or Page.objects.descendant_of(page).count():
 | 
			
		||||
            continue
 | 
			
		||||
        page.delete()
 | 
			
		||||
 | 
			
		||||
    void_pages_of(instance.page).delete()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -187,25 +187,13 @@ ul.list, .list > ul {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** content: list items in full page **/
 | 
			
		||||
.content > .list .list_item {
 | 
			
		||||
.content > .list:not(.date_list) .list_item {
 | 
			
		||||
    min-width: 20em;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    min-height: 2.5em;
 | 
			
		||||
    margin: 0.4em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.content > .list .date_list_item time {
 | 
			
		||||
    color: #007EDF;
 | 
			
		||||
    display: block;
 | 
			
		||||
    margin-left: -0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.content > .list .date_list_item {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** content: date list **/
 | 
			
		||||
.date_list nav {
 | 
			
		||||
    text-align:center;
 | 
			
		||||
@ -246,6 +234,40 @@ ul.list, .list > ul {
 | 
			
		||||
    margin-top: 0em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.date_list_item time {
 | 
			
		||||
    color: #007EDF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.date_list_item.now {
 | 
			
		||||
    font-size: 1.2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    .date_list_item img.now {
 | 
			
		||||
        width: 1.3em;
 | 
			
		||||
        vertical-align: middle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** content: date list in full page **/
 | 
			
		||||
.content > .date_list .date_list_item time {
 | 
			
		||||
    color: #007EDF;
 | 
			
		||||
    font-size: 1.1em;
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.content > .date_list .date_list_item:nth-child(2n+1) {
 | 
			
		||||
    box-shadow: inset 0em 0em 3em rgba(0, 124, 226, 0.1);
 | 
			
		||||
    background-color: rgba(0, 124, 226, 0.05);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.content > .date_list {
 | 
			
		||||
    padding: 0 10%;
 | 
			
		||||
    margin: auto;
 | 
			
		||||
    width: 80%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** content: comments **/
 | 
			
		||||
.comments form input:not([type=checkbox]),
 | 
			
		||||
 | 
			
		||||
@ -148,8 +148,10 @@ Playlist.prototype = {
 | 
			
		||||
        this.playlist.removeChild(sound.item);
 | 
			
		||||
        this.save();
 | 
			
		||||
 | 
			
		||||
        this.player.stop()
 | 
			
		||||
        this.next(false);
 | 
			
		||||
        if(this.sound == sound) {
 | 
			
		||||
            this.player.stop()
 | 
			
		||||
            this.next(false);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    select: function(sound, play = true) {
 | 
			
		||||
 | 
			
		||||
@ -3,16 +3,24 @@ Configurable item to be put in a dated list. Work like list_item, the layout
 | 
			
		||||
is just a bit different.
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
 | 
			
		||||
{% load static %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% load wagtailimages_tags %}
 | 
			
		||||
 | 
			
		||||
<a {% if item.url %}href="{{ item.url }}" {% endif %}
 | 
			
		||||
    class="list_item date_list_item {% if not item_big_cover %}flex_row {% endif %}{% if item.css_class %}{{ item.css_class }}{% endif %}"
 | 
			
		||||
    class="list_item date_list_item {{ item.css_class|default_if_none:"" }}{% if not item_big_cover %} flex_row{% endif %}"
 | 
			
		||||
    title="{{ item.date|date:"l d F Y" }}"
 | 
			
		||||
    >
 | 
			
		||||
 | 
			
		||||
    {% if not item.show_in_menus and item.date and item_date_format != '' %}
 | 
			
		||||
    {% with date_format=item_date_format|default_if_none:'l d F, H:i' %}
 | 
			
		||||
    <time datetime="{{ item.date }}">
 | 
			
		||||
        {% if item.now %}
 | 
			
		||||
        <img src="{% static "aircox/images/play.png" %}"
 | 
			
		||||
            title="{% trans "happening now!" %}"
 | 
			
		||||
            alt="{% trans "happening now!" %}" class="now">
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        {{ item.date|date:date_format }}
 | 
			
		||||
    </time>
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ Options:
 | 
			
		||||
{% load wagtailimages_tags %}
 | 
			
		||||
 | 
			
		||||
<a {% if item.url %}href="{{ item.url }}" {% endif %}
 | 
			
		||||
    class="list_item {% if not item_big_cover %}flex_row {% endif %}{% if item.css_class %}{{ item.css_class }}{% endif %}">
 | 
			
		||||
    class="list_item {{ item.css_class|default_if_none:"" }}{% if not item_big_cover %} flex_row{% endif %}">
 | 
			
		||||
    {% if item.cover %}
 | 
			
		||||
        {% if item_big_cover %}
 | 
			
		||||
            {% image item.cover max-640x480 class="cover big" height="" width="" %}
 | 
			
		||||
@ -23,6 +23,7 @@ Options:
 | 
			
		||||
            {% image item.cover fill-64x64 class="cover small" %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    <div class="flex_item">
 | 
			
		||||
        <h3 class="title">{{ item.title }}</h3>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -222,11 +222,16 @@ class GenericMenu(Menu):
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def page_of(item):
 | 
			
		||||
        return item.page
 | 
			
		||||
 | 
			
		||||
    def page_url(self, item):
 | 
			
		||||
        if item.page.count():
 | 
			
		||||
        page = self.page_of(item)
 | 
			
		||||
        if page:
 | 
			
		||||
            name =  'wagtailadmin_explore' \
 | 
			
		||||
                    if self.explore else 'wagtailadmin_pages:edit'
 | 
			
		||||
            return reverse(name, args=[item.page.first().id])
 | 
			
		||||
            return reverse(name, args=[page.id])
 | 
			
		||||
 | 
			
		||||
        parent_page = self.get_parent(item)
 | 
			
		||||
        if not parent_page:
 | 
			
		||||
@ -311,7 +316,7 @@ class TodayMenu(GenericMenu):
 | 
			
		||||
 | 
			
		||||
        attrs = {}
 | 
			
		||||
 | 
			
		||||
        qs = PageRevision.objects.filter(page = item.page.first())
 | 
			
		||||
        qs = PageRevision.objects.filter(page = item.page)
 | 
			
		||||
        if qs.count():
 | 
			
		||||
            headline = qs.latest('created_at').content_json
 | 
			
		||||
            headline = json.loads(headline).get('headline')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								notes.md
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								notes.md
									
									
									
									
									
								
							@ -21,6 +21,7 @@ This file is used as a reminder, can be used as crappy documentation too.
 | 
			
		||||
    - category page
 | 
			
		||||
    - for timetable, logs, etc. make station optional
 | 
			
		||||
    - django's message css displayed on pages when element is modified (remove bullet)
 | 
			
		||||
    - articles preview in different format
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# conventions
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user