feature: only external links open in new tab
This commit is contained in:
parent
b8b8fef72c
commit
0ee8094cc9
3 changed files with 29 additions and 9 deletions
|
@ -379,6 +379,8 @@ markdown:
|
||||||
enabled: true
|
enabled: true
|
||||||
theme: ashen
|
theme: ashen
|
||||||
wrap: false
|
wrap: false
|
||||||
|
links:
|
||||||
|
external_new_tab: true
|
||||||
blog:
|
blog:
|
||||||
dir: blog
|
dir: blog
|
||||||
```
|
```
|
||||||
|
@ -391,6 +393,7 @@ blog:
|
||||||
| `markdown.syntax_highlighting.enabled` | Whether code should be highlighted. |
|
| `markdown.syntax_highlighting.enabled` | Whether code should be highlighted. |
|
||||||
| `markdown.syntax_highlighting.theme` | [Pygments] style for highlighting. |
|
| `markdown.syntax_highlighting.theme` | [Pygments] style for highlighting. |
|
||||||
| `markdown.syntax_highlighting.wrap` | Whether the resulting code block should be word wrapped. |
|
| `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. |
|
| `blog.dir` | Name of a directory relative to `content/` whose children are automatically considered posts. |
|
||||||
|
|
||||||
### Sitemap
|
### Sitemap
|
||||||
|
|
|
@ -37,6 +37,11 @@ class HighlightingConfig:
|
||||||
wrap: bool = False
|
wrap: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LinksConfig:
|
||||||
|
external_new_tab: bool = True
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MarkdownConfig:
|
class MarkdownConfig:
|
||||||
image_labels: bool = True
|
image_labels: bool = True
|
||||||
|
@ -44,6 +49,7 @@ class MarkdownConfig:
|
||||||
syntax_highlighting: HighlightingConfig = field(
|
syntax_highlighting: HighlightingConfig = field(
|
||||||
default_factory=HighlightingConfig
|
default_factory=HighlightingConfig
|
||||||
)
|
)
|
||||||
|
links: LinksConfig = field(default_factory=LinksConfig)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import xml.etree.ElementTree as etree
|
import xml.etree.ElementTree as etree
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, override
|
from typing import Any, override
|
||||||
|
|
||||||
from l2m4m import LaTeX2MathMLExtension
|
from l2m4m import LaTeX2MathMLExtension
|
||||||
|
|
||||||
# from l2m4m import LaTeX2MathMLExtension
|
|
||||||
from markdown import Markdown
|
from markdown import Markdown
|
||||||
from markdown.extensions.abbr import AbbrExtension
|
from markdown.extensions.abbr import AbbrExtension
|
||||||
from markdown.extensions.attr_list import AttrListExtension
|
from markdown.extensions.attr_list import AttrListExtension
|
||||||
|
@ -34,8 +33,6 @@ from zona.log import get_logger
|
||||||
from zona.metadata import Metadata
|
from zona.metadata import Metadata
|
||||||
from zona.models import Item
|
from zona.models import Item
|
||||||
|
|
||||||
logger = get_logger()
|
|
||||||
|
|
||||||
|
|
||||||
class ZonaImageTreeprocessor(Treeprocessor):
|
class ZonaImageTreeprocessor(Treeprocessor):
|
||||||
"""Implement Zona's image caption rendering."""
|
"""Implement Zona's image caption rendering."""
|
||||||
|
@ -43,6 +40,7 @@ class ZonaImageTreeprocessor(Treeprocessor):
|
||||||
def __init__(self, md: Markdown):
|
def __init__(self, md: Markdown):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.md: Markdown = md
|
self.md: Markdown = md
|
||||||
|
self.logger: Logger = get_logger()
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def run(self, root: etree.Element):
|
def run(self, root: etree.Element):
|
||||||
|
@ -87,6 +85,7 @@ class ZonaLinkTreeprocessor(Treeprocessor):
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.resolve: bool = resolve
|
self.resolve: bool = resolve
|
||||||
|
self.logger: Logger = get_logger()
|
||||||
if self.resolve:
|
if self.resolve:
|
||||||
assert source is not None
|
assert source is not None
|
||||||
assert layout is not None
|
assert layout is not None
|
||||||
|
@ -103,9 +102,15 @@ class ZonaLinkTreeprocessor(Treeprocessor):
|
||||||
if not href:
|
if not href:
|
||||||
continue
|
continue
|
||||||
if self.resolve:
|
if self.resolve:
|
||||||
|
assert self.config
|
||||||
cur = Path(href)
|
cur = Path(href)
|
||||||
_href = 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
|
# resolve relative to content root
|
||||||
resolved = (
|
resolved = (
|
||||||
self.layout.content / cur.relative_to("/")
|
self.layout.content / cur.relative_to("/")
|
||||||
|
@ -114,18 +119,24 @@ class ZonaLinkTreeprocessor(Treeprocessor):
|
||||||
# treat as relative link and try to resolve
|
# treat as relative link and try to resolve
|
||||||
resolved = (self.source.parent / cur).resolve()
|
resolved = (self.source.parent / cur).resolve()
|
||||||
# only substitute if link points to an actual file
|
# 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)
|
item = self.item_map.get(resolved)
|
||||||
if item:
|
if item:
|
||||||
href = util.normalize_url(item.url)
|
href = util.normalize_url(item.url)
|
||||||
element.set("href", href)
|
element.set("href", href)
|
||||||
logger.debug(
|
self.logger.debug(
|
||||||
f"Link in file {self.source}: {_href} resolved to {href}"
|
f"Link in file {self.source}: {_href} resolved to {href}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.debug(
|
self.logger.debug(
|
||||||
f"Warning: resolved path {resolved} not found in item map"
|
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")
|
element.set("target", "_blank")
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue