mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Merge pull request #404 from tbunnyman/PerPageTemplates#376
Add per page/article templates. Closes #376
This commit is contained in:
commit
d726e5e81c
8 changed files with 128 additions and 15 deletions
11
docs/faq.rst
11
docs/faq.rst
|
|
@ -49,3 +49,14 @@ install it. You can do so by typing::
|
||||||
In case you don't have pip installed, consider installing it via::
|
In case you don't have pip installed, consider installing it via::
|
||||||
|
|
||||||
$ (sudo) easy_install pip
|
$ (sudo) easy_install pip
|
||||||
|
|
||||||
|
How do I assign custom templates on a per page basis?
|
||||||
|
=====================================================
|
||||||
|
|
||||||
|
It's as simple as adding an extra line of metadata to any pages or articles you
|
||||||
|
want to have it's own template.
|
||||||
|
|
||||||
|
:template: template_name
|
||||||
|
|
||||||
|
Then just make sure to have the template installed in to your theme as
|
||||||
|
``template_name.html``.
|
||||||
|
|
@ -21,6 +21,7 @@ class Page(object):
|
||||||
:param content: the string to parse, containing the original content.
|
:param content: the string to parse, containing the original content.
|
||||||
"""
|
"""
|
||||||
mandatory_properties = ('title',)
|
mandatory_properties = ('title',)
|
||||||
|
default_template = 'page'
|
||||||
|
|
||||||
def __init__(self, content, metadata=None, settings=None,
|
def __init__(self, content, metadata=None, settings=None,
|
||||||
filename=None):
|
filename=None):
|
||||||
|
|
@ -44,6 +45,9 @@ class Page(object):
|
||||||
# also keep track of the metadata attributes available
|
# also keep track of the metadata attributes available
|
||||||
self.metadata = local_metadata
|
self.metadata = local_metadata
|
||||||
|
|
||||||
|
#default template if it's not defined in page
|
||||||
|
self.template = self._get_template()
|
||||||
|
|
||||||
# default author to the one in settings if not defined
|
# default author to the one in settings if not defined
|
||||||
if not hasattr(self, 'author'):
|
if not hasattr(self, 'author'):
|
||||||
if 'AUTHOR' in settings:
|
if 'AUTHOR' in settings:
|
||||||
|
|
@ -153,9 +157,16 @@ class Page(object):
|
||||||
url = property(functools.partial(get_url_setting, key='url'))
|
url = property(functools.partial(get_url_setting, key='url'))
|
||||||
save_as = property(functools.partial(get_url_setting, key='save_as'))
|
save_as = property(functools.partial(get_url_setting, key='save_as'))
|
||||||
|
|
||||||
|
def _get_template(self):
|
||||||
|
if hasattr(self, 'template') and self.template is not None:
|
||||||
|
return self.template
|
||||||
|
else:
|
||||||
|
return self.default_template
|
||||||
|
|
||||||
|
|
||||||
class Article(Page):
|
class Article(Page):
|
||||||
mandatory_properties = ('title', 'date', 'category')
|
mandatory_properties = ('title', 'date', 'category')
|
||||||
|
default_template = 'article'
|
||||||
|
|
||||||
|
|
||||||
class Quote(Page):
|
class Quote(Page):
|
||||||
|
|
|
||||||
|
|
@ -167,11 +167,9 @@ class ArticlesGenerator(Generator):
|
||||||
|
|
||||||
def generate_articles(self, write):
|
def generate_articles(self, write):
|
||||||
"""Generate the articles."""
|
"""Generate the articles."""
|
||||||
article_template = self.get_template('article')
|
|
||||||
for article in chain(self.translations, self.articles):
|
for article in chain(self.translations, self.articles):
|
||||||
write(article.save_as,
|
write(article.save_as, self.get_template(article.template),
|
||||||
article_template, self.context, article=article,
|
self.context, article=article, category=article.category)
|
||||||
category=article.category)
|
|
||||||
|
|
||||||
def generate_direct_templates(self, write):
|
def generate_direct_templates(self, write):
|
||||||
"""Generate direct templates pages"""
|
"""Generate direct templates pages"""
|
||||||
|
|
@ -222,10 +220,10 @@ class ArticlesGenerator(Generator):
|
||||||
|
|
||||||
def generate_drafts(self, write):
|
def generate_drafts(self, write):
|
||||||
"""Generate drafts pages."""
|
"""Generate drafts pages."""
|
||||||
article_template = self.get_template('article')
|
|
||||||
for article in self.drafts:
|
for article in self.drafts:
|
||||||
write('drafts/%s.html' % article.slug, article_template,
|
write('drafts/%s.html' % article.slug,
|
||||||
self.context, article=article, category=article.category)
|
self.get_template(article.template), self.context,
|
||||||
|
article=article, category=article.category)
|
||||||
|
|
||||||
def generate_pages(self, writer):
|
def generate_pages(self, writer):
|
||||||
"""Generate the pages on the disk"""
|
"""Generate the pages on the disk"""
|
||||||
|
|
@ -385,7 +383,6 @@ class PagesGenerator(Generator):
|
||||||
(repr(unicode.encode(page.status, 'utf-8')),
|
(repr(unicode.encode(page.status, 'utf-8')),
|
||||||
repr(f)))
|
repr(f)))
|
||||||
|
|
||||||
|
|
||||||
self.pages, self.translations = process_translations(all_pages)
|
self.pages, self.translations = process_translations(all_pages)
|
||||||
self.hidden_pages, self.hidden_translations = process_translations(hidden_pages)
|
self.hidden_pages, self.hidden_translations = process_translations(hidden_pages)
|
||||||
|
|
||||||
|
|
@ -395,7 +392,7 @@ class PagesGenerator(Generator):
|
||||||
def generate_output(self, writer):
|
def generate_output(self, writer):
|
||||||
for page in chain(self.translations, self.pages,
|
for page in chain(self.translations, self.pages,
|
||||||
self.hidden_translations, self.hidden_pages):
|
self.hidden_translations, self.hidden_pages):
|
||||||
writer.write_file(page.save_as, self.get_template('page'),
|
writer.write_file(page.save_as, self.get_template(page.template),
|
||||||
self.context, page=page,
|
self.context, page=page,
|
||||||
relative_urls=self.settings.get('RELATIVE_URLS'))
|
relative_urls=self.settings.get('RELATIVE_URLS'))
|
||||||
|
|
||||||
|
|
|
||||||
11
tests/TestPages/hidden_page_with_template.rst
Normal file
11
tests/TestPages/hidden_page_with_template.rst
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
This is a test hidden page with a custom template
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
:status: hidden
|
||||||
|
:template: custom
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
|
|
||||||
|
This page is hidden
|
||||||
|
|
||||||
|
This page has a custom template to be called when rendered
|
||||||
8
tests/TestPages/page_with_template.rst
Normal file
8
tests/TestPages/page_with_template.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
This is a test page with a preset template
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
:template: custom
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
|
|
||||||
|
This article has a custom template to be called when rendered
|
||||||
8
tests/content/article_with_template.rst
Normal file
8
tests/content/article_with_template.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
Article with template
|
||||||
|
#####################
|
||||||
|
|
||||||
|
:template: custom
|
||||||
|
|
||||||
|
This article has a custom template to be called when rendered
|
||||||
|
|
||||||
|
This is some content. With some stuff to "typogrify".
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from .support import unittest
|
from .support import unittest
|
||||||
|
|
||||||
from pelican.contents import Page
|
from pelican.contents import Page, Article
|
||||||
from pelican.settings import _DEFAULT_CONFIG
|
from pelican.settings import _DEFAULT_CONFIG
|
||||||
from pelican.utils import truncate_html_words
|
from pelican.utils import truncate_html_words
|
||||||
|
|
||||||
|
|
@ -135,6 +135,17 @@ class TestPage(unittest.TestCase):
|
||||||
# will simply skip this test.
|
# will simply skip this test.
|
||||||
unittest.skip("There is no locale %s in this system." % locale)
|
unittest.skip("There is no locale %s in this system." % locale)
|
||||||
|
|
||||||
|
def test_template(self):
|
||||||
|
"""
|
||||||
|
Pages default to page, metadata overwrites
|
||||||
|
"""
|
||||||
|
default_page = Page(**self.page_kwargs)
|
||||||
|
self.assertEqual('page', default_page.template)
|
||||||
|
page_kwargs = self._copy_page_kwargs()
|
||||||
|
page_kwargs['metadata']['template'] = 'custom'
|
||||||
|
custom_page = Page(**page_kwargs)
|
||||||
|
self.assertEqual('custom', custom_page.template)
|
||||||
|
|
||||||
def _copy_page_kwargs(self):
|
def _copy_page_kwargs(self):
|
||||||
# make a deep copy of page_kwargs
|
# make a deep copy of page_kwargs
|
||||||
page_kwargs = dict([(key, self.page_kwargs[key]) for key in
|
page_kwargs = dict([(key, self.page_kwargs[key]) for key in
|
||||||
|
|
@ -146,3 +157,15 @@ class TestPage(unittest.TestCase):
|
||||||
for subkey in page_kwargs[key]])
|
for subkey in page_kwargs[key]])
|
||||||
|
|
||||||
return page_kwargs
|
return page_kwargs
|
||||||
|
|
||||||
|
class TestArticle(TestPage):
|
||||||
|
def test_template(self):
|
||||||
|
"""
|
||||||
|
Articles default to article, metadata overwrites
|
||||||
|
"""
|
||||||
|
default_article = Article(**self.page_kwargs)
|
||||||
|
self.assertEqual('article', default_article.template)
|
||||||
|
article_kwargs = self._copy_page_kwargs()
|
||||||
|
article_kwargs['metadata']['template'] = 'custom'
|
||||||
|
custom_article = Article(**article_kwargs)
|
||||||
|
self.assertEqual('custom', custom_article.template)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,37 @@ CUR_DIR = os.path.dirname(__file__)
|
||||||
|
|
||||||
class TestArticlesGenerator(unittest.TestCase):
|
class TestArticlesGenerator(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestArticlesGenerator, self).setUp()
|
||||||
|
self.generator = None
|
||||||
|
|
||||||
|
def get_populated_generator(self):
|
||||||
|
"""
|
||||||
|
We only need to pull all the test articles once, but read from it
|
||||||
|
for each test.
|
||||||
|
"""
|
||||||
|
if self.generator is None:
|
||||||
|
settings = _DEFAULT_CONFIG.copy()
|
||||||
|
settings['ARTICLE_DIR'] = 'content'
|
||||||
|
settings['DEFAULT_CATEGORY'] = 'Default'
|
||||||
|
self.generator = ArticlesGenerator(settings.copy(), settings,
|
||||||
|
CUR_DIR, _DEFAULT_CONFIG['THEME'], None,
|
||||||
|
_DEFAULT_CONFIG['MARKUP'])
|
||||||
|
self.generator.generate_context()
|
||||||
|
return self.generator
|
||||||
|
|
||||||
|
def distill_articles(self, articles):
|
||||||
|
distilled = []
|
||||||
|
for page in articles:
|
||||||
|
distilled.append([
|
||||||
|
page.title,
|
||||||
|
page.status,
|
||||||
|
page.category.name,
|
||||||
|
page.template
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return distilled
|
||||||
|
|
||||||
def test_generate_feeds(self):
|
def test_generate_feeds(self):
|
||||||
|
|
||||||
generator = ArticlesGenerator(None, {'FEED': _DEFAULT_CONFIG['FEED']},
|
generator = ArticlesGenerator(None, {'FEED': _DEFAULT_CONFIG['FEED']},
|
||||||
|
|
@ -93,6 +124,16 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
generator.generate_direct_templates(write)
|
generator.generate_direct_templates(write)
|
||||||
write.assert_called_count == 0
|
write.assert_called_count == 0
|
||||||
|
|
||||||
|
def test_per_article_template(self):
|
||||||
|
"""
|
||||||
|
Custom template articles get the field but standard/unset are None
|
||||||
|
"""
|
||||||
|
generator = self.get_populated_generator()
|
||||||
|
articles = self.distill_articles(generator.articles)
|
||||||
|
custom_template = ['Article with template', 'published', 'Default', 'custom']
|
||||||
|
standard_template = ['This is a super article !', 'published', 'Yeah', 'article']
|
||||||
|
self.assertIn(custom_template, articles)
|
||||||
|
self.assertIn(standard_template, articles)
|
||||||
|
|
||||||
class TestPageGenerator(unittest.TestCase):
|
class TestPageGenerator(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
@ -107,7 +148,8 @@ class TestPageGenerator(unittest.TestCase):
|
||||||
for page in pages:
|
for page in pages:
|
||||||
distilled.append([
|
distilled.append([
|
||||||
page.title,
|
page.title,
|
||||||
page.status
|
page.status,
|
||||||
|
page.template
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return distilled
|
return distilled
|
||||||
|
|
@ -124,12 +166,14 @@ class TestPageGenerator(unittest.TestCase):
|
||||||
hidden_pages = self.distill_pages(generator.hidden_pages)
|
hidden_pages = self.distill_pages(generator.hidden_pages)
|
||||||
|
|
||||||
pages_expected = [
|
pages_expected = [
|
||||||
[u'This is a test page', 'published'],
|
[u'This is a test page', 'published', 'page'],
|
||||||
[u'This is a markdown test page', 'published']
|
[u'This is a markdown test page', 'published', 'page'],
|
||||||
|
[u'This is a test page with a preset template', 'published', 'custom']
|
||||||
]
|
]
|
||||||
hidden_pages_expected = [
|
hidden_pages_expected = [
|
||||||
[u'This is a test hidden page', 'hidden'],
|
[u'This is a test hidden page', 'hidden', 'page'],
|
||||||
[u'This is a markdown test hidden page', 'hidden']
|
[u'This is a markdown test hidden page', 'hidden', 'page'],
|
||||||
|
[u'This is a test hidden page with a custom template', 'hidden', 'custom']
|
||||||
]
|
]
|
||||||
|
|
||||||
self.assertItemsEqual(pages_expected,pages)
|
self.assertItemsEqual(pages_expected,pages)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue