diff --git a/aircox_cms/models.py b/aircox_cms/models.py
index 07e9d2e..b32770f 100755
--- a/aircox_cms/models.py
+++ b/aircox_cms/models.py
@@ -162,14 +162,11 @@ class WebsiteSettings(BaseSetting):
verbose_name = _('website settings')
-#
-# Publications
-#
@register_snippet
class Comment(models.Model):
publication = models.ForeignKey(
- 'Publication',
- verbose_name = _('publication')
+ Page,
+ verbose_name = _('page')
)
published = models.BooleanField(
verbose_name = _('published'),
@@ -227,16 +224,114 @@ class Comment(models.Model):
return super().save(*args, **kwargs)
+class BasePage(Page):
+ body = RichTextField(
+ _('body'),
+ null = True, blank = True,
+ help_text = _('the publication itself')
+ )
+ cover = models.ForeignKey(
+ 'wagtailimages.Image',
+ verbose_name = _('cover'),
+ null=True, blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+',
+ help_text = _('image to use as cover of the publication'),
+ )
+ allow_comments = models.BooleanField(
+ _('allow comments'),
+ default = True,
+ help_text = _('allow comments')
+ )
+
+ # panels
+ content_panels = [
+ MultiFieldPanel([
+ FieldPanel('title'),
+ ImageChooserPanel('cover'),
+ FieldPanel('body', classname='full'),
+ ], heading=_('Content'))
+ ]
+ settings_panels = Page.settings_panels + [
+ FieldPanel('allow_comments'),
+ ]
+ search_fields = [
+ index.SearchField('title', partial_match=True),
+ index.SearchField('body', partial_match=True),
+ index.FilterField('live'),
+ index.FilterField('show_in_menus'),
+ ]
+
+ # properties
+ @property
+ def url(self):
+ if not self.live:
+ parent = self.get_parent().specific
+ return parent and parent.url
+ return super().url
+
+ @property
+ def icon(self):
+ return image_url(self.cover, 'fill-64x64')
+
+ @property
+ def small_icon(self):
+ return image_url(self.cover, 'fill-32x32')
+
+ @property
+ def comments(self):
+ return Comment.objects.filter(
+ publication = self,
+ published = True,
+ ).order_by('-date')
+
+ # methods
+ def get_context(self, request, *args, **kwargs):
+ from aircox_cms.forms import CommentForm
+
+ context = super().get_context(request, *args, **kwargs)
+ if self.allow_comments and \
+ WebsiteSettings.for_site(request.site).allow_comments:
+ context['comment_form'] = CommentForm()
+ return context
+
+ def serve(self, request):
+ from aircox_cms.forms import CommentForm
+ if request.POST and 'comment' in request.POST['type']:
+ settings = WebsiteSettings.for_site(request.site)
+ comment_form = CommentForm(request.POST)
+ if comment_form.is_valid():
+ comment = comment_form.save(commit=False)
+ comment.publication = self
+ comment.published = settings.accept_comments
+ comment.save()
+ messages.success(request,
+ settings.comment_success_message
+ if comment.published else
+ settings.comment_wait_message,
+ fail_silently=True,
+ )
+ else:
+ messages.error(
+ request, settings.comment_error_message, fail_silently=True
+ )
+ return super().serve(request)
+
+ class Meta:
+ abstract = True
+
+
+#
+# Publications
+#
class PublicationRelatedLink(RelatedLinkBase,TemplateMixin):
template = 'aircox_cms/snippets/link.html'
parent = ParentalKey('Publication', related_name='links')
-
class PublicationTag(TaggedItemBase):
content_object = ParentalKey('Publication', related_name='tagged_items')
-
-class Publication(Page):
+class Publication(BasePage):
order_field = 'date'
date = models.DateTimeField(
@@ -262,19 +357,6 @@ class Publication(Page):
help_text = _('allow comments')
)
- body = RichTextField(
- _('body'),
- blank=True,
- help_text = _('the publication itself')
- )
- cover = models.ForeignKey(
- 'wagtailimages.Image',
- verbose_name = _('cover'),
- null=True, blank=True,
- on_delete=models.SET_NULL,
- related_name='+',
- help_text = _('image to use as cover of the publication'),
- )
headline = models.TextField(
_('headline'),
blank = True, null = True,
@@ -309,82 +391,32 @@ class Publication(Page):
FieldPanel('publish_as'),
FieldPanel('allow_comments'),
]
- search_fields = [
- index.SearchField('title', partial_match=True),
- index.SearchField('body', partial_match=True),
- index.FilterField('live'),
- index.FilterField('show_in_menus'),
+ search_fields = BasePage.search_fields + [
+ index.SearchField('headline', partial_match=True),
]
- @property
- def url(self):
- if not self.live:
- parent = self.get_parent().specific
- return parent and parent.url
- return super().url
-
- @property
- def icon(self):
- return image_url(self.cover, 'fill-64x64')
-
- @property
- def small_icon(self):
- return image_url(self.cover, 'fill-32x32')
@property
def recents(self):
return self.get_children().type(Publication).not_in_menu().live() \
.order_by('-publication__date')
- @property
- def comments(self):
- return Comment.objects.filter(
- publication = self,
- published = True,
- ).order_by('-date')
+ def get_context(self, request, *args, **kwargs):
+ context = super().get_context(request, *args, **kwargs)
+ view = request.GET.get('view')
+ context.update({
+ 'view': view,
+ 'page': self,
+ })
+ if view == 'list':
+ context.update(BaseList.from_request(request, related = self))
+ context['list_url_args'] += '&view=list'
+ return context
def save(self, *args, **kwargs):
if not self.date and self.first_published_at:
self.date = self.first_published_at
- super().save(*args, **kwargs)
-
- def get_context(self, request, *args, **kwargs):
- from aircox_cms.forms import CommentForm
- context = super().get_context(request, *args, **kwargs)
- view = request.GET.get('view')
- page = request.GET.get('page')
-
- if self.allow_comments and \
- WebsiteSettings.for_site(request.site).allow_comments:
- context['comment_form'] = CommentForm()
-
- if view == 'list':
- context['object_list'] = ListBase.from_request(
- request, context = context, related = self
- )
- return context
-
- def serve(self, request):
- from aircox_cms.forms import CommentForm
- if request.POST and 'comment' in request.POST['type']:
- settings = WebsiteSettings.for_site(request.site)
- comment_form = CommentForm(request.POST)
- if comment_form.is_valid():
- comment = comment_form.save(commit=False)
- comment.publication = self
- comment.published = settings.accept_comments
- comment.save()
- messages.success(request,
- settings.comment_success_message
- if comment.published else
- settings.comment_wait_message,
- fail_silently=True,
- )
- else:
- messages.error(
- request, settings.comment_error_message, fail_silently=True
- )
- return super().serve(request)
+ return super().save(*args, **kwargs)
class ProgramPage(Publication):
@@ -393,7 +425,6 @@ class ProgramPage(Publication):
verbose_name = _('program'),
related_name = 'page',
on_delete=models.SET_NULL,
- unique = True,
blank=True, null=True,
)
# rss = models.URLField()
@@ -488,7 +519,6 @@ class DiffusionPage(Publication):
aircox.models.Diffusion,
verbose_name = _('diffusion'),
related_name = 'page',
- unique = True,
null=True,
# not blank because we enforce the connection to a diffusion
# (still users always tend to break sth)
@@ -619,7 +649,18 @@ class DiffusionPage(Publication):
#
# Others types of pages
#
-class DynamicListPage(Page):
+
+class CategoryPage(BasePage, BaseList):
+ content_panels = BasePage.content_panels + BaseList.panels
+
+ def get_context(self, request, *args, **kwargs):
+ context = super().get_context(request, *args, **kwargs)
+ context.update(BaseList.get_context(self, request, paginate = True))
+ context['view'] = 'list'
+ return context
+
+
+class DynamicListPage(BasePage):
"""
Displays a list of publications using query passed by the url.
This can be used for search/tags page, and generally only one
@@ -628,47 +669,21 @@ class DynamicListPage(Page):
If a title is given, use it instead of the generated one.
"""
# FIXME/TODO: title in template
- body = RichTextField(
- _('body'),
- blank = True, null = True,
- help_text = _('add an extra description for this list')
- )
-
- content_panels = [
- MultiFieldPanel([
- FieldPanel('title'),
- FieldPanel('body'),
- ], heading=_('Content'))
- ]
-
+ # TODO: personnalized titles depending on request
class Meta:
verbose_name = _('Dynamic List Page')
verbose_name_plural = _('Dynamic List Pages')
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
- qs = ListBase.from_request(request, context=context)
- context['object_list'] = qs
+ context.update(BaseList.from_request(request))
return context
-class DatedListPage(DatedListBase,Page):
- body = RichTextField(
- _('body'),
- blank = True, null = True,
- help_text = _('add an extra description for this list')
- )
-
+class DatedListPage(DatedBaseList,BasePage):
class Meta:
abstract = True
- content_panels = [
- MultiFieldPanel([
- FieldPanel('title'),
- FieldPanel('body'),
- ], heading=_('Content')),
- ] + DatedListBase.panels
-
def get_queryset(self, request, context):
"""
Must be implemented by the child
@@ -702,6 +717,8 @@ class LogsPage(DatedListPage):
station = models.ForeignKey(
aircox.models.Station,
verbose_name = _('station'),
+ null = True, blank = True,
+ on_delete = models.SET_NULL,
help_text = _('(required) related station')
)
age_max = models.IntegerField(
@@ -763,6 +780,8 @@ class TimetablePage(DatedListPage):
station = models.ForeignKey(
aircox.models.Station,
verbose_name = _('station'),
+ on_delete = models.SET_NULL,
+ null = True, blank = True,
help_text = _('(required) related station')
)
diff --git a/aircox_cms/sections.py b/aircox_cms/sections.py
index ebc3f44..0c4f1c0 100755
--- a/aircox_cms/sections.py
+++ b/aircox_cms/sections.py
@@ -167,7 +167,7 @@ class RelatedLinkBase(Orderable):
}
-class ListBase(models.Model):
+class BaseList(models.Model):
"""
Generic list
"""
@@ -175,37 +175,24 @@ class ListBase(models.Model):
none = 0x00
previous = 0x01
next = 0x02
- before_related = 0x03,
- after_related = 0x04,
+ before_related = 0x03
+ after_related = 0x04
- date_filter = models.SmallIntegerField(
- verbose_name = _('filter by date'),
- choices = [ (int(y), _(x.replace('_', ' ')))
- for x,y in DateFilter.__members__.items() ],
- blank = True, null = True,
- )
- model = models.ForeignKey(
- ContentType,
- verbose_name = _('filter by type'),
- blank = True, null = True,
- on_delete=models.SET_NULL,
- help_text = _('if set, select only elements that are of this type'),
- limit_choices_to = related_pages_filter,
- )
- related = models.ForeignKey(
- Page,
- verbose_name = _('filter by a related page'),
- blank = True, null = True,
- on_delete=models.SET_NULL,
- help_text = _('if set, select children or siblings related to this page'),
- )
- siblings = models.BooleanField(
- verbose_name = _('select siblings of related'),
+ class RelationFilter(IntEnum):
+ none = 0x00
+ subpages = 0x01
+ siblings = 0x02
+
+ # rendering
+ use_focus = models.BooleanField(
+ _('focus available'),
default = False,
- help_text = _(
- 'if checked, related publications are siblings instead of '
- 'the children.'
- ),
+ help_text = _('if true, highlight the first focused article found')
+ )
+ count = models.SmallIntegerField(
+ _('count'),
+ default = 30,
+ help_text = _('number of items to display in the list'),
)
asc = models.BooleanField(
verbose_name = _('ascending order'),
@@ -213,27 +200,87 @@ class ListBase(models.Model):
help_text = _('if selected sort list in the ascending order by date')
)
- class Meta:
- abstract = True
+ # selectors
+ date_filter = models.SmallIntegerField(
+ verbose_name = _('filter on date'),
+ choices = [ (int(y), _(x.replace('_', ' ')))
+ for x,y in DateFilter.__members__.items() ],
+ blank = True, null = True,
+ help_text = _(
+ 'select pages whose date follows the given constraint'
+ )
+ )
+ model = models.ForeignKey(
+ ContentType,
+ verbose_name = _('filter on page type'),
+ blank = True, null = True,
+ on_delete=models.SET_NULL,
+ help_text = _('if set, select only elements that are of this type'),
+ limit_choices_to = related_pages_filter,
+ )
+ related = models.ForeignKey(
+ Page,
+ verbose_name = _('related page'),
+ blank = True, null = True,
+ on_delete=models.SET_NULL,
+ help_text = _(
+ 'if set, select children or siblings of this page'
+ ),
+ related_name = '+'
+ )
+ relation = models.BooleanField(
+ verbose_name = _('relation'),
+ choices = [ (int(y), _(x.replace('_', ' ')))
+ for x,y in RelationFilter.__members__.items() ],
+ default = 1,
+ help_text = _(
+ 'when the list is related to a page, only select pages that '
+ 'correspond to this relationship'
+ ),
+ )
+ search = models.CharField(
+ verbose_name = _('filter on search'),
+ blank = True, null = True,
+ max_length = 128,
+ help_text = _(
+ 'keep only pages that matches the given search'
+ )
+ )
+ tags = models.CharField(
+ verbose_name = _('filter on tag'),
+ blank = True, null = True,
+ max_length = 128,
+ help_text = _(
+ 'keep only pages with the given tags (separated by a colon)'
+ )
+ )
panels = [
MultiFieldPanel([
- FieldPanel('model'),
- PageChooserPanel('related'),
- FieldPanel('siblings'),
- ], heading=_('filters')),
+ FieldPanel('count'),
+ FieldPanel('use_focus'),
+ FieldPanel('asc'),
+ ], heading=_('rendering')),
MultiFieldPanel([
FieldPanel('date_filter'),
- FieldPanel('asc'),
- ], heading=_('sorting'))
+ FieldPanel('model'),
+ PageChooserPanel('related'),
+ FieldPanel('relation'),
+ FieldPanel('search'),
+ FieldPanel('tags'),
+ ], heading=_('filters'))
]
+ class Meta:
+ abstract = True
+
def __get_related(self, qs):
related = self.related and self.related.specific
- if self.siblings:
+ if self.relation == self.RelationFilter.siblings:
qs = qs.sibling_of(related)
else:
+ # elif self.relation == RelatedFilter.subpages:
qs = qs.descendant_of(related)
date = related.date if hasattr(related, 'date') else \
@@ -250,7 +297,6 @@ class ListBase(models.Model):
reusable by other classes if needed.
"""
from aircox_cms.models import Publication
-
# model
if self.model:
qs = self.model.model_class().objects.all()
@@ -262,7 +308,7 @@ class ListBase(models.Model):
if self.related:
qs = self.__get_related(qs)
- # date
+ # date_filter
date = tz.now()
if self.date_filter == self.DateFilter.previous:
qs = qs.filter(date__lt = date)
@@ -270,77 +316,138 @@ class ListBase(models.Model):
qs = qs.filter(date__gte = date)
# sort
- if self.asc:
- return qs.order_by('date', 'pk')
- return qs.order_by('-date', '-pk')
+ qs = qs.order_by('date', 'pk') \
+ if self.asc else qs.order_by('-date', '-pk')
- def to_url(self, list_page = None, **kwargs):
+ # tags
+ if self.tags:
+ qs = qs.filter(tags__name__in = ','.split(self.tags))
+
+ # search
+ if self.search:
+ # this qs.search does not return a queryset
+ qs = qs.search(self.search)
+
+ return qs
+
+ def get_context(self, request, qs = None, paginate = True):
"""
- Return a url parameters from self. Extra named parameters are used
- to override values of self or add some to the parameters.
+ Return a context object using the given request and arguments.
+ @param paginate: paginate and include paginator into context
- If there is related field use it to get the page, otherwise use the
- given list_page or the first DynamicListPage it finds.
+ Context arguments:
+ - object_list: queryset of the list's objects
+ - paginator: [if paginate] paginator object for this list
+ - list_url_args: GET arguments of the url as string
+
+ ! Note: BaseList does not inherit from Wagtail.Page, and calling
+ this method won't call other super() get_context.
"""
- import aircox_cms.models as models
+ qs = qs or self.get_queryset()
+ paginator = None
+ context = {}
+ if qs.count():
+ if paginate:
+ context.update(self.paginate(request, qs))
+ else:
+ context['object_list'] = qs[:self.count]
+ else:
+ # keep empty queryset
+ context['object_list'] = qs
+ context['list_url_args'] = self.to_url(full_url = False)
+ #context['list_selector'] = {
+ # attr: getattr(self, attr) for attr in (
+ # 'asc', 'date_filter', 'model', 'related', 'relation',
+ # 'tags', 'search',
+ # )
+ #}
+ return context
+ def paginate(self, request, qs):
+ # paginator
+ paginator = Paginator(qs, self.count)
+ try:
+ qs = paginator.page(request.GET.get('page') or 1)
+ except PageNotAnInteger:
+ qs = paginator.page(1)
+ except EmptyPage:
+ qs = paginator.page(paginator.num_pages)
+ return {
+ 'paginator': paginator,
+ 'object_list': qs
+ }
+
+ def to_url(self, page = None, full_url = True, **kwargs):
+ """
+ Return a url to a given page with GET corresponding to this
+ list's parameters.
+ @param page: if given use it to prepend url with page's url instead of giving only
+ GET parameters
+ @param **kwargs: override list parameters
+
+ If there is related field use it to get the page, otherwise use
+ the given list_page or the first BaseListPage it finds.
+ """
params = {
- 'view': 'list',
+ 'asc': self.asc,
'date_filter': self.get_date_filter_display(),
'model': self.model and self.model.model,
- 'asc': self.asc,
- 'related': self.related,
- 'siblings': self.siblings,
+ 'relation': self.get_relation_display(),
+ 'search': self.search,
+ 'tags': self.tags
}
params.update(kwargs)
- page = params.get('related') or list_page or \
- models.DynamicListPage.objects.all().first()
-
if params.get('related'):
params['related'] = True
params = '&'.join([
key if value == True else '{}={}'.format(key, value)
- for key, value in params.items()
- if value
+ for key, value in params.items() if value
])
+ if not full_url:
+ return params
+
+ page = page or self.page
+ if not page:
+ raise ValueError(
+ "full_url = True requires either list.related or "
+ "method's argument `page` to be given"
+ )
return page.url + '?' + params
@classmethod
- def from_request(cl, request, related = None, context = None,
- *args, **kwargs):
+ def from_request(cl, request, related = None):
"""
- Return a queryset from the request's GET parameters. Context
- can be used to update relative informations.
+ Return a context from the request's GET parameters. Context
+ can be used to update relative informations, more information
+ on this object from BaseList.get_context()
+
+ @param request: get params from this request
+ @param related: reference page for a related list
+ @return context object from BaseList.get_context()
This function can be used by other views if needed
Parameters:
+ * asc: if present, sort ascending instead of descending
* date_filter: one of DateFilter attribute's key.
* model: ['program','diffusion','event'] type of the publication
- * asc: if present, sort ascending instead of descending
- * related: children of the thread passed in arguments only
- * siblings: sibling of the related instead of children
+ * relation: one of RelationFilter attribute's key
+ * related: list is related to the method's argument `related`
* tag: tag to search for
* search: query to search in the publications
* page: page number
-
- Context's fields:
- * object_list: the final queryset
- * list_selector: dict of { 'tag_query', 'search_query' } plus
- arguments passed to ListBase.get_base_queryset
- * paginator: paginator object
"""
- def set(key, value):
- if context is not None:
- context[key] = value
-
+ # FIXME: page argument to select a page
+ # FIXME: related
date_filter = request.GET.get('date_filter')
model = request.GET.get('model')
+ relation = request.GET.get('relation')
kwargs = {
+ 'asc': 'asc' in request.GET,
'date_filter':
int(getattr(cl.DateFilter, date_filter))
if date_filter and hasattr(cl.DateFilter, date_filter)
@@ -350,42 +457,21 @@ class ListBase(models.Model):
DiffusionPage if model == 'diffusion' else
EventPage if model == 'event' else None,
'related': 'related' in request.GET and related,
- 'siblings': 'siblings' in request.GET,
- 'asc': 'asc' in request.GET,
+ 'relation':
+ int(getattr(cl.RelationFilter, relation))
+ if relation and hasattr(cl.RelationFilter, relation)
+ else None,
+ 'tags': request.GET.get('tags'),
+ 'search': request.GET.get('search'),
}
- base_list = cl(**{ k:v for k,v in kwargs.items() if v })
- qs = base_list.get_queryset()
-
- # filter by tag
- tag = request.GET.get('tag')
- if tag:
- kwargs['terms'] = tag
- qs = qs.filter(tags__name = tag)
-
- # search
- search = request.GET.get('search')
- if search:
- kwargs['terms'] = search
- qs = qs.search(search)
-
- set('list_selector', kwargs)
-
- # paginator
- if qs:
- paginator = Paginator(qs, 30)
- try:
- qs = paginator.page(request.GET.get('page') or 1)
- except PageNotAnInteger:
- qs = paginator.page(1)
- except EmptyPage:
- qs = parginator.page(paginator.num_pages)
- set('paginator', paginator)
- set('object_list', qs)
- return qs
+ base_list = cl(
+ count = 30, **{ k:v for k,v in kwargs.items() if v }
+ )
+ return base_list.get_context(request)
-class DatedListBase(models.Model):
+class DatedBaseList(models.Model):
"""
List that display items per days. Renders a navigation section on the
top.
@@ -794,70 +880,47 @@ class SectionLink(RelatedLinkBase,TemplateMixin):
@register_snippet
-class SectionList(ListBase, SectionRelativeItem):
+class SectionList(BaseList, SectionRelativeItem):
"""
This one is quite badass, but needed: render a list of pages
- using given parameters (cf. ListBase).
+ using given parameters (cf. BaseList).
If focus_available, the first article in the list will be the last
article with a focus, and will be rendered in a bigger size.
"""
- focus_available = models.BooleanField(
- _('focus available'),
- default = False,
- help_text = _('if true, highlight the first focused article found')
- )
- count = models.SmallIntegerField(
- _('count'),
- default = 5,
- help_text = _('number of items to display in the list'),
- )
+ # TODO/FIXME: focus, quid?
+ # TODO: logs in menu show headline???
url_text = models.CharField(
_('text of the url'),
max_length=32,
blank = True, null = True,
help_text = _('use this text to display an URL to the complete '
- 'list. If empty, does not print an address'),
+ 'list. If empty, no link is displayed'),
)
panels = SectionRelativeItem.panels + [
- MultiFieldPanel([
- FieldPanel('focus_available'),
- FieldPanel('count'),
FieldPanel('url_text'),
- ], heading=_('Rendering')),
- ] + ListBase.panels
+ ] + BaseList.panels
def get_context(self, request, page):
- from aircox_cms.models import Publication
- context = super().get_context(request, page)
-
+ import aircox_cms.models as cms
if self.is_related:
self.related = 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'
- qs = qs.exclude(pk = focus.pk)
- else:
- focus = None
-
- if not qs.count():
+ context = BaseList.get_context(self, request, paginate = False)
+ if not context['object_list'].count():
return { 'hide': True }
- pages = qs[:self.count - (focus != None)]
-
- context['focus'] = focus
- context['object_list'] = pages
+ context.update(SectionRelativeItem.get_context(self, request, page))
if self.url_text:
- context['url'] = self.to_url(
- list_page = self.is_related and page
- )
+ if not self.is_related or not page:
+ settings = cms.WebsiteSettings.for_site(request.site)
+ page = settings.list_page
+ context['url'] = self.to_url(page = page) + '&view=list'
return context
+SectionList._meta.get_field('count').default = 5
+
@register_snippet
class SectionLogsList(SectionItem):
@@ -915,7 +978,7 @@ class SectionLogsList(SectionItem):
@register_snippet
-class SectionTimetable(SectionItem,DatedListBase):
+class SectionTimetable(SectionItem,DatedBaseList):
class Meta:
verbose_name = _('Section: Timetable')
verbose_name_plural = _('Sections: Timetable')
@@ -937,8 +1000,8 @@ class SectionTimetable(SectionItem,DatedListBase):
help_text = _('if checked, navigation dates will be shown')
)
- # TODO: put in multi-field panel of datedlistbase
- panels = SectionItem.panels + DatedListBase.panels + [
+ # TODO: put in multi-field panel of DatedBaseList
+ panels = SectionItem.panels + DatedBaseList.panels + [
MultiFieldPanel([
FieldPanel('nav_visible'),
FieldPanel('target'),
@@ -987,12 +1050,6 @@ class SectionSearchField(SectionItem):
FieldPanel('default_text'),
]
- def get_context(self, request, page):
- # FIXME ?????
- from aircox_cms.models import DynamicListPage
- context = super().get_context(request, page)
- return context
-
@register_snippet
class SectionPlayer(SectionItem):
diff --git a/aircox_cms/static/aircox_cms/css/layout.css b/aircox_cms/static/aircox_cms/css/layout.css
index 5f66ad8..7dbf9fd 100755
--- a/aircox_cms/static/aircox_cms/css/layout.css
+++ b/aircox_cms/static/aircox_cms/css/layout.css
@@ -148,7 +148,7 @@ body section ul {
width: 100%;
}
-ul.list {
+ul.list, .list > ul {
padding: 0.4em;
}
@@ -186,6 +186,21 @@ ul.list {
}
+/** content: list items in full page **/
+.content > .list .list_item {
+ min-width: 20em;
+ display: inline-block;
+ min-height: 2.5em;
+ margin: 0.4em;
+}
+
+.content > .list .dated_list_item time {
+ color: #007EDF;
+ display: block;
+ margin-left: -0.5em;
+}
+
+
/** content: date list **/
.date_list nav {
text-align:center;
diff --git a/aircox_cms/static/aircox_cms/css/theme.css b/aircox_cms/static/aircox_cms/css/theme.css
index 9b43acf..65ae99d 100755
--- a/aircox_cms/static/aircox_cms/css/theme.css
+++ b/aircox_cms/static/aircox_cms/css/theme.css
@@ -82,12 +82,15 @@ a:hover > .small_icon {
main {
background-color: rgba(255,255,255,0.9);
- padding: 1em;
margin: 0em 2em;
box-shadow: 0em 0em 0.2em black;
width: 60%;
}
+ main > .content {
+ /*! margin: 1em; */
+ }
+
main:not(.detail) h1 {
margin: 0em 0em 0.4em 0em;
@@ -109,68 +112,65 @@ main.detail {
padding: 0em;
}
- main.detail > .content {
+ main > .content {
padding: 1em;
}
- main.detail > header {
- padding: 0em;
+ main > header {
margin: 0em;
- }
-
- main.detail > header h1.title,
- main.detail > header .headline {
- display: block;
- padding: 0.4em;
- vertical-align: middle;
- transition: opacity 1.5s;
- }
-
- main.detail > header:hover h1.title,
- main.detail > header:hover .headline {
- opacity: 0.0;
- transition: opacity 1.5s 1s;
- }
-
- main.detail > header h1.title {
+ padding: 1em;
position: relative;
- z-index: 1000;
- height: 1.2em;
+ }
+
+ main > header .foreground {
+ position: absolute;
+ left: 0em;
+ top: 0em;
+ width: calc(100% - 2em);
+ padding: 1em;
+ }
+
+ main > header h1 {
+ width: calc(100% - 2em);
margin: 0em;
- background-color: rgba(255,255,255,0.8);
- /*! padding-top: 0em; */
+ margin-bottom: 0.8em;
}
- main.detail > header h1.title + section {
- margin-top: 2em;
- }
-
- main.detail header .headline {
+ main header .headline {
display: inline-block;
- width: calc(100% - 0.8em);
+ width: calc(60% - 0.8em);
min-height: 1.2em;
font-size: 1.2em;
font-weight: bold;
- background-color: rgba(255,255,255,0.8);
}
- main.detail > header .cover_container,
- main.detail > header img.cover {
- display: block;
- width: 100%;
+ main > header .background {
+ margin: -1em;
+ height: 17em;
+ overflow: hidden;
+ position: relative;
}
- main.detail > header .cover_container {
- max-height: 450px;
- overflow: hidden;
- margin-top: -2.8em;
- margin-bottom: -2.4em;
+ main > header .background img {
+ position: absolute;
+ top: -40%;
+ left: -40%;
+ width: 250%;
+ min-height: 250%;
+ filter: blur(20px);
+ opacity: 0.3;
}
- main.detail > header img.cover {
- height: auto;
- margin: auto;
- vertical-align: middle;
+ main > header .cover {
+ right: 0em;
+ bottom: 0em;
+ width: auto;
+ max-height: calc(100% - 4em);
+ max-width: 40%;
+ margin: 1em;
+ position: absolute;
+ box-shadow: 0em 0em 4em rgba(0, 0, 0, 0.3);
+ border: 1em rgba(255, 255, 255, 0.1) solid;
}
diff --git a/aircox_cms/static/wagtailadmin/css/core.css b/aircox_cms/static/wagtailadmin/css/core.css
index 47d7d32..d73f7f6 100644
--- a/aircox_cms/static/wagtailadmin/css/core.css
+++ b/aircox_cms/static/wagtailadmin/css/core.css
@@ -5296,7 +5296,7 @@ body.explorer-open .explorer-close {
}
li.submenu-active .nav-submenu {
box-shadow: 2px 0 2px rgba(0, 0, 0, 0.35);
- width: 220px;
+ width: 230px;
padding: 0 0 0.5em;
}
body.ready li.submenu-active .nav-submenu {
diff --git a/aircox_cms/templates/aircox_cms/base_site.html b/aircox_cms/templates/aircox_cms/base_site.html
index c06b27e..46c6991 100755
--- a/aircox_cms/templates/aircox_cms/base_site.html
+++ b/aircox_cms/templates/aircox_cms/base_site.html
@@ -1,6 +1,7 @@
{% load staticfiles %}
{% load i18n %}
+{% load wagtailcore_tags %}
{% load wagtailimages_tags %}
{% load wagtailsettings_tags %}
@@ -60,12 +61,47 @@
{% block title %}
- {{ page.title }}
+ {% if page.cover %}
+
+ {% image page.cover max-600x480 class="background-cover" height="" width="" %}
+
+ {% image page.cover max-600x480 class="cover" height="" width="" %}
+
+ {% endif %}
+
+
+ {% if page.headline %}
+
+ {% endif %}
+ {% if page.cover %}
+
+ {% endif %}
{% endblock %}
- {% block content %}
- {% endblock %}
+
+ {% block content %}
+ {% if page.body %}
+
+ {{ page.body|richtext}}
+
+ {% endif %}
+ {% endblock %}
+
+ {% block content_extras %}
+ {% endblock %}
+
+
+ {% render_sections position="post_content" %}
+
+
+
+
+