1
|
|
|
"""Page CMS page_tags template tags""" |
2
|
|
|
from django import template |
3
|
|
|
from django.utils.safestring import SafeText |
4
|
|
|
from django.template import TemplateSyntaxError |
5
|
|
|
from django.conf import settings |
6
|
|
|
from django.utils.text import unescape_string_literal |
7
|
|
|
|
8
|
|
|
from pages import settings as pages_settings |
9
|
|
|
from pages.models import Content, Page |
10
|
|
|
from pages.placeholders import PlaceholderNode, ImagePlaceholderNode, FilePlaceholderNode |
11
|
|
|
from pages.placeholders import ContactPlaceholderNode, MarkdownPlaceholderNode |
12
|
|
|
from pages.placeholders import JsonPlaceholderNode, parse_placeholder |
13
|
|
|
from six.moves import urllib |
14
|
|
|
import six |
15
|
|
|
|
16
|
|
|
register = template.Library() |
17
|
|
|
|
18
|
|
|
|
19
|
|
|
def get_page_from_string_or_id(page_string, lang=None): |
20
|
|
|
"""Return a Page object from a slug or an id.""" |
21
|
|
|
if type(page_string) == int: |
22
|
|
|
return Page.objects.get(pk=int(page_string)) |
23
|
|
|
# if we have a string coming from some templates templates |
24
|
|
|
if (isinstance(page_string, SafeText) or |
25
|
|
|
isinstance(page_string, six.string_types)): |
26
|
|
|
if page_string.isdigit(): |
27
|
|
|
return Page.objects.get(pk=int(page_string)) |
28
|
|
|
return Page.objects.from_path(page_string, lang) |
29
|
|
|
# in any other case we return the input becasue it's probably |
30
|
|
|
# a Page object. |
31
|
|
|
return page_string |
32
|
|
|
|
33
|
|
|
def _get_content(context, page, content_type, lang, fallback=True): |
34
|
|
|
"""Helper function used by ``PlaceholderNode``.""" |
35
|
|
|
if not page: |
36
|
|
|
return '' |
37
|
|
|
|
38
|
|
|
if not lang and 'lang' in context: |
39
|
|
|
lang = context.get('lang', pages_settings.PAGE_DEFAULT_LANGUAGE) |
40
|
|
|
|
41
|
|
|
page = get_page_from_string_or_id(page, lang) |
42
|
|
|
|
43
|
|
|
if not page: |
44
|
|
|
return '' |
45
|
|
|
|
46
|
|
|
content = Content.objects.get_content(page, lang, content_type, fallback) |
47
|
|
|
return content |
48
|
|
|
|
49
|
|
|
"""Filters""" |
50
|
|
|
|
51
|
|
|
|
52
|
|
|
def has_content_in(page, language): |
53
|
|
|
"""Fitler that return ``True`` if the page has any content in a |
54
|
|
|
particular language. |
55
|
|
|
|
56
|
|
|
:param page: the current page |
57
|
|
|
:param language: the language you want to look at |
58
|
|
|
""" |
59
|
|
|
return Content.objects.filter(page=page, language=language).count() > 0 |
60
|
|
|
register.filter(has_content_in) |
61
|
|
|
|
62
|
|
|
|
63
|
|
|
"""Inclusion tags""" |
64
|
|
|
|
65
|
|
|
|
66
|
|
|
def pages_menu(context, page, url='/'): |
67
|
|
|
"""Render a nested list of all the descendents of the given page, |
68
|
|
|
including this page. |
69
|
|
|
|
70
|
|
|
:param page: the page where to start the menu from. |
71
|
|
|
:param url: not used anymore. |
72
|
|
|
""" |
73
|
|
|
lang = context.get('lang', pages_settings.PAGE_DEFAULT_LANGUAGE) |
74
|
|
|
page = get_page_from_string_or_id(page, lang) |
75
|
|
|
if page: |
76
|
|
|
children = page.get_children_for_frontend() |
77
|
|
|
context.update({'children': children, 'page': page}) |
78
|
|
|
return context |
79
|
|
|
pages_menu = register.inclusion_tag('pages/menu.html', |
80
|
|
|
takes_context=True)(pages_menu) |
81
|
|
|
|
82
|
|
|
|
83
|
|
|
def pages_sub_menu(context, page, url='/'): |
84
|
|
|
"""Get the root page of the given page and |
85
|
|
|
render a nested list of all root's children pages. |
86
|
|
|
Good for rendering a secondary menu. |
87
|
|
|
|
88
|
|
|
:param page: the page where to start the menu from. |
89
|
|
|
:param url: not used anymore. |
90
|
|
|
""" |
91
|
|
|
lang = context.get('lang', pages_settings.PAGE_DEFAULT_LANGUAGE) |
92
|
|
|
page = get_page_from_string_or_id(page, lang) |
93
|
|
|
if page: |
94
|
|
|
root = page.get_root() |
95
|
|
|
children = root.get_children_for_frontend() |
96
|
|
|
context.update({'children': children, 'page': page}) |
97
|
|
|
return context |
98
|
|
|
pages_sub_menu = register.inclusion_tag('pages/sub_menu.html', |
99
|
|
|
takes_context=True)(pages_sub_menu) |
100
|
|
|
|
101
|
|
|
|
102
|
|
|
def pages_siblings_menu(context, page, url='/'): |
103
|
|
|
"""Get the parent page of the given page and render a nested list of its |
104
|
|
|
child pages. Good for rendering a secondary menu. |
105
|
|
|
|
106
|
|
|
:param page: the page where to start the menu from. |
107
|
|
|
:param url: not used anymore. |
108
|
|
|
""" |
109
|
|
|
lang = context.get('lang', pages_settings.PAGE_DEFAULT_LANGUAGE) |
110
|
|
|
page = get_page_from_string_or_id(page, lang) |
111
|
|
|
if page: |
112
|
|
|
siblings = page.get_siblings() |
113
|
|
|
context.update({'children': siblings, 'page': page}) |
114
|
|
|
return context |
115
|
|
|
pages_siblings_menu = register.inclusion_tag('pages/sub_menu.html', |
116
|
|
|
takes_context=True)(pages_siblings_menu) |
117
|
|
|
|
118
|
|
|
|
119
|
|
|
def pages_admin_menu(context, page): |
120
|
|
|
"""Render the admin table of pages.""" |
121
|
|
|
request = context.get('request', None) |
122
|
|
|
|
123
|
|
|
expanded = False |
124
|
|
|
if request and "tree_expanded" in request.COOKIES: |
125
|
|
|
cookie_string = urllib.parse.unquote(request.COOKIES['tree_expanded']) |
126
|
|
|
if cookie_string: |
127
|
|
|
ids = [int(id) for id in |
128
|
|
|
urllib.parse.unquote(request.COOKIES['tree_expanded']).split(',')] |
129
|
|
|
if page.id in ids: |
130
|
|
|
expanded = True |
131
|
|
|
context.update({'expanded': expanded, 'page': page}) |
132
|
|
|
return context |
133
|
|
|
pages_admin_menu = register.inclusion_tag('admin/pages/page/menu.html', |
134
|
|
|
takes_context=True)(pages_admin_menu) |
135
|
|
|
|
136
|
|
|
|
137
|
|
|
def show_content(context, page, content_type, lang=None, fallback=True): |
138
|
|
|
"""Display a content type from a page. |
139
|
|
|
|
140
|
|
|
Example:: |
141
|
|
|
|
142
|
|
|
{% show_content page_object "title" %} |
143
|
|
|
|
144
|
|
|
You can also use the slug of a page:: |
145
|
|
|
|
146
|
|
|
{% show_content "my-page-slug" "title" %} |
147
|
|
|
|
148
|
|
|
Or even the id of a page:: |
149
|
|
|
|
150
|
|
|
{% show_content 10 "title" %} |
151
|
|
|
|
152
|
|
|
:param page: the page object, slug or id |
153
|
|
|
:param content_type: content_type used by a placeholder |
154
|
|
|
:param lang: the wanted language |
155
|
|
|
(default None, use the request object to know) |
156
|
|
|
:param fallback: use fallback content from other language |
157
|
|
|
""" |
158
|
|
|
return {'content': _get_content(context, page, content_type, lang, |
159
|
|
|
fallback)} |
160
|
|
|
show_content = register.inclusion_tag('pages/content.html', |
161
|
|
|
takes_context=True)(show_content) |
162
|
|
|
|
163
|
|
|
|
164
|
|
|
def show_absolute_url(context, page, lang=None): |
165
|
|
|
""" |
166
|
|
|
Show the url of a page in the right language |
167
|
|
|
|
168
|
|
|
Example :: |
169
|
|
|
|
170
|
|
|
{% show_absolute_url page_object %} |
171
|
|
|
|
172
|
|
|
You can also use the slug of a page:: |
173
|
|
|
|
174
|
|
|
{% show_absolute_url "my-page-slug" %} |
175
|
|
|
|
176
|
|
|
Keyword arguments: |
177
|
|
|
:param page: the page object, slug or id |
178
|
|
|
:param lang: the wanted language \ |
179
|
|
|
(defaults to `settings.PAGE_DEFAULT_LANGUAGE`) |
180
|
|
|
""" |
181
|
|
|
if not lang: |
182
|
|
|
lang = context.get('lang', pages_settings.PAGE_DEFAULT_LANGUAGE) |
183
|
|
|
page = get_page_from_string_or_id(page, lang) |
184
|
|
|
if not page: |
185
|
|
|
return {'content': ''} |
186
|
|
|
url = page.get_url_path(language=lang) |
187
|
|
|
if url: |
188
|
|
|
return {'content': url} |
189
|
|
|
return {'content': ''} |
190
|
|
|
show_absolute_url = register.inclusion_tag('pages/content.html', |
191
|
|
|
takes_context=True)(show_absolute_url) |
192
|
|
|
|
193
|
|
|
|
194
|
|
|
def show_revisions(context, page, content_type, lang=None): |
195
|
|
|
"""Render the last 10 revisions of a page content with a list using |
196
|
|
|
the ``pages/revisions.html`` template""" |
197
|
|
|
if (not pages_settings.PAGE_CONTENT_REVISION or |
198
|
|
|
content_type in pages_settings.PAGE_CONTENT_REVISION_EXCLUDE_LIST): |
199
|
|
|
return {'revisions': None} |
200
|
|
|
revisions = Content.objects.filter(page=page, language=lang, |
201
|
|
|
type=content_type).order_by('-creation_date') |
202
|
|
|
if len(revisions) < 2: |
203
|
|
|
return {'revisions': None} |
204
|
|
|
return {'revisions': revisions[0:10]} |
205
|
|
|
show_revisions = register.inclusion_tag('pages/revisions.html', |
206
|
|
|
takes_context=True)(show_revisions) |
207
|
|
|
|
208
|
|
|
|
209
|
|
|
def pages_dynamic_tree_menu(context, page, url='/'): |
210
|
|
|
""" |
211
|
|
|
Render a "dynamic" tree menu, with all nodes expanded which are either |
212
|
|
|
ancestors or the current page itself. |
213
|
|
|
|
214
|
|
|
Override ``pages/dynamic_tree_menu.html`` if you want to change the |
215
|
|
|
design. |
216
|
|
|
|
217
|
|
|
:param page: the current page |
218
|
|
|
:param url: not used anymore |
219
|
|
|
""" |
220
|
|
|
lang = context.get('lang', pages_settings.PAGE_DEFAULT_LANGUAGE) |
221
|
|
|
page = get_page_from_string_or_id(page, lang) |
222
|
|
|
children = None |
223
|
|
|
if page and 'current_page' in context: |
224
|
|
|
current_page = context['current_page'] |
225
|
|
|
# if this node is expanded, we also have to render its children |
226
|
|
|
# a node is expanded if it is the current node or one of its ancestors |
227
|
|
|
if(page.tree_id == current_page.tree_id and |
228
|
|
|
page.lft <= current_page.lft and |
229
|
|
|
page.rght >= current_page.rght): |
230
|
|
|
children = page.get_children_for_frontend() |
231
|
|
|
context.update({'children': children, 'page': page}) |
232
|
|
|
return context |
233
|
|
|
pages_dynamic_tree_menu = register.inclusion_tag( |
234
|
|
|
'pages/dynamic_tree_menu.html', |
235
|
|
|
takes_context=True |
236
|
|
|
)(pages_dynamic_tree_menu) |
237
|
|
|
|
238
|
|
|
|
239
|
|
|
def pages_breadcrumb(context, page, url='/'): |
240
|
|
|
""" |
241
|
|
|
Render a breadcrumb like menu. |
242
|
|
|
|
243
|
|
|
Override ``pages/breadcrumb.html`` if you want to change the |
244
|
|
|
design. |
245
|
|
|
|
246
|
|
|
:param page: the current page |
247
|
|
|
:param url: not used anymore |
248
|
|
|
""" |
249
|
|
|
lang = context.get('lang', pages_settings.PAGE_DEFAULT_LANGUAGE) |
250
|
|
|
page = get_page_from_string_or_id(page, lang) |
251
|
|
|
pages_navigation = None |
252
|
|
|
if page: |
253
|
|
|
pages_navigation = page.get_ancestors() |
254
|
|
|
context.update({'pages_navigation': pages_navigation, 'page': page}) |
255
|
|
|
return context |
256
|
|
|
pages_breadcrumb = register.inclusion_tag( |
257
|
|
|
'pages/breadcrumb.html', |
258
|
|
|
takes_context=True |
259
|
|
|
)(pages_breadcrumb) |
260
|
|
|
|
261
|
|
|
|
262
|
|
|
"""Tags""" |
263
|
|
|
|
264
|
|
|
class GetPageNode(template.Node): |
265
|
|
|
"""get_page Node""" |
266
|
|
|
def __init__(self, page_filter, varname): |
267
|
|
|
self.page_filter = page_filter |
268
|
|
|
self.varname = varname |
269
|
|
|
|
270
|
|
|
def render(self, context): |
271
|
|
|
page_or_id = self.page_filter.resolve(context) |
272
|
|
|
page = get_page_from_string_or_id(page_or_id) |
273
|
|
|
context[self.varname] = page |
274
|
|
|
return '' |
275
|
|
|
|
276
|
|
|
|
277
|
|
|
def do_get_page(parser, token): |
278
|
|
|
"""Retrieve a page and insert into the template's context. |
279
|
|
|
|
280
|
|
|
Example:: |
281
|
|
|
|
282
|
|
|
{% get_page "news" as news_page %} |
283
|
|
|
|
284
|
|
|
:param page: the page object, slug or id |
285
|
|
|
:param name: name of the context variable to store the page in |
286
|
|
|
""" |
287
|
|
|
bits = token.split_contents() |
288
|
|
|
if 4 != len(bits): |
289
|
|
|
raise TemplateSyntaxError('%r expects 4 arguments' % bits[0]) |
290
|
|
|
if bits[-2] != 'as': |
291
|
|
|
raise TemplateSyntaxError( |
292
|
|
|
'%r expects "as" as the second argument' % bits[0]) |
293
|
|
|
page_filter = parser.compile_filter(bits[1]) |
294
|
|
|
varname = bits[-1] |
295
|
|
|
return GetPageNode(page_filter, varname) |
296
|
|
|
do_get_page = register.tag('get_page', do_get_page) |
297
|
|
|
|
298
|
|
|
|
299
|
|
|
class GetContentNode(template.Node): |
300
|
|
|
"""Get content node""" |
301
|
|
|
def __init__(self, page, content_type, varname, lang, lang_filter): |
302
|
|
|
self.page = page |
303
|
|
|
self.content_type = content_type |
304
|
|
|
self.varname = varname |
305
|
|
|
self.lang = lang |
306
|
|
|
self.lang_filter = lang_filter |
307
|
|
|
|
308
|
|
|
def render(self, context): |
309
|
|
|
if self.lang_filter: |
310
|
|
|
self.lang = self.lang_filter.resolve(context) |
311
|
|
|
context[self.varname] = _get_content( |
312
|
|
|
context, |
313
|
|
|
self.page.resolve(context), |
314
|
|
|
self.content_type.resolve(context), |
315
|
|
|
self.lang |
316
|
|
|
) |
317
|
|
|
return '' |
318
|
|
|
|
319
|
|
|
|
320
|
|
|
def do_get_content(parser, token): |
321
|
|
|
"""Retrieve a Content object and insert it into the template's context. |
322
|
|
|
|
323
|
|
|
Example:: |
324
|
|
|
|
325
|
|
|
{% get_content page_object "title" as content %} |
326
|
|
|
|
327
|
|
|
You can also use the slug of a page:: |
328
|
|
|
|
329
|
|
|
{% get_content "my-page-slug" "title" as content %} |
330
|
|
|
|
331
|
|
|
Syntax:: |
332
|
|
|
|
333
|
|
|
{% get_content page type [lang] as name %} |
334
|
|
|
|
335
|
|
|
:param page: the page object, slug or id |
336
|
|
|
:param type: content_type used by a placeholder |
337
|
|
|
:param name: name of the context variable to store the content in |
338
|
|
|
:param lang: the wanted language |
339
|
|
|
""" |
340
|
|
|
bits = token.split_contents() |
341
|
|
|
if not 5 <= len(bits) <= 6: |
342
|
|
|
raise TemplateSyntaxError('%r expects 4 or 5 arguments' % bits[0]) |
343
|
|
|
if bits[-2] != 'as': |
344
|
|
|
raise TemplateSyntaxError( |
345
|
|
|
'%r expects "as" as the second last argument' % bits[0]) |
346
|
|
|
page = parser.compile_filter(bits[1]) |
347
|
|
|
content_type = parser.compile_filter(bits[2]) |
348
|
|
|
varname = bits[-1] |
349
|
|
|
lang = None |
350
|
|
|
lang_filter = None |
351
|
|
|
if len(bits) == 6: |
352
|
|
|
lang = bits[3] |
353
|
|
|
else: |
354
|
|
|
lang_filter = parser.compile_filter("lang") |
355
|
|
|
return GetContentNode(page, content_type, varname, lang, lang_filter) |
356
|
|
|
do_get_content = register.tag('get_content', do_get_content) |
357
|
|
|
|
358
|
|
|
|
359
|
|
|
class LoadPagesNode(template.Node): |
360
|
|
|
"""Load page node.""" |
361
|
|
|
def render(self, context): |
362
|
|
|
if 'pages_navigation' not in context: |
363
|
|
|
pages = Page.objects.navigation().order_by("tree_id") |
364
|
|
|
context.update({'pages_navigation': pages}) |
365
|
|
|
if 'current_page' not in context: |
366
|
|
|
context.update({'current_page': None}) |
367
|
|
|
return '' |
368
|
|
|
|
369
|
|
|
|
370
|
|
|
def do_load_pages(parser, token): |
371
|
|
|
"""Load the navigation pages, lang, and current_page variables into the |
372
|
|
|
current context. |
373
|
|
|
|
374
|
|
|
Example:: |
375
|
|
|
|
376
|
|
|
<ul> |
377
|
|
|
{% load_pages %} |
378
|
|
|
{% for page in pages_navigation %} |
379
|
|
|
{% pages_menu page %} |
380
|
|
|
{% endfor %} |
381
|
|
|
</ul> |
382
|
|
|
""" |
383
|
|
|
return LoadPagesNode() |
384
|
|
|
do_load_pages = register.tag('load_pages', do_load_pages) |
385
|
|
|
|
386
|
|
|
|
387
|
|
|
def do_placeholder(parser, token): |
388
|
|
|
""" |
389
|
|
|
Method that parse the placeholder template tag. |
390
|
|
|
|
391
|
|
|
Syntax:: |
392
|
|
|
|
393
|
|
|
{% placeholder <name> [on <page>] [with <widget>] \ |
394
|
|
|
[parsed] [as <varname>] %} |
395
|
|
|
|
396
|
|
|
Example usage:: |
397
|
|
|
|
398
|
|
|
{% placeholder about %} |
399
|
|
|
{% placeholder body with TextArea as body_text %} |
400
|
|
|
{% placeholder welcome with TextArea parsed as welcome_text %} |
401
|
|
|
{% placeholder teaser on next_page with TextArea parsed %} |
402
|
|
|
""" |
403
|
|
|
name, params = parse_placeholder(parser, token) |
404
|
|
|
return PlaceholderNode(name, **params) |
405
|
|
|
register.tag('placeholder', do_placeholder) |
406
|
|
|
|
407
|
|
|
def do_markdownlaceholder(parser, token): |
408
|
|
|
""" |
409
|
|
|
Method that parse the markdownplaceholder template tag. |
410
|
|
|
""" |
411
|
|
|
name, params = parse_placeholder(parser, token) |
412
|
|
|
return MarkdownPlaceholderNode(name, **params) |
413
|
|
|
register.tag('markdownplaceholder', do_markdownlaceholder) |
414
|
|
|
|
415
|
|
|
def do_imageplaceholder(parser, token): |
416
|
|
|
""" |
417
|
|
|
Method that parse the imageplaceholder template tag. |
418
|
|
|
""" |
419
|
|
|
name, params = parse_placeholder(parser, token) |
420
|
|
|
return ImagePlaceholderNode(name, **params) |
421
|
|
|
register.tag('imageplaceholder', do_imageplaceholder) |
422
|
|
|
|
423
|
|
|
def do_fileplaceholder(parser, token): |
424
|
|
|
""" |
425
|
|
|
Method that parse the fileplaceholder template tag. |
426
|
|
|
""" |
427
|
|
|
name, params = parse_placeholder(parser, token) |
428
|
|
|
return FilePlaceholderNode(name, **params) |
429
|
|
|
register.tag('fileplaceholder', do_fileplaceholder) |
430
|
|
|
|
431
|
|
|
def do_contactplaceholder(parser, token): |
432
|
|
|
""" |
433
|
|
|
Method that parse the contactplaceholder template tag. |
434
|
|
|
""" |
435
|
|
|
name, params = parse_placeholder(parser, token) |
436
|
|
|
return ContactPlaceholderNode(name, **params) |
437
|
|
|
register.tag('contactplaceholder', do_contactplaceholder) |
438
|
|
|
|
439
|
|
|
|
440
|
|
|
def do_jsonplaceholder(parser, token): |
441
|
|
|
""" |
442
|
|
|
Method that parse the contactplaceholder template tag. |
443
|
|
|
""" |
444
|
|
|
name, params = parse_placeholder(parser, token) |
445
|
|
|
return JsonPlaceholderNode(name, **params) |
446
|
|
|
register.tag('jsonplaceholder', do_jsonplaceholder) |
447
|
|
|
|
448
|
|
|
|
449
|
|
|
def language_content_up_to_date(page, language): |
450
|
|
|
"""Tell if all the page content has been updated since the last |
451
|
|
|
change of the official version (settings.LANGUAGE_CODE) |
452
|
|
|
|
453
|
|
|
This is approximated by comparing the last modified date of any |
454
|
|
|
content in the page, not comparing each content block to its |
455
|
|
|
corresponding official language version. That allows users to |
456
|
|
|
easily make "do nothing" changes to any content block when no |
457
|
|
|
change is required for a language. |
458
|
|
|
""" |
459
|
|
|
lang_code = getattr(settings, 'LANGUAGE_CODE', None) |
460
|
|
|
if lang_code == language: |
461
|
|
|
# official version is always "up to date" |
462
|
|
|
return True |
463
|
|
|
# get the last modified date for the official version |
464
|
|
|
last_modified = Content.objects.filter(language=lang_code, |
465
|
|
|
page=page).order_by('-creation_date') |
466
|
|
|
if not last_modified: |
467
|
|
|
# no official version |
468
|
|
|
return True |
469
|
|
|
lang_modified = Content.objects.filter(language=language, |
470
|
|
|
page=page).order_by('-creation_date')[0].creation_date |
471
|
|
|
return lang_modified > last_modified[0].creation_date |
472
|
|
|
register.filter(language_content_up_to_date) |
473
|
|
|
|
474
|
|
|
|
475
|
|
|
@register.assignment_tag |
476
|
|
|
def get_pages_with_tag(tag): |
477
|
|
|
""" |
478
|
|
|
Return Pages with given tag |
479
|
|
|
|
480
|
|
|
Syntax:: |
481
|
|
|
|
482
|
|
|
{% get_pages_with_tag <tag name> as <varname> %} |
483
|
|
|
|
484
|
|
|
Example use: |
485
|
|
|
{% get_pages_with_tag "footer" as pages %} |
486
|
|
|
""" |
487
|
|
|
return Page.objects.filter(tags__name__in=[tag]) |
488
|
|
|
|
489
|
|
|
|
490
|
|
|
def do_page_has_content(parser, token): |
491
|
|
|
""" |
492
|
|
|
Conditional tag that only renders its nodes if the page |
493
|
|
|
has content for a particular content type. By default the |
494
|
|
|
current page is used. |
495
|
|
|
|
496
|
|
|
Syntax:: |
497
|
|
|
|
498
|
|
|
{% page_has_content <content_type> [<page var name>] %} |
499
|
|
|
... |
500
|
|
|
{%_end page_has_content %} |
501
|
|
|
|
502
|
|
|
Example use: |
503
|
|
|
{% page_has_content 'header-image' %} |
504
|
|
|
<img src="{{ MEDIA_URL }}{% imageplaceholder 'header-image' %}"> |
505
|
|
|
{% end_page_has_content %} |
506
|
|
|
""" |
507
|
|
|
nodelist = parser.parse(('end_page_has_content',)) |
508
|
|
|
parser.delete_first_token() |
509
|
|
|
args = token.split_contents() |
510
|
|
|
try: |
511
|
|
|
content_type = unescape_string_literal(args[1]) |
512
|
|
|
except IndexError: |
513
|
|
|
raise template.TemplateSyntaxError( |
514
|
|
|
"%r tag requires arguments content_type" % args[0] |
515
|
|
|
) |
516
|
|
|
if len(args) > 2: |
517
|
|
|
page = args[2] |
518
|
|
|
else: |
519
|
|
|
page = None |
520
|
|
|
return PageHasContentNode(page, content_type, nodelist) |
521
|
|
|
register.tag('page_has_content', do_page_has_content) |
522
|
|
|
|
523
|
|
|
class PageHasContentNode(template.Node): |
524
|
|
|
|
525
|
|
|
def __init__(self, page, content_type, nodelist): |
526
|
|
|
self.page = page or 'current_page' |
527
|
|
|
self.content_type = content_type |
528
|
|
|
self.nodelist = nodelist |
529
|
|
|
|
530
|
|
|
def render(self, context): |
531
|
|
|
page = context[self.page] |
532
|
|
|
content = page.get_content(context.get('lang', None), self.content_type) |
533
|
|
|
if(content): |
534
|
|
|
output = self.nodelist.render(context) |
535
|
|
|
return output |
536
|
|
|
return '' |
537
|
|
|
|
538
|
|
|
|