redesign default layout; add new sections type (Timetable, Logs, Search); fix multiple things & minors changes in some sections; new settings for referencing; new templates for date_list's items; etc
This commit is contained in:
		@ -40,20 +40,22 @@ class WebsiteSettings(BaseSetting):
 | 
			
		||||
    #   exist. Update all dependent code such as signal handling
 | 
			
		||||
 | 
			
		||||
    # general website information
 | 
			
		||||
    logo = models.ForeignKey(
 | 
			
		||||
        'wagtailimages.Image',
 | 
			
		||||
        verbose_name = _('logo'),
 | 
			
		||||
        null=True, blank=True, on_delete=models.SET_NULL,
 | 
			
		||||
        related_name='+',
 | 
			
		||||
        help_text = _('logo of the website'),
 | 
			
		||||
    )
 | 
			
		||||
    favicon = models.ForeignKey(
 | 
			
		||||
        'wagtailimages.Image',
 | 
			
		||||
    favicon = models.ImageField(
 | 
			
		||||
        verbose_name = _('favicon'),
 | 
			
		||||
        null=True, blank=True,
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        related_name='+',
 | 
			
		||||
        help_text = _('favicon for the website'),
 | 
			
		||||
        help_text = _('small logo for the website displayed in the browser'),
 | 
			
		||||
    )
 | 
			
		||||
    tags = models.CharField(
 | 
			
		||||
        _('tags'),
 | 
			
		||||
        max_length=256,
 | 
			
		||||
        null=True, blank=True,
 | 
			
		||||
        help_text = _('tags describing the website; used for referencing'),
 | 
			
		||||
    )
 | 
			
		||||
    description = models.CharField(
 | 
			
		||||
        _('public description'),
 | 
			
		||||
        max_length=256,
 | 
			
		||||
        null=True, blank=True,
 | 
			
		||||
        help_text = _('public description of the website; used for referencing'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # comments
 | 
			
		||||
@ -107,8 +109,11 @@ class WebsiteSettings(BaseSetting):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    panels = [
 | 
			
		||||
        ImageChooserPanel('logo'),
 | 
			
		||||
        ImageChooserPanel('favicon'),
 | 
			
		||||
        MultiFieldPanel([
 | 
			
		||||
            FieldPanel('favicon'),
 | 
			
		||||
            FieldPanel('tags'),
 | 
			
		||||
            FieldPanel('description'),
 | 
			
		||||
        ], heading=_('promotion')),
 | 
			
		||||
        MultiFieldPanel([
 | 
			
		||||
            FieldPanel('allow_comments'),
 | 
			
		||||
            FieldPanel('accept_comments'),
 | 
			
		||||
@ -252,7 +257,8 @@ class Publication(Page):
 | 
			
		||||
        FieldPanel('allow_comments'),
 | 
			
		||||
    ]
 | 
			
		||||
    search_fields = [
 | 
			
		||||
        index.SearchField('body'),
 | 
			
		||||
        index.SearchField('title', partial_match=True),
 | 
			
		||||
        index.SearchField('body', partial_match=True),
 | 
			
		||||
        index.FilterField('live'),
 | 
			
		||||
        index.FilterField('show_in_menus'),
 | 
			
		||||
    ]
 | 
			
		||||
@ -285,7 +291,7 @@ class Publication(Page):
 | 
			
		||||
            context['comment_form'] = CommentForm()
 | 
			
		||||
 | 
			
		||||
        if view == 'list':
 | 
			
		||||
            context['object_list'] = ListPage.get_queryset(
 | 
			
		||||
            context['object_list'] = ListBase.from_request(
 | 
			
		||||
                request, context = context, related = self
 | 
			
		||||
            )
 | 
			
		||||
        return context
 | 
			
		||||
@ -448,11 +454,17 @@ class DiffusionPage(Publication):
 | 
			
		||||
            item = cl.from_diffusion(diff, ListItem)
 | 
			
		||||
            item.live = True
 | 
			
		||||
 | 
			
		||||
        item.info = []
 | 
			
		||||
        if diff.initial:
 | 
			
		||||
            item.info = _('Rerun of %(date)s') % {
 | 
			
		||||
            item.info.append(_('Rerun of %(date)s') % {
 | 
			
		||||
                'date': diff.initial.start.strftime('%A %d')
 | 
			
		||||
            }
 | 
			
		||||
        diff.css_class = 'diffusion'
 | 
			
		||||
            })
 | 
			
		||||
        if diff.type == diff.Type.canceled:
 | 
			
		||||
            item.info.append(_('Cancelled'))
 | 
			
		||||
        item.info = '; '.join(item.info)
 | 
			
		||||
 | 
			
		||||
        item.date = diff.start
 | 
			
		||||
        item.css_class = 'diffusion'
 | 
			
		||||
        return item
 | 
			
		||||
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
@ -460,6 +472,7 @@ class DiffusionPage(Publication):
 | 
			
		||||
            self.date = self.diffusion.start
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EventPageQuerySet(PageQuerySet):
 | 
			
		||||
    def upcoming(self):
 | 
			
		||||
        now = tz.now().date()
 | 
			
		||||
@ -587,8 +600,7 @@ class LogsPage(DatedListPage):
 | 
			
		||||
        verbose_name = _('station'),
 | 
			
		||||
        null = True,
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        help_text = _('(required for logs) the station on which the logs '
 | 
			
		||||
                      'happened')
 | 
			
		||||
        help_text = _('(required) the station on which the logs happened')
 | 
			
		||||
    )
 | 
			
		||||
    age_max = models.IntegerField(
 | 
			
		||||
        _('maximum age'),
 | 
			
		||||
@ -608,24 +620,6 @@ class LogsPage(DatedListPage):
 | 
			
		||||
        ], heading=_('Configuration')),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def as_item(cl, log):
 | 
			
		||||
        """
 | 
			
		||||
        Return a log object as a DiffusionPage or ListItem.
 | 
			
		||||
        Supports: Log/Track, Diffusion
 | 
			
		||||
        """
 | 
			
		||||
        if type(log) == programs.Diffusion:
 | 
			
		||||
            return DiffusionPage.as_item(log)
 | 
			
		||||
        return ListItem(
 | 
			
		||||
            title = '{artist} -- {title}'.format(
 | 
			
		||||
                artist = log.related.artist,
 | 
			
		||||
                title = log.related.title,
 | 
			
		||||
            ),
 | 
			
		||||
            summary = log.related.info,
 | 
			
		||||
            date = log.date,
 | 
			
		||||
            info = '♫',
 | 
			
		||||
            css_class = 'track'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def get_nav_dates(self, date):
 | 
			
		||||
        """
 | 
			
		||||
        Return a list of dates availables for the navigation
 | 
			
		||||
@ -648,8 +642,8 @@ class LogsPage(DatedListPage):
 | 
			
		||||
 | 
			
		||||
        logs = []
 | 
			
		||||
        for date in context['nav_dates']['dates']:
 | 
			
		||||
            items = self.station.on_air(date = date)
 | 
			
		||||
            items = [ self.as_item(item) for item in items ]
 | 
			
		||||
            items = [ SectionLogsList.as_item(item)
 | 
			
		||||
                        for item in self.station.on_air(date = date) ]
 | 
			
		||||
            logs.append((date, items))
 | 
			
		||||
        return logs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										213
									
								
								cms/sections.py
									
									
									
									
									
								
							
							
						
						
									
										213
									
								
								cms/sections.py
									
									
									
									
									
								
							@ -34,7 +34,7 @@ from taggit.models import TaggedItemBase
 | 
			
		||||
 | 
			
		||||
# aircox
 | 
			
		||||
import aircox.programs.models as programs
 | 
			
		||||
 | 
			
		||||
import aircox.controllers.models as controllers
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def related_pages_filter(reset_cache=False):
 | 
			
		||||
@ -102,6 +102,11 @@ class RelatedLinkBase(Orderable):
 | 
			
		||||
        related_name='+',
 | 
			
		||||
        help_text = _('icon to display before the url'),
 | 
			
		||||
    )
 | 
			
		||||
    # icon = models.ImageField(
 | 
			
		||||
    #    verbose_name = _('icon'),
 | 
			
		||||
    #    null=True, blank=True,
 | 
			
		||||
    #    help_text = _('icon to display before the url'),
 | 
			
		||||
    #)
 | 
			
		||||
    text = models.CharField(
 | 
			
		||||
        _('text'),
 | 
			
		||||
        max_length = 64,
 | 
			
		||||
@ -327,7 +332,9 @@ class ListBase(models.Model):
 | 
			
		||||
        search = request.GET.get('search')
 | 
			
		||||
        if search:
 | 
			
		||||
            kwargs['terms'] = search
 | 
			
		||||
            print(search, qs)
 | 
			
		||||
            qs = qs.search(search)
 | 
			
		||||
            print(qs.count())
 | 
			
		||||
 | 
			
		||||
        set('list_selector', kwargs)
 | 
			
		||||
 | 
			
		||||
@ -534,7 +541,6 @@ class SectionItemMeta(models.base.ModelBase):
 | 
			
		||||
                    cl.template = 'cms/sections/section_item.html'
 | 
			
		||||
        return cl
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionItem(models.Model,metaclass=SectionItemMeta):
 | 
			
		||||
    """
 | 
			
		||||
@ -554,15 +560,6 @@ class SectionItem(models.Model,metaclass=SectionItemMeta):
 | 
			
		||||
        default = False,
 | 
			
		||||
        help_text=_('if set show a title at the head of the section'),
 | 
			
		||||
    )
 | 
			
		||||
    is_related = models.BooleanField(
 | 
			
		||||
        _('is related'),
 | 
			
		||||
        default = False,
 | 
			
		||||
        help_text=_(
 | 
			
		||||
            'if set, section is related to the page being processed '
 | 
			
		||||
            'e.g rendering a list of links will use thoses of the '
 | 
			
		||||
            'publication instead of an assigned one.'
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    css_class = models.CharField(
 | 
			
		||||
        _('CSS class'),
 | 
			
		||||
        max_length=64,
 | 
			
		||||
@ -574,7 +571,6 @@ class SectionItem(models.Model,metaclass=SectionItemMeta):
 | 
			
		||||
            FieldPanel('title'),
 | 
			
		||||
            FieldPanel('show_title'),
 | 
			
		||||
            FieldPanel('css_class'),
 | 
			
		||||
            FieldPanel('is_related'),
 | 
			
		||||
        ], heading=_('General')),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
@ -593,12 +589,7 @@ class SectionItem(models.Model,metaclass=SectionItemMeta):
 | 
			
		||||
            self.real_type = type(self).__name__.lower()
 | 
			
		||||
        return super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def related_page_attr(self, page, attr):
 | 
			
		||||
        return self.is_related and hasattr(page, attr) \
 | 
			
		||||
                and getattr(page, attr)
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
    def get_context(self, request, page):
 | 
			
		||||
        """
 | 
			
		||||
        Default context attributes:
 | 
			
		||||
        * self: section being rendered
 | 
			
		||||
@ -636,6 +627,33 @@ class SectionItem(models.Model,metaclass=SectionItemMeta):
 | 
			
		||||
            self.title or self.pk
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
class SectionRelativeItem(SectionItem):
 | 
			
		||||
    is_related = models.BooleanField(
 | 
			
		||||
        _('is related'),
 | 
			
		||||
        default = False,
 | 
			
		||||
        help_text=_(
 | 
			
		||||
            'if set, section is related to the page being processed '
 | 
			
		||||
            'e.g rendering a list of links will use thoses of the '
 | 
			
		||||
            'publication instead of an assigned one.'
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract=True
 | 
			
		||||
 | 
			
		||||
    panels = SectionItem.panels.copy()
 | 
			
		||||
    panels[-1] = MultiFieldPanel(
 | 
			
		||||
        panels[-1].children + [ FieldPanel('is_related') ],
 | 
			
		||||
        heading = panels[-1].heading
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def related_attr(self, page, attr):
 | 
			
		||||
        """
 | 
			
		||||
        Return an attribute from the given page if self.is_related,
 | 
			
		||||
        otherwise retrieve the attribute from self.
 | 
			
		||||
        """
 | 
			
		||||
        return self.is_related and hasattr(page, attr) \
 | 
			
		||||
                and getattr(page, attr)
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionText(SectionItem):
 | 
			
		||||
@ -644,14 +662,14 @@ class SectionText(SectionItem):
 | 
			
		||||
        FieldPanel('body'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
    def get_context(self, request, page):
 | 
			
		||||
        from wagtail.wagtailcore.rich_text import expand_db_html
 | 
			
		||||
        context = super().get_context(request, page, *args, **kwargs)
 | 
			
		||||
        context = super().get_context(request, page)
 | 
			
		||||
        context['content'] = expand_db_html(self.body)
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionImage(SectionItem):
 | 
			
		||||
class SectionImage(SectionRelativeItem):
 | 
			
		||||
    class ResizeMode(IntEnum):
 | 
			
		||||
        max = 0x00
 | 
			
		||||
        min = 0x01
 | 
			
		||||
@ -685,7 +703,10 @@ class SectionImage(SectionItem):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    panels = SectionItem.panels + [
 | 
			
		||||
        ImageChooserPanel('image'),
 | 
			
		||||
        MultiFieldPanel([
 | 
			
		||||
            ImageChooserPanel('image'),
 | 
			
		||||
            FieldPanel('image'),
 | 
			
		||||
        ], heading=_('Source')),
 | 
			
		||||
        MultiFieldPanel([
 | 
			
		||||
            FieldPanel('width'),
 | 
			
		||||
            FieldPanel('height'),
 | 
			
		||||
@ -693,21 +714,25 @@ class SectionImage(SectionItem):
 | 
			
		||||
        ], heading=_('Resizing'))
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
        context = super().get_context(request, page, *args, **kwargs)
 | 
			
		||||
    def get_filter(self):
 | 
			
		||||
        return \
 | 
			
		||||
            'original' if not (self.height or self.width) else \
 | 
			
		||||
            'width-{}'.format(self.width) if not self.height else \
 | 
			
		||||
            'height-{}'.format(self.height) if not self.width else \
 | 
			
		||||
            '{}-{}x{}'.format(
 | 
			
		||||
                self.get_resize_mode_display(),
 | 
			
		||||
                self.width, self.height
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        image = self.related_page_attr(page, 'cover') or self.image
 | 
			
		||||
    def get_context(self, request, page):
 | 
			
		||||
        context = super().get_context(request, page)
 | 
			
		||||
 | 
			
		||||
        image = self.related_attr(page, 'cover') or self.image
 | 
			
		||||
        if not image:
 | 
			
		||||
            return context
 | 
			
		||||
 | 
			
		||||
        if self.width or self.height:
 | 
			
		||||
            filter_spec = \
 | 
			
		||||
                'width-{}'.format(self.width) if not self.height else \
 | 
			
		||||
                'height-{}'.format(self.height) if not self.width else \
 | 
			
		||||
                '{}-{}x{}'.format(
 | 
			
		||||
                    self.get_resize_mode_display(),
 | 
			
		||||
                    self.width, self.height
 | 
			
		||||
                )
 | 
			
		||||
            filter_spec = self.get_filter()
 | 
			
		||||
            filter_spec = (image.id, filter_spec)
 | 
			
		||||
            url = reverse(
 | 
			
		||||
                'wagtailimages_serve',
 | 
			
		||||
@ -732,7 +757,7 @@ class SectionLink(RelatedLinkBase, SectionItem):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionLinkList(SectionItem, ClusterableModel):
 | 
			
		||||
class SectionLinkList(SectionRelativeItem, ClusterableModel):
 | 
			
		||||
    """
 | 
			
		||||
    Render a list of links. If related to the current page, print
 | 
			
		||||
    the page's links otherwise, the assigned link list.
 | 
			
		||||
@ -746,16 +771,15 @@ class SectionLinkList(SectionItem, ClusterableModel):
 | 
			
		||||
        ))
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
        context = super().get_context(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        links = self.related_page_attr(page, 'related_link') or self.links
 | 
			
		||||
        context['object_list'] = links
 | 
			
		||||
    def get_context(self, request, page):
 | 
			
		||||
        context = super().get_context(request, page)
 | 
			
		||||
        links = self.related_attr(page, 'related_link') or self.links
 | 
			
		||||
        context['object_list'] = links.all()
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionList(ListBase, SectionItem):
 | 
			
		||||
class SectionList(ListBase, SectionRelativeItem):
 | 
			
		||||
    """
 | 
			
		||||
    This one is quite badass, but needed: render a list of pages
 | 
			
		||||
    using given parameters (cf. ListBase).
 | 
			
		||||
@ -789,18 +813,17 @@ class SectionList(ListBase, SectionItem):
 | 
			
		||||
        ], heading=_('Rendering')),
 | 
			
		||||
    ] + ListBase.panels
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
    def get_context(self, request, page):
 | 
			
		||||
        from aircox.cms.models import Publication
 | 
			
		||||
        context = super().get_context(request, page, *args, **kwargs)
 | 
			
		||||
        context = super().get_context(request, page)
 | 
			
		||||
 | 
			
		||||
        qs = self.get_queryset()
 | 
			
		||||
        qs = qs.live()
 | 
			
		||||
        if self.focus_available:
 | 
			
		||||
            focus = qs.type(Publication).filter(focus = True).first()
 | 
			
		||||
            if focus:
 | 
			
		||||
                focus.css_class = \
 | 
			
		||||
                    focus.css_class + ' focus' if focus.css_class else 'focus'
 | 
			
		||||
                qs = qs.exclude(focus.page)
 | 
			
		||||
                focus.css_class = 'focus'
 | 
			
		||||
                qs = qs.exclude(pk = focus.pk)
 | 
			
		||||
        else:
 | 
			
		||||
            focus = None
 | 
			
		||||
        pages = qs[:self.count - (focus != None)]
 | 
			
		||||
@ -814,8 +837,65 @@ class SectionList(ListBase, SectionItem):
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionLogsList(SectionItem):
 | 
			
		||||
    station = models.ForeignKey(
 | 
			
		||||
        controllers.Station,
 | 
			
		||||
        verbose_name = _('station'),
 | 
			
		||||
        null = True,
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        help_text = _('(required) the station on which the logs happened')
 | 
			
		||||
    )
 | 
			
		||||
    count = models.SmallIntegerField(
 | 
			
		||||
        _('count'),
 | 
			
		||||
        default = 5,
 | 
			
		||||
        help_text = _('number of items to display in the list (max 100)'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _('list of logs')
 | 
			
		||||
        verbose_name_plural = _('lists of logs')
 | 
			
		||||
 | 
			
		||||
    panels = SectionItem.panels + [
 | 
			
		||||
        FieldPanel('station'),
 | 
			
		||||
        FieldPanel('count'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def as_item(log):
 | 
			
		||||
        """
 | 
			
		||||
        Return a log object as a DiffusionPage or ListItem.
 | 
			
		||||
        Supports: Log/Track, Diffusion
 | 
			
		||||
        """
 | 
			
		||||
        from aircox.cms.models import DiffusionPage
 | 
			
		||||
        if type(log) == programs.Diffusion:
 | 
			
		||||
            return DiffusionPage.as_item(log)
 | 
			
		||||
        return ListItem(
 | 
			
		||||
            title = '{artist} -- {title}'.format(
 | 
			
		||||
                artist = log.related.artist,
 | 
			
		||||
                title = log.related.title,
 | 
			
		||||
            ),
 | 
			
		||||
            summary = log.related.info,
 | 
			
		||||
            date = log.date,
 | 
			
		||||
            info = '♫',
 | 
			
		||||
            css_class = 'track'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page):
 | 
			
		||||
        context = super().get_context(request, page)
 | 
			
		||||
        context['object_list'] = [
 | 
			
		||||
            self.as_item(item)
 | 
			
		||||
            for item in self.station.on_air(count = min(self.count, 100))
 | 
			
		||||
        ]
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionTimetable(SectionItem,DatedListBase):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _('timetable')
 | 
			
		||||
        verbose_name_plural = _('timetable')
 | 
			
		||||
 | 
			
		||||
    panels = SectionItem.panels + DatedListBase.panels
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self, context):
 | 
			
		||||
@ -827,27 +907,48 @@ class SectionTimetable(SectionItem,DatedListBase):
 | 
			
		||||
            diffs.append((date, items))
 | 
			
		||||
        return diffs
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
        context = super().get_context(request, page, *args, **kwargs)
 | 
			
		||||
    def get_context(self, request, page):
 | 
			
		||||
        context = super().get_context(request, page)
 | 
			
		||||
        context.update(self.get_date_context())
 | 
			
		||||
        context['object_list'] = self.get_queryset(context)
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionLogs(SectionItem):
 | 
			
		||||
    count = models.SmallIntegerField(
 | 
			
		||||
        _('count'),
 | 
			
		||||
        default = 5,
 | 
			
		||||
        help_text = _('number of items to display in the list'),
 | 
			
		||||
class SectionPublicationInfo(SectionItem):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _('section with publication\'s info')
 | 
			
		||||
        verbose_name = _('sections with publication\'s info')
 | 
			
		||||
 | 
			
		||||
@register_snippet
 | 
			
		||||
class SectionSearchField(SectionItem):
 | 
			
		||||
    page = models.ForeignKey(
 | 
			
		||||
        'cms.ListPage',
 | 
			
		||||
        verbose_name = _('search page'),
 | 
			
		||||
        blank = True, null = True,
 | 
			
		||||
        help_text=_('page used to display the results'),
 | 
			
		||||
    )
 | 
			
		||||
    default_text = models.CharField(
 | 
			
		||||
        _('default text'),
 | 
			
		||||
        max_length=32,
 | 
			
		||||
        default=_('search'),
 | 
			
		||||
        help_text=_('text to display when the search field is empty'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _('search field')
 | 
			
		||||
        verbose_name_plural = _('search fields')
 | 
			
		||||
 | 
			
		||||
    panels = SectionItem.panels + [
 | 
			
		||||
        FieldPanel('count'),
 | 
			
		||||
        PageChooserPanel('page'),
 | 
			
		||||
        FieldPanel('default_text'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page, *args, **kwargs):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_context(self, request, page):
 | 
			
		||||
        from aircox.cms.models import ListPage
 | 
			
		||||
        context = super().get_context(request, page)
 | 
			
		||||
        list_page = self.page or ListPage.objects.live().first()
 | 
			
		||||
        context['list_page'] = list_page
 | 
			
		||||
        print(context, self.template)
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										104
									
								
								cms/static/cms/css/layout.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								cms/static/cms/css/layout.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,104 @@
 | 
			
		||||
/**
 | 
			
		||||
 *  Define rules for the default layouts, and some useful classes
 | 
			
		||||
 */
 | 
			
		||||
body {
 | 
			
		||||
    margin: 0em;
 | 
			
		||||
    padding: 0em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1, h2, h3, h4, h5 {
 | 
			
		||||
    margin: 0.4em 0em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** classes: flex **/
 | 
			
		||||
.flex_row {
 | 
			
		||||
    display: -webkit-flex;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    -webkit-flex-direction: row;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex_column {
 | 
			
		||||
    display: -webkit-flex;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    -webkit-flex-direction: column;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex_row > .flex_item,
 | 
			
		||||
.flex_column > .flex_item {
 | 
			
		||||
    -webkit-flex: auto;
 | 
			
		||||
    flex: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** content: list & items **/
 | 
			
		||||
.list {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    padding: 0.4em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list_item {
 | 
			
		||||
    width: inherit;
 | 
			
		||||
    margin: 0.4em 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list_item > *:not(:last-child) {
 | 
			
		||||
    margin-right: 0.4em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list_item img.cover.big {
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list_item img.cover.small {
 | 
			
		||||
    margin-right: 0.4em;
 | 
			
		||||
    border-radius: 0.4em;
 | 
			
		||||
    float: left;
 | 
			
		||||
    min-height: 64px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** content: date list **/
 | 
			
		||||
.date_list nav {
 | 
			
		||||
    text-align:center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    .date_list nav a {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        width: 4em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .date_list nav a[selected] {
 | 
			
		||||
        color: #007EDF;
 | 
			
		||||
        border-bottom: 0.2em #007EDF dotted;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
.date_list ul:not([selected]) {
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.date_list ul:target {
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    .date_list h2 {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
.date_list_item .cover.small {
 | 
			
		||||
    width: 64px;
 | 
			
		||||
    margin: 0.4em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.date_list_item h3 {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** content: publication **/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										74
									
								
								cms/static/cms/css/theme.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								cms/static/cms/css/theme.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Define a default theme, that is the one for RadioCampus
 | 
			
		||||
 *
 | 
			
		||||
 * Colors:
 | 
			
		||||
 * - light:
 | 
			
		||||
 *   - background: #F2F2F2
 | 
			
		||||
 *   - color: #000
 | 
			
		||||
 *
 | 
			
		||||
 * - dark:
 | 
			
		||||
 *   - background: #212121
 | 
			
		||||
 *   - color: #007EDF
 | 
			
		||||
 *
 | 
			
		||||
 * - info:
 | 
			
		||||
 *   - generic (time,url,...): #616161
 | 
			
		||||
 *   - additional: #007EDF
 | 
			
		||||
 *   - active: #007EDF
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** main **/
 | 
			
		||||
body {
 | 
			
		||||
    background-color: #F2F2F2;
 | 
			
		||||
    font-family: "Myriad Pro",Calibri,Helvetica,Arial,sans-serif;
 | 
			
		||||
    margin: 0em;
 | 
			
		||||
    padding: 0em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
h1, h2, h3 {
 | 
			
		||||
    font-family: "Myriad Pro",Calibri,Helvetica,Arial,sans-serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1:first-letter, h2:first-letter, h3:first-letter {
 | 
			
		||||
    text-transform: capitalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1 { font-size: 1.4em; }
 | 
			
		||||
h2 { font-size: 1.2em; }
 | 
			
		||||
h3 { font-size: 1.0em; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** info **/
 | 
			
		||||
time {
 | 
			
		||||
    font-size: 0.9em;
 | 
			
		||||
    color: #616161;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info {
 | 
			
		||||
    font-size: 0.9em;
 | 
			
		||||
    color: #007EDF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    color: #616161;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover {
 | 
			
		||||
    color: #007EDF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.error { color: red; }
 | 
			
		||||
.warning { color: orange; }
 | 
			
		||||
.success { color: green; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** page **/
 | 
			
		||||
.page > nav {
 | 
			
		||||
    width: 20em;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,14 @@
 | 
			
		||||
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="application-name" content="aircox-cms">
 | 
			
		||||
        <meta name="description" content="{{ settings.cms.WebsiteSettings.description }}">
 | 
			
		||||
        <meta name="keywords" content="{{ page.tags.all|default:settings.cms.WebsiteSettings.tags }}">
 | 
			
		||||
 | 
			
		||||
        {% with favicon=settings.cms.WebsiteSettings.favicon %}
 | 
			
		||||
            <link rel="icon" href="{{ favicon.url }}" />
 | 
			
		||||
        {% endwith %}
 | 
			
		||||
        {% block css %}
 | 
			
		||||
            <link rel="stylesheet" href="{% static 'cms/css/layout.css' %}" type="text/css" />
 | 
			
		||||
            <link rel="stylesheet" href="{% static 'cms/css/theme.css' %}" type="text/css" />
 | 
			
		||||
@ -21,19 +29,19 @@
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <div class="top">
 | 
			
		||||
            <nav>
 | 
			
		||||
                <a href="">Grille Horaire</a>
 | 
			
		||||
                <a href="">Programmes</a>
 | 
			
		||||
                <a href="">Contact</a>
 | 
			
		||||
            </nav>
 | 
			
		||||
            {% render_sections position="top" %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="middle">
 | 
			
		||||
            <nav class="left">
 | 
			
		||||
                {% render_sections position="menu_left" %}
 | 
			
		||||
        <header class="header">
 | 
			
		||||
            {% render_sections position="header" %}
 | 
			
		||||
        </header>
 | 
			
		||||
 | 
			
		||||
        <div class="page flex_row">
 | 
			
		||||
            <nav class="page_left flex_item">
 | 
			
		||||
                {% render_sections position="page_left" %}
 | 
			
		||||
            </nav>
 | 
			
		||||
 | 
			
		||||
            <main>
 | 
			
		||||
            <main class="flex_item">
 | 
			
		||||
            {% if messages %}
 | 
			
		||||
            <ul class="messages">
 | 
			
		||||
                {% for message in messages %}
 | 
			
		||||
@ -50,6 +58,14 @@
 | 
			
		||||
            {% block content %}
 | 
			
		||||
            {% endblock %}
 | 
			
		||||
            </main>
 | 
			
		||||
 | 
			
		||||
            <nav class="page_right flex_item">
 | 
			
		||||
                {% render_sections position="page_right" %}
 | 
			
		||||
            </nav>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <footer class="footer">
 | 
			
		||||
            {% render_sections position="footer" %}
 | 
			
		||||
        </footer>
 | 
			
		||||
    </body>
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,11 @@
 | 
			
		||||
{% extends "cms/base_site.html" %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% load wagtailcore_tags %}
 | 
			
		||||
{% load wagtailimages_tags %}
 | 
			
		||||
 | 
			
		||||
{% load aircox_cms %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% if object_list %}
 | 
			
		||||
{# list view #}
 | 
			
		||||
@ -18,75 +21,21 @@
 | 
			
		||||
{# detail view #}
 | 
			
		||||
    <div class="content">
 | 
			
		||||
        {% if page.cover %}
 | 
			
		||||
        <img class="cover" src="{{ page.cover.file.url }}">
 | 
			
		||||
        {% image page.cover max-600x480 class="cover" height="" width="" %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        <div class="body">
 | 
			
		||||
        <section class="body">
 | 
			
		||||
        {{ page.body|richtext}}
 | 
			
		||||
        {% block content_extras %}{% endblock %}
 | 
			
		||||
        </section>
 | 
			
		||||
 | 
			
		||||
        <div class="post_content">
 | 
			
		||||
        {% render_sections position="post_content" %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        {% block content_extras %}
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
 | 
			
		||||
        {% if page.related_links.all %}
 | 
			
		||||
        <ul class="related">
 | 
			
		||||
            <h3>{% trans "Related links" %}</h3>
 | 
			
		||||
            {% for link in page.related_links.all %}
 | 
			
		||||
            <li>
 | 
			
		||||
                <a href="{{ link.url }}">
 | 
			
		||||
                {% if link.icon %}{% image link.icon fill-size-32x32 %}{% endif %}
 | 
			
		||||
                {{ link.title|default:link.url }}
 | 
			
		||||
                </a>
 | 
			
		||||
            </li>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </ul>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        <div class="comments">
 | 
			
		||||
        <section class="comments">
 | 
			
		||||
        {% include "cms/snippets/comments.html" %}
 | 
			
		||||
        </div>
 | 
			
		||||
        </section>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    {% block page_nav %}
 | 
			
		||||
    <nav class="page_nav">
 | 
			
		||||
        {% block metadata %}
 | 
			
		||||
        <div class="meta">
 | 
			
		||||
            <div class="author">
 | 
			
		||||
                {% if page.publish_as %}
 | 
			
		||||
                    {% with page.publish_as as item %}
 | 
			
		||||
                    {% include "cms/snippets/list_item.html" %}
 | 
			
		||||
                    {% endwith %}
 | 
			
		||||
                {% else %}
 | 
			
		||||
                    {{ page.owner|default:'' }}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </div>
 | 
			
		||||
            <time datetime="{{ page.specific.date }}">
 | 
			
		||||
                {% trans "Published on " %}
 | 
			
		||||
                {{ page.specific.date|date:'l d F, H:i' }}
 | 
			
		||||
            </time>
 | 
			
		||||
 | 
			
		||||
            <div class="tags">
 | 
			
		||||
            {% for tag in page.tags.all %}
 | 
			
		||||
             {# <a href="{% pageurl page.blog_index %}?tag={{ tag }}">{{ tag }}</a> #}
 | 
			
		||||
             {{ tag }}
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
 | 
			
		||||
        {% block page_nav_extras %}
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
 | 
			
		||||
        {% if page.recents %}
 | 
			
		||||
        <div>
 | 
			
		||||
            <h2>{% trans "Last Publications" %}</h2>
 | 
			
		||||
            {% with object_list=page.recents %}
 | 
			
		||||
            {% include "cms/snippets/list.html" %}
 | 
			
		||||
            {% endwith %}
 | 
			
		||||
            {# TODO: url to complete list of publications #}
 | 
			
		||||
        </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </nav>
 | 
			
		||||
    {% endblock %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
<div class="section_item {{ self.css_class }}">
 | 
			
		||||
<section class="section_item {{ self.css_class }}">
 | 
			
		||||
    {% block title %}
 | 
			
		||||
    {% if self.show_title %}<h2>{{ self.title }}</h2>{% endif %}
 | 
			
		||||
    {% endblock %}
 | 
			
		||||
    {% block content %}{{ content|safe }}{% endblock %}
 | 
			
		||||
</div>
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% with link=self.as_dict %}
 | 
			
		||||
<a href="{{ link.url }}">
 | 
			
		||||
    {% if link.icon %}{% image link.icon fill-32x32 class="icon" %}{% endif %}
 | 
			
		||||
    {% if link.icon %}{% image link.icon fill-32x32 class="icon link_icon" height='' width='' %}{% endif %}
 | 
			
		||||
    {{ link.text }}
 | 
			
		||||
</a>
 | 
			
		||||
{% endwith %}
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
    {% with link=item.as_dict %}
 | 
			
		||||
    <a href="{{ link.url }}"
 | 
			
		||||
        {% if item.css_class %}class="{{ item.css_class }}"{% endif %}>
 | 
			
		||||
        {% if link.icon %}{% image link.icon fill-32x32 class="icon" %}{% endif %}
 | 
			
		||||
        {% if link.icon %}{% image link.icon fill-24x24 class="icon" %}{% endif %}
 | 
			
		||||
        {{ link.text }}
 | 
			
		||||
    </a>
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								cms/templates/cms/sections/section_logs_list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								cms/templates/cms/sections/section_logs_list.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
{% extends "cms/sections/section_item.html" %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% with item_date_format="H:i" list_css_class="date_list" %}
 | 
			
		||||
{% include "cms/snippets/list.html" %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								cms/templates/cms/sections/section_publication_info.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								cms/templates/cms/sections/section_publication_info.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
{% extends "cms/sections/section_item.html" %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
<div class="meta">
 | 
			
		||||
    <div class="author">
 | 
			
		||||
        {% if page.publish_as %}
 | 
			
		||||
            {% trans "Published by" %}
 | 
			
		||||
            {% with item=page.publish_as item_date_format='' %}
 | 
			
		||||
            {% include "cms/snippets/list_item.html" %}
 | 
			
		||||
            {% endwith %}
 | 
			
		||||
        {% elif page.owner %}
 | 
			
		||||
            {% trans "Published by" %}
 | 
			
		||||
            {{ page.owner }}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
    <time datetime="{{ page.specific.date }}">
 | 
			
		||||
        {% trans "Published on " %}
 | 
			
		||||
        {{ page.specific.date|date:'l d F, H:i' }}
 | 
			
		||||
    </time>
 | 
			
		||||
    <div class="tags">
 | 
			
		||||
    {% for tag in page.tags.all %}
 | 
			
		||||
     {# <a href="{% pageurl page.blog_index %}?tag={{ tag }}">{{ tag }}</a> #}
 | 
			
		||||
     {{ tag }}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								cms/templates/cms/sections/section_search_field.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								cms/templates/cms/sections/section_search_field.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
{% extends "cms/sections/section_item.html" %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<form action="{{ list_page.url }}" method="GET">
 | 
			
		||||
    <input type="text" name="search" placeholder="{{ self.text }}">
 | 
			
		||||
    <input type="submit" style="display: none;">
 | 
			
		||||
</form>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								cms/templates/cms/sections/section_timetable.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								cms/templates/cms/sections/section_timetable.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
{% extends "cms/sections/section_item.html" %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% include "cms/snippets/date_list.html" %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
@ -1,34 +1,58 @@
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    /// Function used to select a panel on a tab selection.
 | 
			
		||||
    /// The tab should be at max level -2 of the main container
 | 
			
		||||
    /// The panel must have a class "panel"
 | 
			
		||||
    function select_tab(target) {
 | 
			
		||||
        parent = target.parentNode.parentNode;
 | 
			
		||||
 | 
			
		||||
        var date = target.dataset.date;
 | 
			
		||||
        panel = parent.querySelector('.panel[data-date="' + date + '"]');
 | 
			
		||||
 | 
			
		||||
        // unselect
 | 
			
		||||
        qs = parent.querySelectorAll('*[selected]');
 | 
			
		||||
        for(var i = 0; i < qs.length; i++)
 | 
			
		||||
            if(qs[i].dataset.date != date)
 | 
			
		||||
                qs[i].removeAttribute('selected');
 | 
			
		||||
 | 
			
		||||
        console.log(panel, target, date);
 | 
			
		||||
        panel.setAttribute('selected', 'true');
 | 
			
		||||
        target.setAttribute('selected', 'true');
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{# FIXME: get current complete URL #}
 | 
			
		||||
<div class="list dated_list">
 | 
			
		||||
<div class="list date_list">
 | 
			
		||||
{% if nav_dates %}
 | 
			
		||||
<nav class="nav_dates">
 | 
			
		||||
    {% if nav_dates.prev %}
 | 
			
		||||
    <a href="?date={{ nav_dates.prev|date:"Y-m-d" }}" title="{% trans "previous days" %}"><</a>
 | 
			
		||||
    <a href="?date={{ nav_dates.prev|date:"Y-m-d" }}" title="{% trans "previous days" %}">◀</a>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% for day in nav_dates.dates %}
 | 
			
		||||
    <a href="#day_{{day|date:"Y-m-d"}}"
 | 
			
		||||
        {% if day == nav_dates.date %}class="today"{% endif %}>
 | 
			
		||||
    <a onclick="select_tab(this);" data-date="day_{{day|date:"Y-m-d"}}"
 | 
			
		||||
        {% if day == nav_dates.date %}selected{% endif %}
 | 
			
		||||
        class="tab {% if day == nav_dates.date %}today{% endif %}">
 | 
			
		||||
        {{ day|date:'D. d' }}
 | 
			
		||||
    </a>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
 | 
			
		||||
    {% if nav_dates.next %}
 | 
			
		||||
    <a href="?date={{ nav_dates.next|date:"Y-m-d" }}" title="{% trans "next days" %}">></a>
 | 
			
		||||
    <a href="?date={{ nav_dates.next|date:"Y-m-d" }}" title="{% trans "next days" %}">▶</a>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
</nav>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{% for day, list in object_list %}
 | 
			
		||||
<ul id="day_{{day|date:"Y-m-d"}}"
 | 
			
		||||
    {% if day == nav_dates.date %}class="today"{% endif %}>
 | 
			
		||||
<ul class="panel {% if day == nav_dates.date %}class="today"{% endif %}"
 | 
			
		||||
    {% if day == nav_dates.date %}selected{% endif %}
 | 
			
		||||
    data-date="day_{{day|date:"Y-m-d"}}">
 | 
			
		||||
    {# you might like to hide it by default -- this more for sections #}
 | 
			
		||||
    <h2>{{ day|date:'l d F' }}</h2>
 | 
			
		||||
    {% with object_list=list item_date_format="H:i" %}
 | 
			
		||||
    {% for item in list %}
 | 
			
		||||
    {% include "cms/snippets/list_item.html" %}
 | 
			
		||||
    {% include "cms/snippets/date_list_item.html" %}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										43
									
								
								cms/templates/cms/snippets/date_list_item.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								cms/templates/cms/snippets/date_list_item.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
{% comment %}
 | 
			
		||||
Configurable item to be put in a dated list. Work like list_item, the layout
 | 
			
		||||
is just a bit different.
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
 | 
			
		||||
{% 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 %}">
 | 
			
		||||
 | 
			
		||||
    {% 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 }}">
 | 
			
		||||
        {{ item.date|date:date_format }}
 | 
			
		||||
    </time>
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% if item_big_cover %}
 | 
			
		||||
        {% image item.cover max-640x480 class="cover big" height="" width="" %}
 | 
			
		||||
    {% elif item.cover %}
 | 
			
		||||
        {% image item.cover fill-64x64 class="cover small" %}
 | 
			
		||||
    {% else %}
 | 
			
		||||
        <div class="cover small"></div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    <div class="flex_item">
 | 
			
		||||
        <h3>{{ item.title }}</h3>
 | 
			
		||||
 | 
			
		||||
        {% if item.summary %}<div class="summary">{{ item.summary }}</div>{% endif %}
 | 
			
		||||
 | 
			
		||||
        {% if item.info %}
 | 
			
		||||
        <span class="info">{{ item.info|safe }}</span>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        {% if item.extra %}
 | 
			
		||||
        <div class="extra"></div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</a>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,19 @@
 | 
			
		||||
{% comment %}
 | 
			
		||||
Options:
 | 
			
		||||
- list_css_class: extra class for the main list container
 | 
			
		||||
- list_paginator: paginator object to display pagination at the bottom;
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
{% load aircox_cms %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<div class="list">
 | 
			
		||||
<ul>
 | 
			
		||||
<ul class="list {{ list_css_class|default:'' }}">
 | 
			
		||||
{% for page in object_list %}
 | 
			
		||||
{% with item=page.specific %}
 | 
			
		||||
{% include "cms/snippets/list_item.html" %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
{% endfor %}
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
{# we use list_paginator to avoid conflicts when there are multiple lists #}
 | 
			
		||||
{% if list_paginator and list_paginator.num_pages > 1 %}
 | 
			
		||||
@ -54,6 +58,6 @@
 | 
			
		||||
</nav>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,30 +4,41 @@ ListItem instance.
 | 
			
		||||
 | 
			
		||||
Options:
 | 
			
		||||
* item: item to render. Fields: title, summary, cover, url, date, info, css_class
 | 
			
		||||
* item_date_format: format passed to the date filter instead of default one
 | 
			
		||||
* item_date_format: format passed to the date filter instead of default one. If
 | 
			
		||||
    it is an empty string, do not print the date.
 | 
			
		||||
* item_big_cover: cover should is big instead of thumbnail (width: 600)
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
 | 
			
		||||
{% load wagtailimages_tags %}
 | 
			
		||||
 | 
			
		||||
<a {% if item.url %}href="{{ item.url }}" {% endif %}
 | 
			
		||||
    class="item page_item{% if item.css_class %}{{ item.css_class }}{% endif %}">
 | 
			
		||||
    {% if item_big_cover %}
 | 
			
		||||
        {% image item.cover max-600 class="cover item_cover" %}
 | 
			
		||||
    {% else %}
 | 
			
		||||
        {% image item.cover fill-64x64 class="cover item_cover" %}
 | 
			
		||||
    class="list_item {% if not item_big_cover %}flex_row {% endif %}{% if item.css_class %}{{ item.css_class }}{% endif %}">
 | 
			
		||||
    {% if item.cover %}
 | 
			
		||||
        {% if item_big_cover %}
 | 
			
		||||
            {% image item.cover max-640x480 class="cover big" height="" width="" %}
 | 
			
		||||
        {% else %}
 | 
			
		||||
            {% image item.cover fill-64x64 class="cover small" %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    <h3>{{ item.title }}</h3>
 | 
			
		||||
    {% if item.summary %}<div class="summary">{{ item.summary }}</div>{% endif %}
 | 
			
		||||
    {% if not item.show_in_menus and item.date %}
 | 
			
		||||
    {% with date_format=list_date_format|default:'l d F, H:i' %}
 | 
			
		||||
    <time datetime="{{ item.date }}">
 | 
			
		||||
        {{ item.date|date:date_format }}
 | 
			
		||||
    </time>
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {% if item.info %}
 | 
			
		||||
    <span class="info">{{ item.info|safe }}</span>
 | 
			
		||||
    <div class="flex_item">
 | 
			
		||||
        <h3>{{ item.title }}</h3>
 | 
			
		||||
 | 
			
		||||
        {% if item.info %}
 | 
			
		||||
        <span class="info">{{ item.info|safe }}</span>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        {% if item.summary %}<div class="summary">{{ item.summary }}</div>{% endif %}
 | 
			
		||||
        {% 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 }}">
 | 
			
		||||
            {{ item.date|date:date_format }}
 | 
			
		||||
        </time>
 | 
			
		||||
        {% endwith %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
    {% if item.extra %}
 | 
			
		||||
    <div class="extra"></div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
</a>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,31 @@ class GenericMenu(Menu):
 | 
			
		||||
        return self._registered_menu_items
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DiffusionsMenu(GenericMenu):
 | 
			
		||||
    """
 | 
			
		||||
    Menu to display diffusions of today
 | 
			
		||||
    """
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return programs.Diffusion.objects.filter(
 | 
			
		||||
            type = programs.Diffusion.Type.normal,
 | 
			
		||||
            start__contains = tz.now().date(),
 | 
			
		||||
        ).order_by('start')
 | 
			
		||||
 | 
			
		||||
    def get_title(self, item):
 | 
			
		||||
        return item.program.name
 | 
			
		||||
 | 
			
		||||
    def get_parent(self, item):
 | 
			
		||||
        return item.program.page.first()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@hooks.register('register_admin_menu_item')
 | 
			
		||||
def register_programs_menu_item():
 | 
			
		||||
    return SubmenuMenuItem(
 | 
			
		||||
        _('Today\'s Diffusions'), DiffusionsMenu(),
 | 
			
		||||
        classnames='icon icon-folder-open-inverse', order=10
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramsMenu(GenericMenu):
 | 
			
		||||
    """
 | 
			
		||||
    Menu to display all active programs.
 | 
			
		||||
@ -67,36 +92,12 @@ class ProgramsMenu(GenericMenu):
 | 
			
		||||
        return settings.default_program_parent_page
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DiffusionsMenu(GenericMenu):
 | 
			
		||||
    """
 | 
			
		||||
    Menu to display diffusions of today
 | 
			
		||||
    """
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return programs.Diffusion.objects.filter(
 | 
			
		||||
            type = programs.Diffusion.Type.normal,
 | 
			
		||||
            start__contains = tz.now().date(),
 | 
			
		||||
        ).order_by('start')
 | 
			
		||||
 | 
			
		||||
    def get_title(self, item):
 | 
			
		||||
        return item.program.name
 | 
			
		||||
 | 
			
		||||
    def get_parent(self, item):
 | 
			
		||||
        return item.program.page.first()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@hooks.register('register_admin_menu_item')
 | 
			
		||||
def register_programs_menu_item():
 | 
			
		||||
    return SubmenuMenuItem(
 | 
			
		||||
        _('Programs'), ProgramsMenu(),
 | 
			
		||||
        classnames='icon icon-folder-open-inverse', order=100
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@hooks.register('register_admin_menu_item')
 | 
			
		||||
def register_programs_menu_item():
 | 
			
		||||
    return SubmenuMenuItem(
 | 
			
		||||
        _('Today\'s Diffusions'), DiffusionsMenu(),
 | 
			
		||||
        classnames='icon icon-folder-open-inverse', order=100
 | 
			
		||||
        classnames='icon icon-folder-open-inverse', order=10
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ from django.db import models
 | 
			
		||||
from django.contrib.contenttypes.fields import GenericForeignKey
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from django.utils.translation import ugettext as _, ugettext_lazy
 | 
			
		||||
from django.utils import timezone as tz
 | 
			
		||||
 | 
			
		||||
import aircox.programs.models as programs
 | 
			
		||||
from aircox.programs.utils import to_timedelta
 | 
			
		||||
@ -176,14 +177,15 @@ class Station(programs.Nameable):
 | 
			
		||||
        for diff in diffs:
 | 
			
		||||
            logs_ = \
 | 
			
		||||
                logs.filter(date__gt = diff.end, date__lt = diff_.start) \
 | 
			
		||||
                    if diff_ else logs.filter(date__gt = diff.end)
 | 
			
		||||
                    if diff_ else \
 | 
			
		||||
                logs.filter(date__gt = diff.end)
 | 
			
		||||
            diff_ = diff
 | 
			
		||||
            items.extends(logs_)
 | 
			
		||||
            items.extend(logs_)
 | 
			
		||||
            items.append(diff)
 | 
			
		||||
            if count and len(items) >= count:
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        if diff_ and not count or len(items) <= count:
 | 
			
		||||
        if diff_ and (not count or len(items) <= count):
 | 
			
		||||
            logs_ = logs.filter(date__lt = diff_.end)
 | 
			
		||||
            items.extend(logs_)
 | 
			
		||||
 | 
			
		||||
@ -207,19 +209,22 @@ class Station(programs.Nameable):
 | 
			
		||||
        # FIXME: as an iterator?
 | 
			
		||||
        # TODO argument to get sound instead of tracks
 | 
			
		||||
        # TODO #Station
 | 
			
		||||
        date = date or tz.now().date()
 | 
			
		||||
        if date > datetime.date.today():
 | 
			
		||||
        if date and date > datetime.date.today():
 | 
			
		||||
            return []
 | 
			
		||||
 | 
			
		||||
        logs = Log.objects.get_for(model = programs.Track) \
 | 
			
		||||
                  .filter(station = self) \
 | 
			
		||||
                  .order_by('-date')
 | 
			
		||||
        diffs = programs.Diffusion.objects \
 | 
			
		||||
                    .filter(type = Diffusion.Type.normal) \
 | 
			
		||||
                    .order_by('-date')
 | 
			
		||||
 | 
			
		||||
        if date:
 | 
			
		||||
            logs = logs.filter(date__contains = date)
 | 
			
		||||
            diffs = diffs.get_at(date)
 | 
			
		||||
            diffs = programs.Diffusion.objects.get_at(date)
 | 
			
		||||
        else:
 | 
			
		||||
            diffs = programs.Diffusion.objects
 | 
			
		||||
 | 
			
		||||
        diffs = diffs.filter(type = programs.Diffusion.Type.normal) \
 | 
			
		||||
                     .filter(start__lte = tz.now()) \
 | 
			
		||||
                     .order_by('-start')
 | 
			
		||||
        return self.__mix_logs_and_diff(diffs, logs, count)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								notes.md
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								notes.md
									
									
									
									
									
								
							@ -33,25 +33,29 @@ This file is used as a reminder, can be used as crappy documentation too.
 | 
			
		||||
        - config generation and sound diffusion
 | 
			
		||||
 | 
			
		||||
- cms:
 | 
			
		||||
    - command to sync programs with cms's
 | 
			
		||||
    - player:
 | 
			
		||||
        - mixcloud
 | 
			
		||||
        - remove from playing playlist -> stop
 | 
			
		||||
    - filter choices on DiffusionPage and ProgramPage related objects
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Long term TODO
 | 
			
		||||
- automatic cancel of passed diffusion based on logs?
 | 
			
		||||
    - archives can be set afterwards for rerun, so check must be done
 | 
			
		||||
        at the same time we monitor
 | 
			
		||||
- sounds monitor: max_size of path, take in account
 | 
			
		||||
- logs: archive functionnality
 | 
			
		||||
- track stats for diffusions
 | 
			
		||||
- debug/prod configuration
 | 
			
		||||
- player support diffusions with multiple archive files
 | 
			
		||||
- view as grid
 | 
			
		||||
- actions -> noscript case, think of accessibility
 | 
			
		||||
- comments -> remove/edit by the author
 | 
			
		||||
- integrate logs for tracks + in on air
 | 
			
		||||
- rename controllers.Station into controllers.Streamer -> keep Station for sth else
 | 
			
		||||
 | 
			
		||||
programs:
 | 
			
		||||
    - sounds monitor: max_size of path, take in account
 | 
			
		||||
 | 
			
		||||
controllers:
 | 
			
		||||
    - automatic cancel of passed diffusion based on logs?
 | 
			
		||||
        - archives can be set afterwards for rerun, so check must be done
 | 
			
		||||
            at the same time we monitor
 | 
			
		||||
    - logs: archive functionnality
 | 
			
		||||
    - tools:
 | 
			
		||||
        - track stats for diffusions
 | 
			
		||||
    - rename controllers.Station into controllers.Streamer -> keep Station for sth else
 | 
			
		||||
 | 
			
		||||
cms:
 | 
			
		||||
    - player support diffusions with multiple archive files
 | 
			
		||||
    - comments -> remove/edit by the author
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user