1
0
Fork 0
forked from github/pelican

Merge branch 'pagination-zebuline'

This commit is contained in:
Alexis Metaireau 2011-02-17 19:04:30 +00:00
commit e9515130e0
13 changed files with 248 additions and 51 deletions

View file

@ -78,7 +78,7 @@ class Pelican(object):
return generators
def get_writer(self):
return Writer(self.output_path)
return Writer(self.output_path, settings=self.settings)

View file

@ -16,6 +16,7 @@ from pelican.readers import read_file
_TEMPLATES = ('index', 'tag', 'tags', 'article', 'category', 'categories',
'archives', 'page')
_DIRECT_TEMPLATES = ('index', 'tags', 'categories', 'archives')
_PAGINATED_DIRECT_TEMPLATES = ('index', )
class Generator(object):
@ -35,7 +36,8 @@ class Generator(object):
templates ready to use with Jinja2.
"""
path = os.path.expanduser(os.path.join(self.theme, 'templates'))
env = Environment(loader=FileSystemLoader(path),extensions=self.settings.get('JINJA_EXTENSIONS', []))
env = Environment(loader=FileSystemLoader(path),
extensions=self.settings.get('JINJA_EXTENSIONS', []))
templates = {}
for template in _TEMPLATES:
try:
@ -134,25 +136,34 @@ class ArticlesGenerator(Generator):
writer.write_file,
relative_urls = self.settings.get('RELATIVE_URLS')
)
# to minimize the number of relative path stuff modification in writer, articles pass first
# to minimize the number of relative path stuff modification
# in writer, articles pass first
for article in chain(self.translations, self.articles):
write('%s' % article.save_as,
templates['article'], self.context, article=article,
category=article.category)
for template in _DIRECT_TEMPLATES:
paginated = {}
if template in _PAGINATED_DIRECT_TEMPLATES:
paginated = {'articles': self.articles, 'dates': self.dates}
write('%s.html' % template, templates[template], self.context,
blog=True)
blog=True, paginated=paginated, page_name=template)
# and subfolders after that
for tag, articles in self.tags.items():
for article in articles:
write('tag/%s.html' % tag, templates['tag'], self.context,
tag=tag, articles=articles)
dates = [article for article in self.dates if article in articles]
write('tag/%s.html' % tag, templates['tag'], self.context,
tag=tag, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates},
page_name='tag/%s'%tag)
for cat, articles in self.categories:
dates = [article for article in self.dates if article in articles]
write('category/%s.html' % cat, templates['category'], self.context,
category=cat, articles=articles)
category=cat, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates},
page_name='category/%s' % cat)
def generate_context(self):
"""change the context"""
@ -281,7 +292,8 @@ class PdfGenerator(Generator):
pass
def generate_output(self, writer=None):
# we don't use the writer passed as argument here, since we write our own files
# we don't use the writer passed as argument here
# since we write our own files
print u' Generating PDF files...'
pdf_path = os.path.join(self.output_path, 'pdf')
try:

85
pelican/paginator.py Normal file
View file

@ -0,0 +1,85 @@
# From django.core.paginator
from math import ceil
class Paginator(object):
def __init__(self, object_list, per_page, orphans=0):
self.object_list = object_list
self.per_page = per_page
self.orphans = orphans
self._num_pages = self._count = None
def page(self, number):
"Returns a Page object for the given 1-based page number."
bottom = (number - 1) * self.per_page
top = bottom + self.per_page
if top + self.orphans >= self.count:
top = self.count
return Page(self.object_list[bottom:top], number, self)
def _get_count(self):
"Returns the total number of objects, across all pages."
if self._count is None:
self._count = len(self.object_list)
return self._count
count = property(_get_count)
def _get_num_pages(self):
"Returns the total number of pages."
if self._num_pages is None:
hits = max(1, self.count - self.orphans)
self._num_pages = int(ceil(hits / float(self.per_page)))
return self._num_pages
num_pages = property(_get_num_pages)
def _get_page_range(self):
"""
Returns a 1-based range of pages for iterating through within
a template for loop.
"""
return range(1, self.num_pages + 1)
page_range = property(_get_page_range)
class Page(object):
def __init__(self, object_list, number, paginator):
self.object_list = object_list
self.number = number
self.paginator = paginator
def __repr__(self):
return '<Page %s of %s>' % (self.number, self.paginator.num_pages)
def has_next(self):
return self.number < self.paginator.num_pages
def has_previous(self):
return self.number > 1
def has_other_pages(self):
return self.has_previous() or self.has_next()
def next_page_number(self):
return self.number + 1
def previous_page_number(self):
return self.number - 1
def start_index(self):
"""
Returns the 1-based index of the first object on this page,
relative to total objects in the paginator.
"""
# Special case, return zero if no items.
if self.paginator.count == 0:
return 0
return (self.paginator.per_page * (self.number - 1)) + 1
def end_index(self):
"""
Returns the 1-based index of the last object on this page,
relative to total objects found (hits).
"""
# Special case for the last page because there can be orphans.
if self.number == self.paginator.num_pages:
return self.paginator.count
return self.number * self.paginator.per_page

View file

@ -30,6 +30,9 @@ _DEFAULT_CONFIG = {'PATH': None,
'DATE_FORMATS': {},
'JINJA_EXTENSIONS': [],
'LOCALE': '', # default to user locale
'WITH_PAGINATION': True,
'DEFAULT_PAGINATION': 5,
'DEFAULT_ORPHANS': 0,
}
def read_settings(filename):

View file

@ -2,24 +2,32 @@
{% block content_title %}{% endblock %}
{% block content %}
{% if articles %}
{% for article in articles %}
{% if loop.index == 1 %}
<aside id="featured" class="body"><article>
<h1 class="entry-title"><a href="{{ SITEURL }}/{{ article.url
}}">{{ article.title }}</a></h1>
{% include 'article_infos.html' %}
{{ article.content }}
{% include 'comments.html' %}
{% for article in articles_page.object_list %}
{# First item #}
{% if loop.first and not articles_page.has_previous() %}
<aside id="featured" class="body">
<article>
<h1 class="entry-title"><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></h1>
{% include 'article_infos.html' %}{{ article.content }}{% include 'comments.html' %}
</article>
</aside><!-- /#featured -->
{% if loop.length > 1 %}
<section id="content" class="body">
<h1>Other articles</h1>
<hr />
<ol id="posts-list" class="hfeed">
{% endif %}
{% else %}
<li><article class="hentry">
{% if loop.length == 1 %}
{% include 'pagination.html' %}
{% endif %}
</aside><!-- /#featured -->
{% if loop.length > 1 %}
<section id="content" class="body">
<h1>Other articles</h1>
<hr />
<ol id="posts-list" class="hfeed">
{% endif %}
{# other items #}
{% else %}
{% if loop.first and articles_page.has_previous %}
<section id="content" class="body">
<ol id="posts-list" class="hfeed" start="{{ articles_paginator.per_page -1 }}">
{% endif %}
<li><article class="hentry">
<header>
<h1><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h1>
</header>
@ -30,11 +38,17 @@
<a class="readmore" href="{{ SITEURL }}/{{ article.url }}">read more</a>
{% include 'comments.html' %}
</div><!-- /.entry-content -->
</article></li>
{% endif %}
</article></li>
{% endif %}
{% if loop.last and (articles_page.has_previous()
or not articles_page.has_previous() and loop.length > 1) %}
{% include 'pagination.html' %}
{% endif %}
{% endfor %}
</ol><!-- /#posts-list -->
</section><!-- /#content -->
{% if loop.length > 1 or articles_page.has_previous() %}
</ol><!-- /#posts-list -->
</section><!-- /#content -->
{% endif %}
{% else %}
<section id="content" class="body">
<h2>Pages</h2>

View file

@ -0,0 +1,13 @@
<p class="paginator">
{% if articles_page.has_previous() %}
{% if articles_page.previous_page_number() == 1 %}
<a href="{{ SITEURL }}/{{ page_name }}.html">&laquo;</a>
{% else %}
<a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.previous_page_number() }}.html">&laquo;</a>
{% endif %}
{% endif %}
Page {{ articles_page.number }} / {{ articles_paginator.num_pages }}
{% if articles_page.has_next() %}
<a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.next_page_number() }}.html">&raquo;</a>
{% endif %}
</p>

View file

@ -11,7 +11,7 @@
</header><!-- /#banner -->
{% if categories %}<ul>
{% for category, articles in categories %}
<li><a href="category/{{category}}.html">{{ category }}</a></li>
<li><a href="{{ SITEURL }}/category/{{category}}.html">{{ category }}</a></li>
{% endfor %}
</ul> {% endif %}
{% block content %}

View file

@ -6,7 +6,7 @@
{% endblock %}
<ol id="post-list">
{% for article in articles %}
{% for article in articles_page.object_list %}
<li><article class="hentry">
<header> <h2 class="entry-title"><a href="{{ article.url }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h2> </header>
<footer class="post-info">
@ -17,5 +17,18 @@
</article></li>
{% endfor %}
</ol><!-- /#posts-list -->
<p class="paginator">
{% if articles_page.has_previous() %}
{% if articles_page.previous_page_number() == 1 %}
<a href="{{ SITEURL }}/{{ page_name }}.html">&laquo;</a>
{% else %}
<a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.previous_page_number() }}.html">&laquo;</a>
{% endif %}
{% endif %}
Page {{ articles_page.number }} / {{ articles_paginator.num_pages }}
{% if articles_page.has_next() %}
<a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.next_page_number() }}.html">&raquo;</a>
{% endif %}
</p>
</section><!-- /#content -->
{% endblock content %}

View file

@ -7,13 +7,15 @@ import locale
from feedgenerator import Atom1Feed, Rss201rev2Feed
from pelican.utils import get_relative_path
from pelican.paginator import Paginator
class Writer(object):
def __init__(self, output_path):
def __init__(self, output_path, settings=None):
self.output_path = output_path
self.reminder = dict()
self.settings = settings or {}
def _create_new_feed(self, feed_type, context):
feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed
@ -74,15 +76,30 @@ class Writer(object):
locale.setlocale(locale.LC_ALL, old_locale)
def write_file(self, name, template, context, relative_urls=True,
**kwargs):
paginated=None, **kwargs):
"""Render the template and write the file.
:param name: name of the file to output
:param template: template to use to generate the content
:param context: dict to pass to the templates.
:param relative_urls: use relative urls or absolutes ones
:param paginated: dict of article list to paginate - must have the
same length (same list in different orders)
:param **kwargs: additional variables to pass to the templates
"""
def _write_file(template, localcontext, output_path, name):
"""Render the template write the file."""
output = template.render(localcontext)
filename = os.sep.join((output_path, name))
try:
os.makedirs(os.path.dirname(filename))
except Exception:
pass
with open(filename, 'w', encoding='utf-8') as f:
f.write(output)
print u' [ok] writing %s' % filename
localcontext = context.copy()
if relative_urls:
localcontext['SITEURL'] = get_relative_path(name)
@ -90,22 +107,43 @@ class Writer(object):
localcontext.update(kwargs)
self.update_context_contents(name, localcontext)
output = template.render(localcontext)
filename = os.sep.join((self.output_path, name))
try:
os.makedirs(os.path.dirname(filename))
except Exception:
pass
with open(filename, 'w', encoding='utf-8') as f:
f.write(output)
print u' [ok] writing %s' % filename
# check paginated
paginated = paginated or {}
if self.settings.get('WITH_PAGINATION') and paginated:
# pagination needed, init paginators
paginators = {}
for key in paginated.iterkeys():
object_list = paginated[key]
paginators[key] = Paginator(object_list,
self.settings.get('DEFAULT_PAGINATION'),
self.settings.get('DEFAULT_ORPHANS'))
# generated pages, and write
for page_num in range(paginators.values()[0].num_pages):
paginated_localcontext = localcontext.copy()
paginated_name = name
for key in paginators.iterkeys():
paginator = paginators[key]
page = paginator.page(page_num+1)
paginated_localcontext.update({'%s_paginator' % key: paginator,
'%s_page' % key: page})
if page_num > 0:
ext = '.' + paginated_name.rsplit('.')[-1]
paginated_name = paginated_name.replace(ext,
'%s%s' % (page_num + 1, ext))
_write_file(template, paginated_localcontext, self.output_path,
paginated_name)
else:
# no pagination
_write_file(template, localcontext, self.output_path, name)
def update_context_contents(self, name, context):
"""Recursively run the context to find elements (articles, pages, etc) whose content getter needs to
be modified in order to deal with relative paths.
"""Recursively run the context to find elements (articles, pages, etc)
whose content getter needs to
be modified in order to deal with relative paths.
:param name: name of the file to output.
:param context: dict that will be passed to the templates.
:param name: name of the file to output.
:param context: dict that will be passed to the templates.
"""
if context is None:
return None
@ -139,13 +177,13 @@ class Writer(object):
return context
def inject_update_method(self, name, item):
"""Replace the content attribute getter of an element by a function that will deals with its
relatives paths.
"""Replace the content attribute getter of an element by a function
that will deals with its relatives paths.
"""
def _update_object_content(name, input):
"""Change all the relatives paths of the input content to relatives paths
suitable fot the ouput content
"""Change all the relatives paths of the input content to relatives
paths suitable fot the ouput content
:param name: path of the output.
:param input: input resource that will be passed to the templates.

View file

@ -0,0 +1,6 @@
Article 1
#########
:date: 2011-02-17
Article 1

View file

@ -0,0 +1,6 @@
Article 2
#########
:date: 2011-02-17
Article 2

View file

@ -0,0 +1,6 @@
Article 3
#########
:date: 2011-02-17
Article 3

View file

@ -8,6 +8,7 @@ DISQUS_SITENAME = "blog-notmyidea"
PDF_GENERATOR = False
REVERSE_CATEGORY_ORDER = True
LOCALE = 'fr_FR.utf8'
DEFAULT_PAGINATION = 2
FEED_RSS = 'feeds/all.rss.xml'
CATEGORY_FEED_RSS = 'feeds/%s.rss.xml'