feature: only external links open in new tab

This commit is contained in:
Daniel Fichtinger 2025-07-11 14:15:03 -04:00
parent b8b8fef72c
commit 0ee8094cc9
3 changed files with 29 additions and 9 deletions

View file

@ -379,6 +379,8 @@ markdown:
enabled: true
theme: ashen
wrap: false
links:
external_new_tab: true
blog:
dir: blog
```
@ -391,6 +393,7 @@ blog:
| `markdown.syntax_highlighting.enabled` | Whether code should be highlighted. |
| `markdown.syntax_highlighting.theme` | [Pygments] style for highlighting. |
| `markdown.syntax_highlighting.wrap` | Whether the resulting code block should be word wrapped. |
| `markdown.links.external_new_tab` | Whether external links should be opened in a new tab. |
| `blog.dir` | Name of a directory relative to `content/` whose children are automatically considered posts. |
### Sitemap

View file

@ -37,6 +37,11 @@ class HighlightingConfig:
wrap: bool = False
@dataclass
class LinksConfig:
external_new_tab: bool = True
@dataclass
class MarkdownConfig:
image_labels: bool = True
@ -44,6 +49,7 @@ class MarkdownConfig:
syntax_highlighting: HighlightingConfig = field(
default_factory=HighlightingConfig
)
links: LinksConfig = field(default_factory=LinksConfig)
@dataclass

View file

@ -1,11 +1,10 @@
import xml.etree.ElementTree as etree
from collections.abc import Sequence
from logging import Logger
from pathlib import Path
from typing import Any, override
from l2m4m import LaTeX2MathMLExtension
# from l2m4m import LaTeX2MathMLExtension
from markdown import Markdown
from markdown.extensions.abbr import AbbrExtension
from markdown.extensions.attr_list import AttrListExtension
@ -34,8 +33,6 @@ from zona.log import get_logger
from zona.metadata import Metadata
from zona.models import Item
logger = get_logger()
class ZonaImageTreeprocessor(Treeprocessor):
"""Implement Zona's image caption rendering."""
@ -43,6 +40,7 @@ class ZonaImageTreeprocessor(Treeprocessor):
def __init__(self, md: Markdown):
super().__init__()
self.md: Markdown = md
self.logger: Logger = get_logger()
@override
def run(self, root: etree.Element):
@ -87,6 +85,7 @@ class ZonaLinkTreeprocessor(Treeprocessor):
):
super().__init__()
self.resolve: bool = resolve
self.logger: Logger = get_logger()
if self.resolve:
assert source is not None
assert layout is not None
@ -103,9 +102,15 @@ class ZonaLinkTreeprocessor(Treeprocessor):
if not href:
continue
if self.resolve:
assert self.config
cur = Path(href)
_href = href
if href.startswith("/"):
same_file = False
resolved = Path()
# href starting with anchor reference the current file
if href.startswith("#"):
same_file = True
elif href.startswith("/"):
# resolve relative to content root
resolved = (
self.layout.content / cur.relative_to("/")
@ -114,18 +119,24 @@ class ZonaLinkTreeprocessor(Treeprocessor):
# treat as relative link and try to resolve
resolved = (self.source.parent / cur).resolve()
# only substitute if link points to an actual file
if resolved.exists():
# that isn't the self file
if not same_file and resolved.exists():
item = self.item_map.get(resolved)
if item:
href = util.normalize_url(item.url)
element.set("href", href)
logger.debug(
self.logger.debug(
f"Link in file {self.source}: {_href} resolved to {href}"
)
else:
logger.debug(
self.logger.debug(
f"Warning: resolved path {resolved} not found in item map"
)
# open link in new tab if not self-link
elif (
self.config.markdown.links.external_new_tab
and not same_file
):
element.set("target", "_blank")