Fixed incorrect URLs when rendering paginated views

This commit is contained in:
squidfunk 2023-09-03 12:48:46 +02:00
parent 7bdd03a794
commit 84cb91b21b
No known key found for this signature in database
GPG Key ID: 5ED40BC4F9C436DF
2 changed files with 70 additions and 54 deletions

View File

@ -223,7 +223,7 @@ class BlogPlugin(BasePlugin[BlogConfig]):
if self.config.pagination: if self.config.pagination:
for view in self._resolve_views(self.blog): for view in self._resolve_views(self.blog):
for at in range(1, len(view.pages)): for at in range(1, len(view.pages)):
self._attach_at(view.pages[at - 1], view, view.pages[at]) self._attach_at(view.parent, view, view.pages[at])
# Replace source file system path # Replace source file system path
view.pages[at].file.src_uri = view.file.src_uri view.pages[at].file.src_uri = view.file.src_uri
@ -245,19 +245,18 @@ class BlogPlugin(BasePlugin[BlogConfig]):
return return
# We set the contents of the view to its title if pagination should # We set the contents of the view to its title if pagination should
# not keep the content of the original view on paginaged views # not keep the content of the original view on paginated views
if not self.config.pagination_keep_content: if not self.config.pagination_keep_content:
view = self._resolve_original(page) view = self._resolve_original(page)
if view in self._resolve_views(self.blog): if view in self._resolve_views(self.blog):
assert isinstance(page, View)
if page.pages.index(page):
main = page.parent
# We need to use the rendered title of the original view # If the current view is paginated, use the rendered title
# if the author set the title in the page's contents, or # of the original view in case the author set the title in
# it would be overridden with the one set in mkdocs.yml, # the page's contents, or it would be overridden with the
# which would result in inconsistent headings # one set in mkdocs.yml, leading to inconsistent headings
name = main._title_from_render or main.title assert isinstance(view, View)
if view != page:
name = view._title_from_render or view.title
return f"# {name}" return f"# {name}"
# Nothing more to be done for views # Nothing more to be done for views
@ -340,23 +339,12 @@ class BlogPlugin(BasePlugin[BlogConfig]):
if view not in self._resolve_views(self.blog): if view not in self._resolve_views(self.blog):
return return
# Retrieve parent view or section # If the current view is paginated, replace and rewire it - the current
assert isinstance(page, View) # view temporarily becomes the main view, and is reset after rendering
main = page.parent assert isinstance(view, View)
if view != page:
# If this page is a view, and the parent page is a view as well, we got items = self._resolve_siblings(view, nav)
# a paginated view and need to replace the parent with the current view. items[items.index(view)] = page
# Paginated views are always rendered at the end of the build, which is
# why we can safely mutate the navigation at this point
if isinstance(main, View):
page.parent = main.parent
# Replace view in navigation and rewire it - the current view in the
# navigation becomes the main view, thus the entire chain moves one
# level up. It's essential that the rendering order is linear, or
# else we might end up with a broken navigation.
items = self._resolve_siblings(main, nav)
items[items.index(main)] = page
# Render excerpts and prepare pagination # Render excerpts and prepare pagination
posts, pagination = self._render(page) posts, pagination = self._render(page)
@ -373,6 +361,26 @@ class BlogPlugin(BasePlugin[BlogConfig]):
context["posts"] = posts context["posts"] = posts
context["pagination"] = pager if pagination else None context["pagination"] = pager if pagination else None
# After rendering a paginated view, replace the URL of the paginated view
# with the URL of the original view - since we need to replace the original
# view with a paginated view in `on_page_context` for correct resolution of
# the active state, we must fix the paginated view URLs after rendering
def on_post_page(self, output, *, page, config):
if not self.config.enabled:
return
# Skip if page is not a view managed by this instance - this plugin has
# support for multiple instances, which is why this check is necessary
view = self._resolve_original(page)
if view not in self._resolve_views(self.blog):
return
# If the current view is paginated, replace the URL of the paginated
# view with the URL of the original view - see https://t.ly/Yeh-P
assert isinstance(view, View)
if view != page:
page.file.url = view.file.url
# Remove temporary directory on shutdown # Remove temporary directory on shutdown
def on_shutdown(self): def on_shutdown(self):
rmtree(self.temp_dir) rmtree(self.temp_dir)

View File

@ -223,7 +223,7 @@ class BlogPlugin(BasePlugin[BlogConfig]):
if self.config.pagination: if self.config.pagination:
for view in self._resolve_views(self.blog): for view in self._resolve_views(self.blog):
for at in range(1, len(view.pages)): for at in range(1, len(view.pages)):
self._attach_at(view.pages[at - 1], view, view.pages[at]) self._attach_at(view.parent, view, view.pages[at])
# Replace source file system path # Replace source file system path
view.pages[at].file.src_uri = view.file.src_uri view.pages[at].file.src_uri = view.file.src_uri
@ -245,19 +245,18 @@ class BlogPlugin(BasePlugin[BlogConfig]):
return return
# We set the contents of the view to its title if pagination should # We set the contents of the view to its title if pagination should
# not keep the content of the original view on paginaged views # not keep the content of the original view on paginated views
if not self.config.pagination_keep_content: if not self.config.pagination_keep_content:
view = self._resolve_original(page) view = self._resolve_original(page)
if view in self._resolve_views(self.blog): if view in self._resolve_views(self.blog):
assert isinstance(page, View)
if page.pages.index(page):
main = page.parent
# We need to use the rendered title of the original view # If the current view is paginated, use the rendered title
# if the author set the title in the page's contents, or # of the original view in case the author set the title in
# it would be overridden with the one set in mkdocs.yml, # the page's contents, or it would be overridden with the
# which would result in inconsistent headings # one set in mkdocs.yml, leading to inconsistent headings
name = main._title_from_render or main.title assert isinstance(view, View)
if view != page:
name = view._title_from_render or view.title
return f"# {name}" return f"# {name}"
# Nothing more to be done for views # Nothing more to be done for views
@ -340,23 +339,12 @@ class BlogPlugin(BasePlugin[BlogConfig]):
if view not in self._resolve_views(self.blog): if view not in self._resolve_views(self.blog):
return return
# Retrieve parent view or section # If the current view is paginated, replace and rewire it - the current
assert isinstance(page, View) # view temporarily becomes the main view, and is reset after rendering
main = page.parent assert isinstance(view, View)
if view != page:
# If this page is a view, and the parent page is a view as well, we got items = self._resolve_siblings(view, nav)
# a paginated view and need to replace the parent with the current view. items[items.index(view)] = page
# Paginated views are always rendered at the end of the build, which is
# why we can safely mutate the navigation at this point
if isinstance(main, View):
page.parent = main.parent
# Replace view in navigation and rewire it - the current view in the
# navigation becomes the main view, thus the entire chain moves one
# level up. It's essential that the rendering order is linear, or
# else we might end up with a broken navigation.
items = self._resolve_siblings(main, nav)
items[items.index(main)] = page
# Render excerpts and prepare pagination # Render excerpts and prepare pagination
posts, pagination = self._render(page) posts, pagination = self._render(page)
@ -373,6 +361,26 @@ class BlogPlugin(BasePlugin[BlogConfig]):
context["posts"] = posts context["posts"] = posts
context["pagination"] = pager if pagination else None context["pagination"] = pager if pagination else None
# After rendering a paginated view, replace the URL of the paginated view
# with the URL of the original view - since we need to replace the original
# view with a paginated view in `on_page_context` for correct resolution of
# the active state, we must fix the paginated view URLs after rendering
def on_post_page(self, output, *, page, config):
if not self.config.enabled:
return
# Skip if page is not a view managed by this instance - this plugin has
# support for multiple instances, which is why this check is necessary
view = self._resolve_original(page)
if view not in self._resolve_views(self.blog):
return
# If the current view is paginated, replace the URL of the paginated
# view with the URL of the original view - see https://t.ly/Yeh-P
assert isinstance(view, View)
if view != page:
page.file.url = view.file.url
# Remove temporary directory on shutdown # Remove temporary directory on shutdown
def on_shutdown(self): def on_shutdown(self):
rmtree(self.temp_dir) rmtree(self.temp_dir)