From b8c04c42dffb94fb8dad3bda29c171b71136dd7e Mon Sep 17 00:00:00 2001 From: daveoconnor Date: Thu, 9 Jan 2025 10:07:03 -0800 Subject: [PATCH] Documentation anchor links fixes (#1585) --- core/htmlhelper.py | 11 +++++++++++ core/views.py | 3 ++- templates/docsiframe.html | 23 +++++++++++++++++------ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/core/htmlhelper.py b/core/htmlhelper.py index 3fb7e756..d01bed3c 100644 --- a/core/htmlhelper.py +++ b/core/htmlhelper.py @@ -176,6 +176,8 @@ def modernize_legacy_page( for tag in result.find_all(tag_name, tag_attrs): tag.attrs.pop("class") + result = convert_name_to_id(result) + # Use the base HTML to later extract the and (part of) the placeholder = BeautifulSoup(base_html, "html.parser") if isinstance(head_selector, str): @@ -280,6 +282,15 @@ def convert_h1_to_h2(soup): return soup +def convert_name_to_id(soup): + """Convert all (deprecated) name attributes to id attributes.""" + for tag in soup.find_all(attrs={"name": True}): + tag["id"] = tag["name"] + del tag["name"] + + return soup + + def format_nested_lists(soup): """Flattens nested lists""" try: diff --git a/core/views.py b/core/views.py index a4d9ede5..37127685 100644 --- a/core/views.py +++ b/core/views.py @@ -34,7 +34,7 @@ get_s3_client, ) from .constants import SourceDocType -from .htmlhelper import modernize_legacy_page +from .htmlhelper import modernize_legacy_page, convert_name_to_id from .markdown import process_md from .models import RenderedContent from .tasks import ( @@ -472,6 +472,7 @@ def process_content(self, content): if source_content_type == SourceDocType.ASCIIDOC: extracted_content = content.decode(chardet.detect(content)["encoding"]) soup = BeautifulSoup(extracted_content, "html.parser") + soup = convert_name_to_id(soup) soup.find("head").append( soup.new_tag("script", src=f"{STATIC_URL}js/theme_handling.js") ) diff --git a/templates/docsiframe.html b/templates/docsiframe.html index f3876146..c3e3305d 100644 --- a/templates/docsiframe.html +++ b/templates/docsiframe.html @@ -12,23 +12,34 @@ {#resizeIframe(iframe);#} addClickInterception(iframeDoc); addBase(iframeDoc); + if (window.location.hash) { + scrollToAnchor(iframeDoc, window.location.hash.slice(1)); + } } function resizeIframe(obj) { obj.style.height = obj.contentWindow.document.documentElement.scrollHeight + 'px'; } - function addClickInterception(iframeDoc) { - let anchorLinks = iframeDoc.querySelectorAll('a[href^="#"]'); + function scrollToAnchor(iframeDoc, hash) { + const targetElement = iframeDoc.getElementById(hash); + if (targetElement) { + targetElement.scrollIntoView({behavior: 'smooth'}); + } + } + function addClickInterception(iframeDoc) { + let anchorLinks = iframeDoc.querySelectorAll('a[href*="#"]'); anchorLinks.forEach(function (anchor) { anchor.addEventListener('click', function (event) { + const href = this.getAttribute('href'); + const hrefSplit = href.split('#'); event.preventDefault(); - let targetId = this.getAttribute('href').substring(1); - let targetElement = iframeDoc.getElementById(targetId); - if (targetElement) { - targetElement.scrollIntoView({behavior: 'smooth'}); + {# here we account for anchors on different pages #} + if (!window.location.href.endsWith(hrefSplit[0])) { + window.location.href = href; } + scrollToAnchor(iframeDoc, hrefSplit[1]); }); }); }