Skip to content

Commit 84cb91b

Browse files
committed
Fixed incorrect URLs when rendering paginated views
1 parent 7bdd03a commit 84cb91b

File tree

2 files changed

+72
-56
lines changed

2 files changed

+72
-56
lines changed

material/plugins/blog/plugin.py

+36-28
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ def on_nav(self, nav, *, config, files):
223223
if self.config.pagination:
224224
for view in self._resolve_views(self.blog):
225225
for at in range(1, len(view.pages)):
226-
self._attach_at(view.pages[at - 1], view, view.pages[at])
226+
self._attach_at(view.parent, view, view.pages[at])
227227

228228
# Replace source file system path
229229
view.pages[at].file.src_uri = view.file.src_uri
@@ -245,19 +245,18 @@ def on_page_markdown(self, markdown, *, page, config, files):
245245
return
246246

247247
# We set the contents of the view to its title if pagination should
248-
# not keep the content of the original view on paginaged views
248+
# not keep the content of the original view on paginated views
249249
if not self.config.pagination_keep_content:
250250
view = self._resolve_original(page)
251251
if view in self._resolve_views(self.blog):
252-
assert isinstance(page, View)
253-
if page.pages.index(page):
254-
main = page.parent
255-
256-
# We need to use the rendered title of the original view
257-
# if the author set the title in the page's contents, or
258-
# it would be overridden with the one set in mkdocs.yml,
259-
# which would result in inconsistent headings
260-
name = main._title_from_render or main.title
252+
253+
# If the current view is paginated, use the rendered title
254+
# of the original view in case the author set the title in
255+
# the page's contents, or it would be overridden with the
256+
# one set in mkdocs.yml, leading to inconsistent headings
257+
assert isinstance(view, View)
258+
if view != page:
259+
name = view._title_from_render or view.title
261260
return f"# {name}"
262261

263262
# Nothing more to be done for views
@@ -340,23 +339,12 @@ def on_page_context(self, context, *, page, config, nav):
340339
if view not in self._resolve_views(self.blog):
341340
return
342341

343-
# Retrieve parent view or section
344-
assert isinstance(page, View)
345-
main = page.parent
346-
347-
# If this page is a view, and the parent page is a view as well, we got
348-
# a paginated view and need to replace the parent with the current view.
349-
# Paginated views are always rendered at the end of the build, which is
350-
# why we can safely mutate the navigation at this point
351-
if isinstance(main, View):
352-
page.parent = main.parent
353-
354-
# Replace view in navigation and rewire it - the current view in the
355-
# navigation becomes the main view, thus the entire chain moves one
356-
# level up. It's essential that the rendering order is linear, or
357-
# else we might end up with a broken navigation.
358-
items = self._resolve_siblings(main, nav)
359-
items[items.index(main)] = page
342+
# If the current view is paginated, replace and rewire it - the current
343+
# view temporarily becomes the main view, and is reset after rendering
344+
assert isinstance(view, View)
345+
if view != page:
346+
items = self._resolve_siblings(view, nav)
347+
items[items.index(view)] = page
360348

361349
# Render excerpts and prepare pagination
362350
posts, pagination = self._render(page)
@@ -373,6 +361,26 @@ def pager(args: object):
373361
context["posts"] = posts
374362
context["pagination"] = pager if pagination else None
375363

364+
# After rendering a paginated view, replace the URL of the paginated view
365+
# with the URL of the original view - since we need to replace the original
366+
# view with a paginated view in `on_page_context` for correct resolution of
367+
# the active state, we must fix the paginated view URLs after rendering
368+
def on_post_page(self, output, *, page, config):
369+
if not self.config.enabled:
370+
return
371+
372+
# Skip if page is not a view managed by this instance - this plugin has
373+
# support for multiple instances, which is why this check is necessary
374+
view = self._resolve_original(page)
375+
if view not in self._resolve_views(self.blog):
376+
return
377+
378+
# If the current view is paginated, replace the URL of the paginated
379+
# view with the URL of the original view - see https://t.ly/Yeh-P
380+
assert isinstance(view, View)
381+
if view != page:
382+
page.file.url = view.file.url
383+
376384
# Remove temporary directory on shutdown
377385
def on_shutdown(self):
378386
rmtree(self.temp_dir)

src/plugins/blog/plugin.py

+36-28
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ def on_nav(self, nav, *, config, files):
223223
if self.config.pagination:
224224
for view in self._resolve_views(self.blog):
225225
for at in range(1, len(view.pages)):
226-
self._attach_at(view.pages[at - 1], view, view.pages[at])
226+
self._attach_at(view.parent, view, view.pages[at])
227227

228228
# Replace source file system path
229229
view.pages[at].file.src_uri = view.file.src_uri
@@ -245,19 +245,18 @@ def on_page_markdown(self, markdown, *, page, config, files):
245245
return
246246

247247
# We set the contents of the view to its title if pagination should
248-
# not keep the content of the original view on paginaged views
248+
# not keep the content of the original view on paginated views
249249
if not self.config.pagination_keep_content:
250250
view = self._resolve_original(page)
251251
if view in self._resolve_views(self.blog):
252-
assert isinstance(page, View)
253-
if page.pages.index(page):
254-
main = page.parent
255-
256-
# We need to use the rendered title of the original view
257-
# if the author set the title in the page's contents, or
258-
# it would be overridden with the one set in mkdocs.yml,
259-
# which would result in inconsistent headings
260-
name = main._title_from_render or main.title
252+
253+
# If the current view is paginated, use the rendered title
254+
# of the original view in case the author set the title in
255+
# the page's contents, or it would be overridden with the
256+
# one set in mkdocs.yml, leading to inconsistent headings
257+
assert isinstance(view, View)
258+
if view != page:
259+
name = view._title_from_render or view.title
261260
return f"# {name}"
262261

263262
# Nothing more to be done for views
@@ -340,23 +339,12 @@ def on_page_context(self, context, *, page, config, nav):
340339
if view not in self._resolve_views(self.blog):
341340
return
342341

343-
# Retrieve parent view or section
344-
assert isinstance(page, View)
345-
main = page.parent
346-
347-
# If this page is a view, and the parent page is a view as well, we got
348-
# a paginated view and need to replace the parent with the current view.
349-
# Paginated views are always rendered at the end of the build, which is
350-
# why we can safely mutate the navigation at this point
351-
if isinstance(main, View):
352-
page.parent = main.parent
353-
354-
# Replace view in navigation and rewire it - the current view in the
355-
# navigation becomes the main view, thus the entire chain moves one
356-
# level up. It's essential that the rendering order is linear, or
357-
# else we might end up with a broken navigation.
358-
items = self._resolve_siblings(main, nav)
359-
items[items.index(main)] = page
342+
# If the current view is paginated, replace and rewire it - the current
343+
# view temporarily becomes the main view, and is reset after rendering
344+
assert isinstance(view, View)
345+
if view != page:
346+
items = self._resolve_siblings(view, nav)
347+
items[items.index(view)] = page
360348

361349
# Render excerpts and prepare pagination
362350
posts, pagination = self._render(page)
@@ -373,6 +361,26 @@ def pager(args: object):
373361
context["posts"] = posts
374362
context["pagination"] = pager if pagination else None
375363

364+
# After rendering a paginated view, replace the URL of the paginated view
365+
# with the URL of the original view - since we need to replace the original
366+
# view with a paginated view in `on_page_context` for correct resolution of
367+
# the active state, we must fix the paginated view URLs after rendering
368+
def on_post_page(self, output, *, page, config):
369+
if not self.config.enabled:
370+
return
371+
372+
# Skip if page is not a view managed by this instance - this plugin has
373+
# support for multiple instances, which is why this check is necessary
374+
view = self._resolve_original(page)
375+
if view not in self._resolve_views(self.blog):
376+
return
377+
378+
# If the current view is paginated, replace the URL of the paginated
379+
# view with the URL of the original view - see https://t.ly/Yeh-P
380+
assert isinstance(view, View)
381+
if view != page:
382+
page.file.url = view.file.url
383+
376384
# Remove temporary directory on shutdown
377385
def on_shutdown(self):
378386
rmtree(self.temp_dir)

0 commit comments

Comments
 (0)