changeset 352:498a917cd2d4

pagination: Make pagination use routes to generate proper URLs. This fixes incorrect URLs when using custom sub-page suffixes, for instance. Add tests.
author Ludovic Chabant <ludovic@chabant.com>
date Fri, 17 Apr 2015 16:09:30 -0700
parents 1f22d4b10fef
children 8140ff806258
files piecrust/data/builder.py piecrust/data/paginator.py piecrust/templating/jinjaengine.py tests/bakes/test_pagination.bake tests/test_data_paginator.py
diffstat 5 files changed, 85 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/piecrust/data/builder.py	Fri Apr 17 16:08:23 2015 -0700
+++ b/piecrust/data/builder.py	Fri Apr 17 16:09:30 2015 -0700
@@ -34,7 +34,7 @@
 
     pc_data = PieCrustData()
     pgn_source = ctx.pagination_source or get_default_pagination_source(page)
-    paginator = Paginator(page, pgn_source, first_uri, ctx.page_num,
+    paginator = Paginator(page, pgn_source, ctx.page_num,
                           ctx.pagination_filter)
     assetor = Assetor(page, first_uri)
     linker = PageLinkerData(page.source, page.rel_path)
--- a/piecrust/data/paginator.py	Fri Apr 17 16:08:23 2015 -0700
+++ b/piecrust/data/paginator.py	Fri Apr 17 16:09:30 2015 -0700
@@ -10,23 +10,25 @@
 
 
 class Paginator(object):
-    debug_render = ['has_more', 'items', 'has_items', 'items_per_page',
-                    'items_this_page', 'prev_page_number', 'this_page_number',
-                    'next_page_number', 'prev_page', 'next_page',
-                    'total_item_count', 'total_page_count',
-                    'next_item', 'prev_item']
-    debug_render_invoke = ['has_more', 'items', 'has_items', 'items_per_page',
-                    'items_this_page', 'prev_page_number', 'this_page_number',
-                    'next_page_number', 'prev_page', 'next_page',
-                    'total_item_count', 'total_page_count',
-                    'next_item', 'prev_item']
+    debug_render = [
+            'has_more', 'items', 'has_items', 'items_per_page',
+            'items_this_page', 'prev_page_number', 'this_page_number',
+            'next_page_number', 'prev_page', 'next_page',
+            'total_item_count', 'total_page_count',
+            'next_item', 'prev_item']
+    debug_render_invoke = [
+            'has_more', 'items', 'has_items', 'items_per_page',
+            'items_this_page', 'prev_page_number', 'this_page_number',
+            'next_page_number', 'prev_page', 'next_page',
+            'total_item_count', 'total_page_count',
+            'next_item', 'prev_item']
 
-    def __init__(self, page, source, uri, page_num=1, pgn_filter=None,
-            items_per_page=-1):
+    def __init__(self, page, source, page_num=1, pgn_filter=None,
+                 items_per_page=-1):
         self._parent_page = page
         self._source = source
-        self._uri = uri
         self._page_num = page_num
+        self._route = None
         self._iterator = None
         self._pgn_filter = pgn_filter
         self._items_per_page = items_per_page
@@ -185,11 +187,13 @@
             return
 
         if self._source is None:
-            raise Exception("Can't load pagination data: no source has been defined.")
+            raise Exception("Can't load pagination data: no source has "
+                            "been defined.")
 
         pag_filter = self._getPaginationFilter()
         offset = (self._page_num - 1) * self.items_per_page
-        self._iterator = PageIterator(self._source,
+        self._iterator = PageIterator(
+                self._source,
                 current_page=self._parent_page,
                 pagination_filter=pag_filter,
                 offset=offset, limit=self.items_per_page,
@@ -210,12 +214,17 @@
         return f
 
     def _getPageUri(self, index):
-        uri = self._uri
-        if index > 1:
-            if len(uri) > 0 and not uri.endswith('/'):
-                uri += '/'
-            uri += str(index)
-        return uri
+        if self._route is None:
+            app = self._source.app
+            self._route = app.getRoute(self._parent_page.source.name,
+                                       self._parent_page.source_metadata)
+            if self._route is None:
+                raise Exception("Can't get route for page: %s" %
+                                self._parent_page.path)
+
+        return self._route.getUri(self._parent_page.source_metadata,
+                                  provider=self._parent_page,
+                                  sub_num=index)
 
     def _onIteration(self):
         if self._parent_page is not None and not self._pgn_set_on_ctx:
--- a/piecrust/templating/jinjaengine.py	Fri Apr 17 16:08:23 2015 -0700
+++ b/piecrust/templating/jinjaengine.py	Fri Apr 17 16:09:30 2015 -0700
@@ -179,9 +179,9 @@
             raise Exception("Can't paginate when no page has been pushed "
                             "on the execution stack.")
         first_uri, _ = split_sub_uri(self.app, cpi.render_ctx.uri)
-        return Paginator(cpi.page, value, first_uri,
-                page_num=cpi.render_ctx.page_num,
-                items_per_page=items_per_page)
+        return Paginator(cpi.page, value,
+                         page_num=cpi.render_ctx.page_num,
+                         items_per_page=items_per_page)
 
     def _formatWith(self, value, format_name):
         return format_text(self.app, format_name, value)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/bakes/test_pagination.bake	Fri Apr 17 16:09:30 2015 -0700
@@ -0,0 +1,41 @@
+---
+config:
+    site:
+        posts_per_page: 3
+        pagination_suffix: /page%num%
+in:
+    posts/2015-03-01_post01.md: "---\ntitle: Post 01\n---\n"
+    posts/2015-03-02_post02.md: "---\ntitle: Post 02\n---\n"
+    posts/2015-03-03_post03.md: "---\ntitle: Post 03\n---\n"
+    posts/2015-03-04_post04.md: "---\ntitle: Post 04\n---\n"
+    posts/2015-03-05_post05.md: "---\ntitle: Post 05\n---\n"
+    posts/2015-03-06_post06.md: "---\ntitle: Post 06\n---\n"
+    posts/2015-03-07_post07.md: "---\ntitle: Post 07\n---\n"
+    pages/_index.md: ''
+    pages/foo.md: |
+        {%- for p in pagination.items -%}
+        {{p.url}} {{p.title}}
+        {% endfor -%}
+        {{pagination.prev_page}}
+        {{pagination.this_page}}
+        {{pagination.next_page}}
+outfiles:
+    foo.html: |
+        /2015/03/07/post07.html Post 07
+        /2015/03/06/post06.html Post 06
+        /2015/03/05/post05.html Post 05
+        None
+        /foo.html
+        /foo/page2.html
+    foo/page2.html: |
+        /2015/03/04/post04.html Post 04
+        /2015/03/03/post03.html Post 03
+        /2015/03/02/post02.html Post 02
+        /foo.html
+        /foo/page2.html
+        /foo/page3.html
+    foo/page3.html: |
+        /2015/03/01/post01.html Post 01
+        /foo/page2.html
+        /foo/page3.html
+        None
--- a/tests/test_data_paginator.py	Fri Apr 17 16:08:23 2015 -0700
+++ b/tests/test_data_paginator.py	Fri Apr 17 16:09:30 2015 -0700
@@ -44,8 +44,17 @@
         ('blog', 3, 14)
     ])
 def test_paginator(uri, page_num, count):
+    def _mock_get_uri(index):
+        res = uri
+        if index > 1:
+            if res != '' and not res.endswith('/'):
+                res += '/'
+            res += '%d' % index
+        return res
+
     source = MockSource(count)
-    p = Paginator(None, source, uri, page_num)
+    p = Paginator(None, source, page_num)
+    p._getPageUri = _mock_get_uri
 
     if count <= 5:
         # All posts fit on the page