Add anchor links to headers
This commit is contained in:
parent
1c7917cb86
commit
03e9da57a1
4 changed files with 33 additions and 5 deletions
|
@ -1,6 +1,16 @@
|
|||
section.content {
|
||||
font-size: 1.25rem;
|
||||
padding-top: 0.5rem;
|
||||
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
.heading-anchor {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-details {
|
||||
|
|
|
@ -10,7 +10,7 @@ from wagtail.images import get_image_model_string
|
|||
from wagtail.models import Page
|
||||
|
||||
from .streamfield import get_blocks, get_html, get_word_count, truncate_streamfield
|
||||
from .utils import TocEntry, get_table_of_contents
|
||||
from .utils import TocEntry, add_heading_anchors, get_table_of_contents
|
||||
|
||||
|
||||
class BasePage(Page):
|
||||
|
@ -68,6 +68,10 @@ class BaseContentMixin(models.Model):
|
|||
def summary(self) -> str:
|
||||
return truncate_streamfield(self.body, 50)
|
||||
|
||||
@cached_property
|
||||
def body_html(self):
|
||||
return add_heading_anchors(str(self.body))
|
||||
|
||||
|
||||
class ContentPage(BasePage, BaseContentMixin): # type: ignore[misc]
|
||||
subpage_types: list[Any] = []
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{% extends "wagtail_base.html" %}
|
||||
|
||||
{% load wagtailcore_tags static %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% include "common/hero.html" %}
|
||||
|
||||
<section class="container content">
|
||||
{% include_block page.body %}
|
||||
{{ page.body_html|safe }}
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -5,9 +5,12 @@ from typing import Type
|
|||
from bs4 import BeautifulSoup
|
||||
from django.conf import settings
|
||||
from django.http.request import HttpRequest
|
||||
from django.utils.text import slugify
|
||||
from wagtail.models import Page
|
||||
from wagtail.models import get_page_models as get_wagtail_page_models
|
||||
|
||||
HEADER_TAGS = ["h2", "h3", "h4", "h5", "h6"]
|
||||
|
||||
|
||||
@dataclass
|
||||
class TocEntry:
|
||||
|
@ -20,10 +23,10 @@ class TocEntry:
|
|||
def get_table_of_contents(html: str) -> list[TocEntry]:
|
||||
soup = BeautifulSoup(html, "lxml")
|
||||
|
||||
headings = soup.find_all(["h2", "h3", "h4", "h5", "h6"])
|
||||
headings = soup.find_all(HEADER_TAGS)
|
||||
|
||||
heading_levels = [
|
||||
TocEntry(tag.text, tag.text, int(tag.name[1]), []) for tag in headings
|
||||
TocEntry(tag.text, slugify(tag.text), int(tag.name[1]), []) for tag in headings
|
||||
]
|
||||
|
||||
# Abort if there are no headings
|
||||
|
@ -53,6 +56,17 @@ def get_table_of_contents(html: str) -> list[TocEntry]:
|
|||
return root.children
|
||||
|
||||
|
||||
def add_heading_anchors(html: str) -> str:
|
||||
soup = BeautifulSoup(html, "lxml")
|
||||
for tag in soup.find_all(HEADER_TAGS):
|
||||
slug = slugify(tag.text)
|
||||
anchor = soup.new_tag("a", href="#" + slug, id=slug)
|
||||
anchor.string = "#"
|
||||
anchor.attrs["class"] = "heading-anchor"
|
||||
tag.insert(0, anchor)
|
||||
return str(soup)
|
||||
|
||||
|
||||
def get_page_models() -> list[Type[Page]]:
|
||||
page_models = get_wagtail_page_models().copy()
|
||||
page_models.remove(Page)
|
||||
|
|
Loading…
Reference in a new issue