From f6e0d8d9568b69147094adba42c89f4a28770827 Mon Sep 17 00:00:00 2001 From: bkfox Date: Mon, 19 Jun 2017 00:21:22 +0200 Subject: [PATCH] allow only one program or diffusion for pages; in cms.signals, manage cases when Diffusion.initial is set/changed & clean up; fix bug in loglist nav when max_age is 0 (no limit); work on design for date lists; fix bug in player on item removal; --- aircox/models.py | 2 +- aircox_cms/models.py | 37 +++++++++----- aircox_cms/signals.py | 49 +++++++++++++++---- aircox_cms/static/aircox_cms/css/layout.css | 48 +++++++++++++----- aircox_cms/static/aircox_cms/js/player.js | 6 ++- .../aircox_cms/snippets/date_list_item.html | 10 +++- .../aircox_cms/snippets/list_item.html | 3 +- aircox_cms/wagtail_hooks.py | 11 +++-- notes.md | 1 + 9 files changed, 123 insertions(+), 44 deletions(-) diff --git a/aircox/models.py b/aircox/models.py index 529a622..3a7bdca 100755 --- a/aircox/models.py +++ b/aircox/models.py @@ -922,7 +922,7 @@ class Diffusion(models.Model): return super().save(*args, **kwargs) if self.initial: - # force link to the top initial diffusion + # force link to the first diffusion if self.initial.initial: self.initial = self.initial.initial self.program = self.initial.program diff --git a/aircox_cms/models.py b/aircox_cms/models.py index b32770f..1cac790 100755 --- a/aircox_cms/models.py +++ b/aircox_cms/models.py @@ -420,7 +420,7 @@ class Publication(BasePage): class ProgramPage(Publication): - program = models.ForeignKey( + program = models.OneToOneField( aircox.models.Program, verbose_name = _('program'), related_name = 'page', @@ -515,11 +515,11 @@ class Track(aircox.models.Track,Orderable): class DiffusionPage(Publication): order_field = 'diffusion__start' - diffusion = models.ForeignKey( + diffusion = models.OneToOneField( aircox.models.Diffusion, verbose_name = _('diffusion'), related_name = 'page', - null=True, + null=True, blank = True, # not blank because we enforce the connection to a diffusion # (still users always tend to break sth) on_delete=models.SET_NULL, @@ -548,6 +548,9 @@ class DiffusionPage(Publication): ], heading=_('Content')), InlinePanel('links', label=_('Links')) ] + Page.promote_panels + settings_panels = Publication.settings_panels + [ + FieldPanel('diffusion') + ] @classmethod def from_diffusion(cl, diff, model = None, **kwargs): @@ -572,8 +575,8 @@ class DiffusionPage(Publication): """ initial = diff.initial or diff - if initial.page.all().count(): - item = initial.page.all().first() + if hasattr(initial, 'page'): + item = initial.page else: item = cl.from_diffusion(diff, ListItem) item.live = True @@ -590,6 +593,13 @@ class DiffusionPage(Publication): item.date = diff.start item.css_class = 'diffusion' + + now = tz.now() + if diff.start <= now <= diff.end: + print('now!', diff) + item.css_class = ' now' + item.now = True + return item def get_archive(self): @@ -721,7 +731,7 @@ class LogsPage(DatedListPage): on_delete = models.SET_NULL, help_text = _('(required) related station') ) - age_max = models.IntegerField( + max_age = models.IntegerField( _('maximum age'), default=15, help_text = _('maximum days in the past allowed to be shown. ' @@ -740,7 +750,7 @@ class LogsPage(DatedListPage): content_panels = DatedListPage.content_panels + [ MultiFieldPanel([ FieldPanel('station'), - FieldPanel('age_max'), + FieldPanel('max_age'), FieldPanel('reverse'), ], heading=_('Configuration')), ] @@ -749,20 +759,21 @@ class LogsPage(DatedListPage): """ Return a list of dates availables for the navigation """ - # there might be a bug if age_max < nav_days + # there might be a bug if max_age < nav_days today = tz.now().date() first = min(date, today) - first = max( first - tz.timedelta(days = self.nav_days-1), - today - tz.timedelta(days = self.age_max)) + first = first - tz.timedelta(days = self.nav_days-1) + if self.max_age: + first = max(first, today - tz.timedelta(days = self.max_age)) return [ first + tz.timedelta(days=i) for i in range(0, self.nav_days) ] def get_queryset(self, request, context): today = tz.now().date() - if context['nav_dates']['next'] > today: + if self.max_age and context['nav_dates']['next'] > today: context['nav_dates']['next'] = None - if context['nav_dates']['prev'] < \ - today - tz.timedelta(days = self.age_max): + if self.max_age and context['nav_dates']['prev'] < \ + today - tz.timedelta(days = self.max_age): context['nav_dates']['prev'] = None logs = [] diff --git a/aircox_cms/signals.py b/aircox_cms/signals.py index c4ccf16..b43e4d6 100755 --- a/aircox_cms/signals.py +++ b/aircox_cms/signals.py @@ -1,3 +1,4 @@ +from django.db.models import Q from django.db.models.signals import post_save, pre_delete from django.dispatch import receiver from django.utils.translation import ugettext as _, ugettext_lazy @@ -142,17 +143,49 @@ def program_post_saved(sender, instance, created, *args, **kwargs): parent.add_child(instance = page) +def void_pages_of(page_set): + """ + Return a queryset from page_set that select only empty pages. If + `inverse` is True, select only pages that are not empty. + + Empty is defined on theses parameters: + - `numchild = 0` => no children + - no headline + - no body + """ + if not page_set.count(): + return + + page_set = page_set.filter(numchild = 0) + + # as publications + page_set = models.Publication.objects.filter( + page_ptr_id__in = page_set.values('pk') + ) + + # only empty + q = (Q(headline__isnull = True) | Q(headline = '')) & \ + (Q(body__isnull = True) | Q(body = '')) + return page_set.filter(q) + + @receiver(pre_delete, sender=aircox.Program) def program_post_deleted(sender, instance, *args, **kwargs): - for page in instance.page.all(): - if page.specific.body or Page.objects.descendant_of(page).count(): - continue - page.delete() + void_pages_of(instance.page).delete() @receiver(post_save, sender=aircox.Diffusion) def diffusion_post_saved(sender, instance, created, *args, **kwargs): - if not created or instance.page.count(): + initial = instance.initial + if initial: + if not created and hasattr(instance, 'page'): + # fuck it + page = instance.page + page.diffusion = None + page.save() + return + + if instance.page: return page = models.DiffusionPage.from_diffusion( @@ -164,9 +197,5 @@ def diffusion_post_saved(sender, instance, created, *args, **kwargs): @receiver(pre_delete, sender=aircox.Diffusion) def diffusion_pre_deleted(sender, instance, *args, **kwargs): - for page in instance.page.all(): - if page.specific.body or Page.objects.descendant_of(page).count(): - continue - page.delete() - + void_pages_of(instance.page).delete() diff --git a/aircox_cms/static/aircox_cms/css/layout.css b/aircox_cms/static/aircox_cms/css/layout.css index 66fc07c..d2db76d 100755 --- a/aircox_cms/static/aircox_cms/css/layout.css +++ b/aircox_cms/static/aircox_cms/css/layout.css @@ -187,25 +187,13 @@ ul.list, .list > ul { /** content: list items in full page **/ -.content > .list .list_item { +.content > .list:not(.date_list) .list_item { min-width: 20em; display: inline-block; min-height: 2.5em; margin: 0.4em; } -.content > .list .date_list_item time { - color: #007EDF; - display: block; - margin-left: -0.5em; -} - -.content > .list .date_list_item { - width: 100%; -} - - - /** content: date list **/ .date_list nav { text-align:center; @@ -246,6 +234,40 @@ ul.list, .list > ul { margin-top: 0em; } +.date_list_item time { + color: #007EDF; +} + + +.date_list_item.now { + font-size: 1.2em; +} + + .date_list_item img.now { + width: 1.3em; + vertical-align: middle; + } + + +/** content: date list in full page **/ +.content > .date_list .date_list_item time { + color: #007EDF; + font-size: 1.1em; + display: block; +} + + +.content > .date_list .date_list_item:nth-child(2n+1) { + box-shadow: inset 0em 0em 3em rgba(0, 124, 226, 0.1); + background-color: rgba(0, 124, 226, 0.05); +} + +.content > .date_list { + padding: 0 10%; + margin: auto; + width: 80%; +} + /** content: comments **/ .comments form input:not([type=checkbox]), diff --git a/aircox_cms/static/aircox_cms/js/player.js b/aircox_cms/static/aircox_cms/js/player.js index 43c525d..aacba19 100755 --- a/aircox_cms/static/aircox_cms/js/player.js +++ b/aircox_cms/static/aircox_cms/js/player.js @@ -148,8 +148,10 @@ Playlist.prototype = { this.playlist.removeChild(sound.item); this.save(); - this.player.stop() - this.next(false); + if(this.sound == sound) { + this.player.stop() + this.next(false); + } }, select: function(sound, play = true) { diff --git a/aircox_cms/templates/aircox_cms/snippets/date_list_item.html b/aircox_cms/templates/aircox_cms/snippets/date_list_item.html index b750628..7e2cd49 100755 --- a/aircox_cms/templates/aircox_cms/snippets/date_list_item.html +++ b/aircox_cms/templates/aircox_cms/snippets/date_list_item.html @@ -3,16 +3,24 @@ Configurable item to be put in a dated list. Work like list_item, the layout is just a bit different. {% endcomment %} +{% load static %} +{% load i18n %} + {% load wagtailimages_tags %} {% 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' %} {% endwith %} diff --git a/aircox_cms/templates/aircox_cms/snippets/list_item.html b/aircox_cms/templates/aircox_cms/snippets/list_item.html index 36a121d..5b04e5f 100755 --- a/aircox_cms/templates/aircox_cms/snippets/list_item.html +++ b/aircox_cms/templates/aircox_cms/snippets/list_item.html @@ -15,7 +15,7 @@ Options: {% load wagtailimages_tags %} + class="list_item {{ item.css_class|default_if_none:"" }}{% if not item_big_cover %} flex_row{% endif %}"> {% if item.cover %} {% if item_big_cover %} {% image item.cover max-640x480 class="cover big" height="" width="" %} @@ -23,6 +23,7 @@ Options: {% image item.cover fill-64x64 class="cover small" %} {% endif %} {% endif %} +

{{ item.title }}

diff --git a/aircox_cms/wagtail_hooks.py b/aircox_cms/wagtail_hooks.py index 07ef361..48f800e 100755 --- a/aircox_cms/wagtail_hooks.py +++ b/aircox_cms/wagtail_hooks.py @@ -222,11 +222,16 @@ class GenericMenu(Menu): """ pass + @staticmethod + def page_of(item): + return item.page + def page_url(self, item): - if item.page.count(): + page = self.page_of(item) + if page: name = 'wagtailadmin_explore' \ if self.explore else 'wagtailadmin_pages:edit' - return reverse(name, args=[item.page.first().id]) + return reverse(name, args=[page.id]) parent_page = self.get_parent(item) if not parent_page: @@ -311,7 +316,7 @@ class TodayMenu(GenericMenu): attrs = {} - qs = PageRevision.objects.filter(page = item.page.first()) + qs = PageRevision.objects.filter(page = item.page) if qs.count(): headline = qs.latest('created_at').content_json headline = json.loads(headline).get('headline') diff --git a/notes.md b/notes.md index 9214c43..a2d4420 100755 --- a/notes.md +++ b/notes.md @@ -21,6 +21,7 @@ This file is used as a reminder, can be used as crappy documentation too. - category page - for timetable, logs, etc. make station optional - django's message css displayed on pages when element is modified (remove bullet) + - articles preview in different format # conventions