Skip to content

Commit

Permalink
Merge pull request #314 from PlaidWeb/feature/269-footnote-refs
Browse files Browse the repository at this point in the history
Improve footnote references
  • Loading branch information
fluffy-critter committed Nov 25, 2019
2 parents 32c3e9e + 242632e commit 62eedc9
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 13 deletions.
28 changes: 20 additions & 8 deletions publ/entry.py
Expand Up @@ -43,6 +43,7 @@ def __init__(self, record):

LOGGER.debug('init entry %d', record.id)
self._record = record # index record
self._footnotes = [] # deferred footnotes

def __lt__(self, other):
# pylint:disable=protected-access
Expand Down Expand Up @@ -292,17 +293,26 @@ def _entry_content(self):
def body(self):
""" Get the above-the-fold entry body text """
body, _, is_markdown = self._entry_content
return TrueCallableProxy(
lambda **kwargs: self._get_markup(body, is_markdown, **kwargs)
) if body else CallableProxy(None)

def _body(**kwargs):
kwargs = {'footnotes_defer': True, **kwargs}
if 'footnotes_link' not in kwargs:
kwargs['footnotes_link'] = self.link(absolute=kwargs.get('absolute'))
return self._get_markup(body, is_markdown, **kwargs)

return TrueCallableProxy(_body) if body else CallableProxy(None)

@cached_property
def more(self):
""" Get the below-the-fold entry body text """
_, more, is_markdown = self._entry_content
return TrueCallableProxy(
lambda **kwargs: self._get_markup(more, is_markdown, **kwargs)
) if more else CallableProxy(None)

def _more(**kwargs):
if kwargs.get('absolute') and 'footnote_links' not in kwargs:
kwargs = {'footnotes_link': self.link(absolute=True), **kwargs}
return self._get_markup(more, is_markdown, **kwargs)

return TrueCallableProxy(_more) if more else CallableProxy(None)

@cached_property
def card(self):
Expand Down Expand Up @@ -372,8 +382,10 @@ def _get_markup(self, text, is_markdown, **kwargs):
if is_markdown:
return markdown.to_html(
text,
kwargs,
search_path=self.search_path)
footnote_buffer=self._footnotes,
args=kwargs,
search_path=self.search_path,
entry_id=self._record.id)

return html_entry.process(
text,
Expand Down
73 changes: 68 additions & 5 deletions publ/markdown.py
Expand Up @@ -3,6 +3,7 @@

import logging
import re
import urllib.parse

import flask
import misaka
Expand All @@ -15,6 +16,16 @@
LOGGER = logging.getLogger(__name__)


FOOTNOTE_REF_TEMPLATE = '''\
<sup id="{ref_id}"><a href="{def_url}" rel="footnote">{content}</a></sup>\
'''

FOOTNOTE_DEF_TEMPLATE = '''\
<li id="{def_id}">{before}&nbsp;<a href="{ref_url}" rev="footnote">&#8617;</a>\
{partition}{after}\
'''


class HtmlRenderer(misaka.HtmlRenderer):
""" Customized renderer for enhancing Markdown formatting
Expand All @@ -24,12 +35,61 @@ class HtmlRenderer(misaka.HtmlRenderer):
search_path -- Directories to look in for resolving relatively-linked files
"""

def __init__(self, args, search_path):
# pylint: disable=no-member
def __init__(self, args, search_path, entry_id, footnote_buffer):
# pylint:disable=no-member
super().__init__(0, args.get('xhtml') and misaka.HTML_USE_XHTML or 0)

self._config = args
self._search_path = search_path
self._entry_id = entry_id

self._footnote_link = args.get('footnotes_link') or ''
self._footnote_buffer = footnote_buffer
self._footnote_ofs = len(footnote_buffer) if footnote_buffer else 0

def footnotes(self, buffer):
""" Render the footnotes, if they aren't being deferred """
if self._footnote_buffer is not None and not self._config.get('footnotes_defer'):
return '<div class="footnotes"><hr><ol>{defer}{buffer}</ol></div>'.format(
defer=''.join(self._footnote_buffer),
buffer=buffer)
return ' '

def _footnote_num(self, num):
return num + self._footnote_ofs

def _footnote_id(self, num, anchor):
return '{anchor}_e{eid}_fn{num}'.format(
anchor=anchor,
eid=self._entry_id,
num=self._footnote_num(num))

def _footnote_url(self, num, anchor):
return urllib.parse.urljoin(self._footnote_link,
'#' + self._footnote_id(num, anchor))

def footnote_ref(self, num):
""" Render a link to this footnote """
return FOOTNOTE_REF_TEMPLATE.format(
ref_id=self._footnote_id(num, "ref"),
def_url=self._footnote_url(num, "def"),
content=self._footnote_num(num))

def footnote_def(self, content, num):
""" Render the footnote body, deferring it if so configured """

# Insert the return anchor before the end of the first content block
before, partition, after = content.partition('</p>')
text = FOOTNOTE_DEF_TEMPLATE.format(
def_id=self._footnote_id(num, "def"),
ref_url=self._footnote_url(num, "ref"),
before=before,
partition=partition,
after=after)

if self._footnote_buffer is not None:
self._footnote_buffer.append(text)
return ' '

def image(self, raw_url, title='', alt=''):
""" Adapt a standard Markdown image to a generated rendition set.
Expand Down Expand Up @@ -161,11 +221,14 @@ def _render_image(self, spec, show, container_args, alt_text=None):
_mark_rewritten=True)


def to_html(text, args, search_path):
def to_html(text, args, search_path, entry_id=None, footnote_buffer=None):
""" Convert Markdown text to HTML """

# first process as Markdown
processor = misaka.Markdown(HtmlRenderer(args, search_path),
processor = misaka.Markdown(HtmlRenderer(args,
search_path,
footnote_buffer=footnote_buffer,
entry_id=entry_id),
args.get('markdown_extensions') or
config.markdown_extensions)
text = processor(text)
Expand All @@ -184,7 +247,7 @@ class TitleRenderer(HtmlRenderer):
""" A renderer that is suitable for rendering out page titles and nothing else """

def __init__(self):
super().__init__({}, [])
super().__init__({}, [], entry_id=None, footnote_buffer=None)

@staticmethod
def paragraph(content):
Expand Down
83 changes: 83 additions & 0 deletions tests/content/footnotes.md
@@ -0,0 +1,83 @@
Title: Footnotes
Date: 2019-11-25 00:31:41-08:00
Entry-ID: 1063
UUID: 8718a59e-b8eb-5f3f-aa84-a2f9935b33e6

Here is a footnote in the body.[^body1]

Here is another footnote in the body.[^body2]

[^body1]: hi[^nestbody]

[^body2]: hello

[^nestbody]: This is nested in the body

This footnote will be an invalid reference.[^invalidmore]

[^invalidbody]: more can't reference body; this footnote shouldn't appear

.....


[^invalidmore]: body can't reference more; this footnote shouldn't appear



Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis laoreet aliquet dapibus. Vivamus augue felis, cursus id convallis non, pretium semper tortor. Quisque condimentum eleifend hendrerit. Nam gravida erat pellentesque eleifend scelerisque. Ut tempus quam a augue cursus, a varius felis cursus. Aenean at sapien id risus commodo imperdiet sed eu est. Mauris sodales efficitur nulla vitae imperdiet. Etiam semper libero congue mauris venenatis maximus. Pellentesque eu augue justo.

Ut euismod aliquet sapien non semper. Proin tellus lorem, rhoncus vitae turpis in, tempor scelerisque sapien. Morbi vel facilisis nisl. Nam auctor viverra lacus non scelerisque. Nullam id ligula ut mi egestas sodales. Morbi dapibus nunc ut augue aliquam feugiat. Proin ante magna, efficitur at elit consectetur, maximus bibendum sapien. Aenean non accumsan eros. Praesent eu mi risus. Vestibulum ut imperdiet augue. Quisque accumsan ex velit, sit amet mattis leo tristique vitae.

Suspendisse potenti. Duis dolor dui, pretium non ex a, molestie placerat metus. Aenean sagittis velit sapien, quis semper velit molestie id. Fusce eu magna odio. Nunc pellentesque fermentum velit vitae congue. Fusce porttitor lacus quis velit ultricies pharetra. Cras ullamcorper ac arcu at tempor. Donec vel leo ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In consequat nisl facilisis ante tempus, at condimentum turpis fermentum.

Maecenas vel feugiat turpis. Mauris et tincidunt ex, quis eleifend odio. Nunc vulputate imperdiet sollicitudin. Vestibulum varius erat leo, sed luctus turpis aliquet eget. Nullam interdum erat quis leo varius, sit amet placerat ante pellentesque. Morbi et turpis eu velit elementum mattis ac mollis diam. Vestibulum quam nunc, rhoncus quis mi in, commodo accumsan metus. Donec tristique mi in consectetur accumsan. Pellentesque purus nunc, feugiat vitae fermentum et, rhoncus ut lectus. Praesent purus lectus, aliquam ut pharetra non, tempus rhoncus nibh. Pellentesque eget nibh non massa ultricies facilisis eget sed tellus. Aenean id dignissim ex. In consequat, mi vitae volutpat efficitur, justo enim suscipit mi, eu egestas mauris est ac nibh. Sed ut purus et nunc suscipit tempor.

Mauris aliquam magna justo, at ullamcorper massa fermentum vel. Phasellus nec vehicula neque, quis tincidunt sapien. Mauris vehicula eros eu lectus feugiat, id posuere libero ullamcorper. Pellentesque fermentum vel felis vitae imperdiet. Nam vitae arcu ante. Morbi posuere sollicitudin viverra. Fusce a magna eget ante commodo lobortis in quis augue.

Here is a footnote in the more.[^more1]

This footnote will also be an invalid reference.[^invalidbody]


Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis laoreet aliquet dapibus. Vivamus augue felis, cursus id convallis non, pretium semper tortor. Quisque condimentum eleifend hendrerit. Nam gravida erat pellentesque eleifend scelerisque. Ut tempus quam a augue cursus, a varius felis cursus. Aenean at sapien id risus commodo imperdiet sed eu est. Mauris sodales efficitur nulla vitae imperdiet. Etiam semper libero congue mauris venenatis maximus. Pellentesque eu augue justo.

Ut euismod aliquet sapien non semper. Proin tellus lorem, rhoncus vitae turpis in, tempor scelerisque sapien. Morbi vel facilisis nisl. Nam auctor viverra lacus non scelerisque. Nullam id ligula ut mi egestas sodales. Morbi dapibus nunc ut augue aliquam feugiat. Proin ante magna, efficitur at elit consectetur, maximus bibendum sapien. Aenean non accumsan eros. Praesent eu mi risus. Vestibulum ut imperdiet augue. Quisque accumsan ex velit, sit amet mattis leo tristique vitae.

Suspendisse potenti. Duis dolor dui, pretium non ex a, molestie placerat metus. Aenean sagittis velit sapien, quis semper velit molestie id. Fusce eu magna odio. Nunc pellentesque fermentum velit vitae congue. Fusce porttitor lacus quis velit ultricies pharetra. Cras ullamcorper ac arcu at tempor. Donec vel leo ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In consequat nisl facilisis ante tempus, at condimentum turpis fermentum.

Maecenas vel feugiat turpis. Mauris et tincidunt ex, quis eleifend odio. Nunc vulputate imperdiet sollicitudin. Vestibulum varius erat leo, sed luctus turpis aliquet eget. Nullam interdum erat quis leo varius, sit amet placerat ante pellentesque. Morbi et turpis eu velit elementum mattis ac mollis diam. Vestibulum quam nunc, rhoncus quis mi in, commodo accumsan metus. Donec tristique mi in consectetur accumsan. Pellentesque purus nunc, feugiat vitae fermentum et, rhoncus ut lectus. Praesent purus lectus, aliquam ut pharetra non, tempus rhoncus nibh. Pellentesque eget nibh non massa ultricies facilisis eget sed tellus. Aenean id dignissim ex. In consequat, mi vitae volutpat efficitur, justo enim suscipit mi, eu egestas mauris est ac nibh. Sed ut purus et nunc suscipit tempor.

Mauris aliquam magna justo, at ullamcorper massa fermentum vel. Phasellus nec vehicula neque, quis tincidunt sapien. Mauris vehicula eros eu lectus feugiat, id posuere libero ullamcorper. Pellentesque fermentum vel felis vitae imperdiet. Nam vitae arcu ante. Morbi posuere sollicitudin viverra. Fusce a magna eget ante commodo lobortis in quis augue.

Another one.[^more2]



Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis laoreet aliquet dapibus. Vivamus augue felis, cursus id convallis non, pretium semper tortor. Quisque condimentum eleifend hendrerit. Nam gravida erat pellentesque eleifend scelerisque. Ut tempus quam a augue cursus, a varius felis cursus. Aenean at sapien id risus commodo imperdiet sed eu est. Mauris sodales efficitur nulla vitae imperdiet. Etiam semper libero congue mauris venenatis maximus. Pellentesque eu augue justo.

Ut euismod aliquet sapien non semper. Proin tellus lorem, rhoncus vitae turpis in, tempor scelerisque sapien. Morbi vel facilisis nisl. Nam auctor viverra lacus non scelerisque. Nullam id ligula ut mi egestas sodales. Morbi dapibus nunc ut augue aliquam feugiat. Proin ante magna, efficitur at elit consectetur, maximus bibendum sapien. Aenean non accumsan eros. Praesent eu mi risus. Vestibulum ut imperdiet augue. Quisque accumsan ex velit, sit amet mattis leo tristique vitae.

Suspendisse potenti. Duis dolor dui, pretium non ex a, molestie placerat metus. Aenean sagittis velit sapien, quis semper velit molestie id. Fusce eu magna odio. Nunc pellentesque fermentum velit vitae congue. Fusce porttitor lacus quis velit ultricies pharetra. Cras ullamcorper ac arcu at tempor. Donec vel leo ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In consequat nisl facilisis ante tempus, at condimentum turpis fermentum.

Maecenas vel feugiat turpis. Mauris et tincidunt ex, quis eleifend odio. Nunc vulputate imperdiet sollicitudin. Vestibulum varius erat leo, sed luctus turpis aliquet eget. Nullam interdum erat quis leo varius, sit amet placerat ante pellentesque. Morbi et turpis eu velit elementum mattis ac mollis diam. Vestibulum quam nunc, rhoncus quis mi in, commodo accumsan metus. Donec tristique mi in consectetur accumsan. Pellentesque purus nunc, feugiat vitae fermentum et, rhoncus ut lectus. Praesent purus lectus, aliquam ut pharetra non, tempus rhoncus nibh. Pellentesque eget nibh non massa ultricies facilisis eget sed tellus. Aenean id dignissim ex. In consequat, mi vitae volutpat efficitur, justo enim suscipit mi, eu egestas mauris est ac nibh. Sed ut purus et nunc suscipit tempor.

Mauris aliquam magna justo, at ullamcorper massa fermentum vel. Phasellus nec vehicula neque, quis tincidunt sapien. Mauris vehicula eros eu lectus feugiat, id posuere libero ullamcorper. Pellentesque fermentum vel felis vitae imperdiet. Nam vitae arcu ante. Morbi posuere sollicitudin viverra. Fusce a magna eget ante commodo lobortis in quis augue.



Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis laoreet aliquet dapibus. Vivamus augue felis, cursus id convallis non, pretium semper tortor. Quisque condimentum eleifend hendrerit. Nam gravida erat pellentesque eleifend scelerisque. Ut tempus quam a augue cursus, a varius felis cursus. Aenean at sapien id risus commodo imperdiet sed eu est. Mauris sodales efficitur nulla vitae imperdiet. Etiam semper libero congue mauris venenatis maximus. Pellentesque eu augue justo.

Ut euismod aliquet sapien non semper. Proin tellus lorem, rhoncus vitae turpis in, tempor scelerisque sapien. Morbi vel facilisis nisl. Nam auctor viverra lacus non scelerisque. Nullam id ligula ut mi egestas sodales. Morbi dapibus nunc ut augue aliquam feugiat. Proin ante magna, efficitur at elit consectetur, maximus bibendum sapien. Aenean non accumsan eros. Praesent eu mi risus. Vestibulum ut imperdiet augue. Quisque accumsan ex velit, sit amet mattis leo tristique vitae.

Suspendisse potenti. Duis dolor dui, pretium non ex a, molestie placerat metus. Aenean sagittis velit sapien, quis semper velit molestie id. Fusce eu magna odio. Nunc pellentesque fermentum velit vitae congue. Fusce porttitor lacus quis velit ultricies pharetra. Cras ullamcorper ac arcu at tempor. Donec vel leo ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In consequat nisl facilisis ante tempus, at condimentum turpis fermentum.

Maecenas vel feugiat turpis. Mauris et tincidunt ex, quis eleifend odio. Nunc vulputate imperdiet sollicitudin. Vestibulum varius erat leo, sed luctus turpis aliquet eget. Nullam interdum erat quis leo varius, sit amet placerat ante pellentesque. Morbi et turpis eu velit elementum mattis ac mollis diam. Vestibulum quam nunc, rhoncus quis mi in, commodo accumsan metus. Donec tristique mi in consectetur accumsan. Pellentesque purus nunc, feugiat vitae fermentum et, rhoncus ut lectus. Praesent purus lectus, aliquam ut pharetra non, tempus rhoncus nibh. Pellentesque eget nibh non massa ultricies facilisis eget sed tellus. Aenean id dignissim ex. In consequat, mi vitae volutpat efficitur, justo enim suscipit mi, eu egestas mauris est ac nibh. Sed ut purus et nunc suscipit tempor.

Mauris aliquam magna justo, at ullamcorper massa fermentum vel. Phasellus nec vehicula neque, quis tincidunt sapien. Mauris vehicula eros eu lectus feugiat, id posuere libero ullamcorper. Pellentesque fermentum vel felis vitae imperdiet. Nam vitae arcu ante. Morbi posuere sollicitudin viverra. Fusce a magna eget ante commodo lobortis in quis augue.
[^more1]: foo[^nestmore]

[^nestmore]: this is nested in the more

[^more2]: bar


0 comments on commit 62eedc9

Please sign in to comment.