work on schedule; section.as_view()

This commit is contained in:
bkfox 2016-06-07 01:57:06 +02:00
parent 2365cc8b8e
commit b99dec05e3
8 changed files with 184 additions and 120 deletions

View File

@ -103,6 +103,9 @@ class Post (models.Model, Routable):
""" """
Base model that can be used as is if wanted. Represent a generic Base model that can be used as is if wanted. Represent a generic
publication on the website. publication on the website.
You can declare an extra property "info" that can be used to append
info in lists rendering.
""" """
# metadata # metadata
thread_type = models.ForeignKey( thread_type = models.ForeignKey(

View File

@ -35,8 +35,6 @@ class Section(View):
* name: set name/id of the section container * name: set name/id of the section container
* css_class: css classes of the container * css_class: css classes of the container
* attr: HTML attributes of the container * attr: HTML attributes of the container
* hide_empty: if true, section is not rendered when content is empty
* title: title of the section * title: title of the section
* header: header of the section * header: header of the section
* footer: footer of the section * footer: footer of the section
@ -50,13 +48,28 @@ class Section(View):
name = '' name = ''
css_class = '' css_class = ''
attrs = None attrs = None
# hide_empty = False
title = '' title = ''
header = '' header = ''
footer = '' footer = ''
object = None
force_object = None force_object = None
request = None
object = None
kwargs = None
@classmethod
def as_view (cl, *args, **kwargs):
"""
Similar to View.as_view, but instead, wrap a constructor of the
given class that is used as is.
"""
def func(**kwargs_):
if kwargs_:
kwargs.update(kwargs_)
instance = cl(*args, **kwargs)
return instance
return func
def add_css_class(self, css_class): def add_css_class(self, css_class):
if self.css_class: if self.css_class:
if css_class not in self.css_class: if css_class not in self.css_class:
@ -80,7 +93,11 @@ class Section(View):
def get_content(self): def get_content(self):
return '' return ''
def get_context_data(self): def get_context_data(self, request = None, object = None, **kwargs):
if request: self.request = request
if object: self.object = object
if kwargs: self.kwargs = kwargs
return { return {
'view': self, 'view': self,
'tag': self.tag, 'tag': self.tag,
@ -93,14 +110,10 @@ class Section(View):
'object': self.object, 'object': self.object,
} }
def get_context(self, request, object=None, **kwargs): def get(self, request, object=None, return_context=False, **kwargs):
self.object = self.force_object or object context = self.get_context_data(request=request, object=object, **kwargs)
self.request = request if return_context:
self.kwargs = kwargs return context
return self.get_context_data()
def get(self, request, object=None, **kwargs):
context = self.get_context(request, object, **kwargs)
if not context: if not context:
return '' return ''
return render_to_string(self.template_name, context, request=request) return render_to_string(self.template_name, context, request=request)
@ -131,9 +144,12 @@ class Content(Section):
Attributes: Attributes:
* content: raw HTML code to render * content: raw HTML code to render
* rel_attr: name of the attribute of self.object to use * rel_attr: name of the attribute of self.object to use
* re_image_attr: if true and there is an image on the current object,
render the object's image
""" """
content = None content = None
rel_attr = 'content' rel_attr = 'content'
rel_image_attr = 'image'
def get_content(self): def get_content(self):
if self.content is None: if self.content is None:
@ -142,6 +158,10 @@ class Content(Section):
content = escape(content) content = escape(content)
content = re.sub(r'(^|\n\n)((\n?[^\n])+)', r'<p>\2</p>', content) content = re.sub(r'(^|\n\n)((\n?[^\n])+)', r'<p>\2</p>', content)
content = re.sub(r'\n', r'<br>', content) content = re.sub(r'\n', r'<br>', content)
if self.rel_image_attr and hasattr(self.object, self.rel_image_attr):
image = getattr(self.object, self.rel_image_attr)
content = '<img src="{}">'.format(image.url) + content
return content return content
return str(self.content) return str(self.content)
@ -222,12 +242,13 @@ class List(Section):
def get_object_list(self): def get_object_list(self):
return self.object_list return self.object_list
def get_context_data(self): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
object_list = self.object_list or self.get_object_list() object_list = self.object_list or self.get_object_list()
if not object_list and not self.message_empty: if not object_list and not self.message_empty:
return return
context = super().get_context_data()
context.update({ context.update({
'base_template': 'aircox/cms/section.html', 'base_template': 'aircox/cms/section.html',
'list': self, 'list': self,
@ -276,14 +297,15 @@ class Comments(List):
}) })
return '' return ''
def get_context_data(self): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
comment_form = None comment_form = None
if self.object: if self.object:
post = self.object post = self.object
if hasattr(post, 'allow_comments') and post.allow_comments: if hasattr(post, 'allow_comments') and post.allow_comments:
comment_form = (self.comment_form or CommentForm()) comment_form = (self.comment_form or CommentForm())
context = super().get_context_data()
context.update({ context.update({
'comment_form': comment_form, 'comment_form': comment_form,
}) })
@ -319,11 +341,15 @@ class Menu(Section):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.css_class += ' menu menu_{}'.format(self.name or self.position) self.add_css_class('menu')
self.add_css_class('menu_' + str(self.name or self.position))
self.sections = [ section() if callable(section) else section
for section in self.sections ]
if not self.attrs: if not self.attrs:
self.attrs = {} self.attrs = {}
def get_context_data(self): def get_context_data(self, *args, **kwargs):
super().get_context_data(*args, **kwargs)
return { return {
'tag': self.tag, 'tag': self.tag,
'css_class': self.css_class, 'css_class': self.css_class,

View File

@ -7,7 +7,7 @@
{% block content %} {% block content %}
<ul> <ul class="content">
{% for item in object_list %} {% for item in object_list %}
<li {% if item.css_class %}class="{{ item.css_class }}"{% endif %} <li {% if item.css_class %}class="{{ item.css_class }}"{% endif %}
{% for k, v in item.attrs.items %} {% for k, v in item.attrs.items %}
@ -16,6 +16,25 @@
{% if item.detail_url %} {% if item.detail_url %}
<a href="{{ item.detail_url }}"> <a href="{{ item.detail_url }}">
{% endif %} {% endif %}
{% if 'image' in list.fields and item.image %}
<img src="{% thumbnail item.image list.image_size crop %}">
{% endif %}
<div class="content">
{% if 'title' in list.fields and item.title %}
<h2 class="title">{{ item.title }}</h2>
{% endif %}
{% if 'content' in list.fields and item.content %}
<div class="text">
{% if list.truncate %}
{{ item.content|striptags|truncatewords:list.truncate }}
{% else %}
{{ item.content|striptags }}
{% endif %}
</div>
{% endif %}
</div>
<div class="meta"> <div class="meta">
{% if item.date and 'date' in list.fields or 'time' in list.fields %} {% if item.date and 'date' in list.fields or 'time' in list.fields %}
@ -45,25 +64,6 @@
{% endif %} {% endif %}
</div> </div>
{% if 'image' in list.fields and item.image %}
<img src="{% thumbnail item.image list.image_size crop %}">
{% endif %}
<div class="content">
{% if 'title' in list.fields and item.title %}
<h2 class="title">{{ item.title }}</h2>
{% endif %}
{% if 'content' in list.fields and item.content %}
<div class="text">
{% if list.truncate %}
{{ item.content|striptags|truncatewords:list.truncate }}
{% else %}
{{ item.content|striptags }}
{% endif %}
</div>
{% endif %}
</div>
{% if item.detail_url %} {% if item.detail_url %}
</a> </a>
@ -75,8 +75,8 @@
{% endfor %} {% endfor %}
</ul> </ul>
{% if object_list %} {% if object_list and not embed %}
{% if page_obj or list.url %} {% if list.url or page_obj %}
<nav> <nav>
{% if not page_obj or embed %} {% if not page_obj or embed %}
{% comment %}link to show more elements of the list{% endcomment %} {% comment %}link to show more elements of the list{% endcomment %}

View File

@ -72,10 +72,6 @@ class PostListView(PostBaseView, ListView):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if self.list:
self.template_name = self.list.template_name
self.css_class = self.list.css_class
self.add_css_class('list')
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.route = self.kwargs.get('route') or self.route self.route = self.kwargs.get('route') or self.route
@ -88,9 +84,7 @@ class PostListView(PostBaseView, ListView):
qs = self.route.get_queryset(self.model, self.request, qs = self.route.get_queryset(self.model, self.request,
**self.kwargs) **self.kwargs)
else: else:
# FIXME: should neven happen
qs = self.queryset or self.model.objects.all() qs = self.queryset or self.model.objects.all()
qs = qs.filter(published = True) qs = qs.filter(published = True)
query = self.request.GET query = self.request.GET
@ -101,45 +95,47 @@ class PostListView(PostBaseView, ListView):
else: else:
qs = qs.order_by('date', 'id') qs = qs.order_by('date', 'id')
if query.get('fields'):
self.fields = [
field for field in query.get('fields')
if field in self.__class__.fields
]
return qs return qs
def get_context_data(self, **kwargs): def init_list(self):
if self.list: if not self.list:
list = self.list self.list = sections.List(
else:
list = sections.List(
truncate = 32, truncate = 32,
fields = ['date', 'time', 'image', 'title', 'content'], fields = ['date', 'time', 'image', 'title', 'content'],
) )
else:
self.list = self.list()
self.template_name = self.list.template_name
self.css_class = self.list.css_class
context = list.get_context(request = self.request, **self.kwargs) or {} if self.request.GET.get('fields'):
self.list.fields = [
field for field in self.request.GET.getlist('fields')
if field in self.list.fields
]
def get_context_data(self, **kwargs):
self.init_list()
self.add_css_class('list')
context = self.list.get_context_data(self.request, **self.kwargs) or {}
context.update(super().get_context_data(**kwargs)) context.update(super().get_context_data(**kwargs))
context.update(self.get_base_context(**kwargs)) context.update(self.get_base_context(**kwargs))
if self.title: if self.title:
title = self.title title = self.title
else: elif self.route:
title = self.route and \ title = self.route.get_title(self.model, self.request,
self.route.get_title(self.model, self.request,
**self.kwargs) **self.kwargs)
context.update({ context.update({
'title': title, 'title': title,
'base_template': 'aircox/cms/website.html', 'base_template': 'aircox/cms/website.html',
'css_class': self.css_class, 'css_class': self.css_class,
'list': list, 'list': self.list,
}) })
# FIXME: list.url = if self.route: self.model(self.route, self.kwargs) else ''
return context return context
def get_url(self):
return ''
class PostDetailView(DetailView, PostBaseView): class PostDetailView(DetailView, PostBaseView):
""" """
@ -156,7 +152,7 @@ class PostDetailView(DetailView, PostBaseView):
def __init__(self, sections = None, *args, **kwargs): def __init__(self, sections = None, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.add_css_class('detail') self.add_css_class('detail')
self.sections = sections or [] self.sections = [ section() for section in (sections or []) ]
def get_queryset(self): def get_queryset(self):
if self.request.GET.get('embed'): if self.request.GET.get('embed'):

View File

@ -662,7 +662,7 @@ class Diffusion(models.Model):
**filter_args **filter_args
).order_by('-start') ).order_by('-start')
def is_date_in_my_range(self, date): def is_date_in_my_range(self, date = None):
""" """
Return true if the given date is in the diffusion's start-end Return true if the given date is in the diffusion's start-end
range. range.

View File

@ -50,3 +50,10 @@ class Diffusion (RelatedPost):
if not self.tags and self.pk: if not self.tags and self.pk:
self.tags = self.thread.tags self.tags = self.thread.tags
@property
def info(self):
if not self.related or not self.related.initial:
return
return _('rerun of %(day)s') % {
'day': self.related.initial.start.strftime('%A %d/%m')
}

View File

@ -14,8 +14,6 @@ class Diffusions(sections.List):
Section that print diffusions. When rendering, if there is no post yet Section that print diffusions. When rendering, if there is no post yet
associated, use the programs' article. associated, use the programs' article.
""" """
next_count = 5
prev_count = 5
order_by = '-start' order_by = '-start'
show_schedule = False show_schedule = False
@ -32,16 +30,16 @@ class Diffusions(sections.List):
if filter_args: if filter_args:
qs = qs.filter(**filter_args).order_by('start') qs = qs.filter(**filter_args).order_by('start')
r = []
if not self.next_count and not self.prev_count:
return qs return qs
if self.next_count:
r += list(programs.Diffusion.get(next=True, queryset = qs) #r = []
.order_by('-start')[:self.next_count]) #if self.next_count:
if self.prev_count: # r += list(programs.Diffusion.get(next=True, queryset = qs)
r += list(programs.Diffusion.get(prev=True, queryset = qs) # .order_by('-start')[:self.next_count])
.order_by('-start')[:self.prev_count]) #if self.prev_count:
return r # r += list(programs.Diffusion.get(prev=True, queryset = qs)
# .order_by('-start')[:self.prev_count])
#return r
def get_object_list(self): def get_object_list(self):
diffs = self.get_diffs() diffs = self.get_diffs()
@ -59,7 +57,7 @@ class Diffusions(sections.List):
if diff.initial: if diff.initial:
post.info = _('rerun of %(day)s') % { post.info = _('rerun of %(day)s') % {
'day': diff.initial.date.strftime('%A %d/%m') 'day': diff.initial.start.strftime('%A %d/%m')
} }
if self.object: if self.object:
@ -121,10 +119,7 @@ class Schedule(Diffusions):
Render a list of diffusions in the form of a schedule Render a list of diffusions in the form of a schedule
""" """
template_name = 'aircox/website/schedule.html' template_name = 'aircox/website/schedule.html'
next_count = None
prev_count = None
date = None date = None
days = 7
nav_date_format = '%a. %d' nav_date_format = '%a. %d'
fields = [ 'time', 'image', 'title'] fields = [ 'time', 'image', 'title']
@ -134,13 +129,16 @@ class Schedule(Diffusions):
@staticmethod @staticmethod
def get_week_dates(date): def get_week_dates(date):
"""
Return a list of dates of the week of the given date.
"""
first = date - tz.timedelta(days=date.weekday()) first = date - tz.timedelta(days=date.weekday())
return [ first + tz.timedelta(days=i) for i in range(0, 7) ] return [ first + tz.timedelta(days=i) for i in range(0, 7) ]
def date_or_default(self): def date_or_default(self):
if self.date: if self.date:
return self.date return self.date
elif 'year' in self.kwargs: elif self.kwargs and 'year' in self.kwargs:
return tz.datetime(year = int(self.kwargs['year']), return tz.datetime(year = int(self.kwargs['year']),
month = int(self.kwargs['month']), month = int(self.kwargs['month']),
day = int(self.kwargs['day']), day = int(self.kwargs['day']),
@ -148,18 +146,21 @@ class Schedule(Diffusions):
microsecond = 0) microsecond = 0)
return tz.datetime.now() return tz.datetime.now()
def get_diffs(self): def get_object_list(self):
date = self.date_or_default() date = self.date_or_default()
diffs = super().get_diffs( qs = routes.DateRoute.get_queryset(
start__year = date.year, models.Diffusion, self.request,
start__month = date.month, year = date.year,
start__day = date.day, month = date.month,
) day = date.day
return diffs ).order_by('date')
return qs
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
def get_context_data(self, **kwargs):
date = self.date_or_default() date = self.date_or_default()
dates_url = [ dates = [
(date, models.Diffusion.route_url( (date, models.Diffusion.route_url(
routes.DateRoute, routes.DateRoute,
year = date.year, month = date.month, day = date.day year = date.year, month = date.month, day = date.day
@ -167,13 +168,33 @@ class Schedule(Diffusions):
for date in self.get_week_dates(date) for date in self.get_week_dates(date)
] ]
context = super().get_context_data(**kwargs) next_week = dates[-1][0] + tz.timedelta(days=1)
next_week = models.Diffusion.route_url(
routes.DateRoute,
year = next_week.year, month = next_week.month,
day = next_week.day
)
prev_week = dates[0][0] - tz.timedelta(days=1)
prev_week = models.Diffusion.route_url(
routes.DateRoute,
year = prev_week.year, month = prev_week.month,
day = prev_week.day
)
context.update({ context.update({
'date': date, 'date': date,
'dates_url': dates_url, 'dates': dates,
'next_week': next_week,
'prev_week': prev_week,
}) })
return context return context
@property
def url(self):
return None
#class DatesOfDiffusion(sections.List): #class DatesOfDiffusion(sections.List):
# title = _('Dates of diffusion') # title = _('Dates of diffusion')

View File

@ -6,42 +6,53 @@
function update_schedule(event) { function update_schedule(event) {
var target = event.currentTarget; var target = event.currentTarget;
var url = target.getAttribute('href'); var url = target.getAttribute('href');
var schedule = target; var schedule = target;
while(schedule && schedule.className.indexOf('schedule'))
schedule = schedule.parentNode;
if(!schedule)
return false;
// prevent event
event.preventDefault();
// get schedule
while(schedule) {
if (schedule.className &&
schedule.className.indexOf('section_schedule') != -1)
break;
schedule = schedule.parentNode;
}
if(!schedule)
return;
console.log(schedule.className)
// xhr
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() { xhr.onreadystatechange = function() {
if(xhr.readyState != 4 || xhr.status != 200 && xhr.status) if(xhr.readyState != 4 || xhr.status != 200 && xhr.status)
return; return;
var obj = document.createElement('div'); var obj = document.implementation.createHTMLDocument('result');
obj.innerHTML = xhr.responseText; obj.documentElement.innerHTML = xhr.responseText;
target.replaceChild( obj = obj.documentElement;
obj.querySelector('.content'),
schedule.querySelector('.schedule .content')
)
target.replaceChild(
obj.querySelector('.schedule header'),
schedule.querySelector('.schedule header')
)
// target.querySelector('nav a').href = url
}
xhr.open('GET', url + '?embed=1', true); schedule.querySelector('header').innerHTML =
obj.querySelector('header').innerHTML;
schedule.querySelector('.content').innerHTML =
obj.querySelector('.content').innerHTML;
}
fields = [ {% for field in list.fields %}"fields={{ field }}",{% endfor %} ];
fields = fields.join('&');
xhr.open('GET', url + '?embed=1&' + fields, true);
xhr.send(); xhr.send();
return false;
} }
</script> </script>
{% for curr, url in dates_url %} <a href="{{ prev_week }}" onclick="update_schedule(event); return true;">&lt;</a>
<a href="{{ url }}" onclick="return update_schedule(event);" {% if curr == date %} {% for curr, url in dates %}
class="selected"{% endif %}> <a href="{{ url }}" {% if curr == date %}class="selected" {% endif %}
onclick="update_schedule(event); return true;">
{{ curr|date:'D. d' }} {{ curr|date:'D. d' }}
</a> </a>
{% endfor %} {% endfor %}
<a href="{{ next_week }}" onclick="update_schedule(event); return true;">&gt;</a>
</header> </header>
{% endblock %} {% endblock %}