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:
parent
960fcab65d
commit
bce84af7f3
|
@ -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.
Loading…
Reference in New Issue
Block a user