added options to have external links or non-Markdown files open in a new tab

This commit is contained in:
Amy G. Bowersox 2024-08-14 23:35:38 -06:00
parent 4a6f14c32b
commit f26ea7c507
4 changed files with 42 additions and 10 deletions

View File

@ -5,6 +5,10 @@
prefix = "/"
# If true, generate relative URLs for all internal URLs. Default is false.
relative = false
# IF true, external links (full URLs) will be opened in a new tab.
extern-new-tab = false
# If true, "foreign" (non-Markdown) files will be opened in a new tab.
foreign-new-tab = false
[classnames]
# CSS class to use for an invalid reference.

View File

@ -98,6 +98,18 @@ class Context:
metadata_section = self.config.get("metadata", {})
return metadata_section.get("description-title", False)
@property
def extern_in_new_tab(self) -> bool:
"""Returns ``True`` if external links (full URLs) will e opened in a new tab, ``False`` if not."""
links_section = self.config.get("links", {})
return links_section.get("extern-new-tab", False)
@property
def foreign_in_new_tab(self) -> bool:
"""Returns ``True`` if non-Markdown local files will be opened in a new tab, ``False`` if not."""
links_section = self.config.get("links", {})
return links_section.get("foreign-new-tab", False)
@property
def relative_links(self) -> bool:
"""

View File

@ -401,7 +401,12 @@ class ObsidianLinks(Extension):
"""Returns the classname for invalid references."""
return self._context.get_classname('invalid-reference')
def _parse_reference(self, contents: str) -> tuple[str | None, str]:
@property
def extern_link_target(self) -> str:
"""Returns the target attribute for external links, ot ``None`` if there is none."""
return '_blank' if self._context.extern_in_new_tab else None
def _parse_reference(self, contents: str) -> tuple[str | None, str, str | None]:
"""
Parse a reference and break it into link target and title.
@ -411,6 +416,7 @@ class ObsidianLinks(Extension):
Returns:
str: The link target, or ``None`` if the link is invalid.
str: The link title to be used.
str: The target attribute for the resulting anchor, or ``None`` if not specified.
"""
contents = contents.replace(r'\|','|') # handle case where we're inside tables
text = None
@ -435,8 +441,11 @@ class ObsidianLinks(Extension):
self._context.current_node if self._context.relative_links else None)
if hashloc:
link = f"{link}#hdr-{hashloc}"
return link, text
return None, text
target_window = None
if not node.is_md and self._context.foreign_in_new_tab:
target_window = '_blank'
return link, text, target_window
return None, text, None
class ObsidianLinksProc(InlineProcessor):
"""Processor that handles Obsidian links, [[page]]."""
@ -467,7 +476,7 @@ class ObsidianLinks(Extension):
int: The index of the first character in ``data`` that was *not* consumed by the pattern, or ``None``
if the match was rejected.
"""
link, text = self._extref._parse_reference(m.group(1))
link, text, target = self._extref._parse_reference(m.group(1))
if link is None:
el = etree.Element('span')
el.set('class', self._extref.invalid_reference_classname)
@ -476,6 +485,8 @@ class ObsidianLinks(Extension):
el = etree.Element('a')
el.set('href', link)
el.set('class', self._extref.obsidian_link_classname)
if target:
el.set('target', target)
el.text = text
return el, m.start(0), m.end(0)
@ -515,9 +526,12 @@ class ObsidianLinks(Extension):
if is_proper_url(link):
el = etree.Element('a')
el.set('href', link)
target = self._extref.extern_link_target
if target:
el.set('target', target)
el.text = text
else:
newlink, _ = self._extref._parse_reference(sanitize_reference(link))
newlink, _, target = self._extref._parse_reference(sanitize_reference(link))
if newlink is None:
el = etree.Element('span')
el.set('class', self._extref.invalid_reference_classname)
@ -526,6 +540,8 @@ class ObsidianLinks(Extension):
el = etree.Element('a')
el.set('href', newlink)
el.set('class', self._extref.obsidian_link_classname)
if target:
el.set('target', target)
el.text = text
return el, m.start(0), m.end(0)

View File

@ -250,15 +250,15 @@ class SourceIndex:
Returns:
SourceNode: The node that was found, or ``None`` if the node was not found.
str: Indicates whether the match was on "NAME" or "ALIAS". Returns ``None`` if the node was not found.
str: Indicates whether the match was on "NAME", "ALIAS", or "PATH". Returns ``None``
if the node was not found.
"""
if reference in self._byname:
return self._byname[reference], 'NAME'
elif reference in self._byalias:
return self._byalias[reference], 'ALIAS'
else:
new_path = from_node.path.parent / reference
s = new_path.as_posix()
if s in self._bypath:
return self._bypath[s], 'PATH'
new_path = (from_node.path.parent / reference).as_posix()
if new_path in self._bypath:
return self._bypath[new_path], 'PATH'
return None, None