custom version of simple_footnotes
This commit is contained in:
parent
04bdafae05
commit
d91a9e910b
complex_footnotes
26
complex_footnotes/README.md
Normal file
26
complex_footnotes/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
Simple Footnotes
|
||||
================
|
||||
|
||||
A Pelican plugin to add footnotes to blog posts.
|
||||
|
||||
When writing a post or page, add a footnote like this:
|
||||
|
||||
Here's my written text[ref]and here is a footnote[/ref].
|
||||
|
||||
This will appear as, roughly:
|
||||
|
||||
Here's my written text<sup>1</sup>
|
||||
|
||||
1. and here is a footnote ↩
|
||||
|
||||
Inspired by Andrew Nacin's [Simple Footnotes WordPress plugin](http://wordpress.org/plugins/simple-footnotes/).
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
Needs html5lib, so you'll want to `pip install html5lib` before running.
|
||||
|
||||
Should work with any content format (ReST, Markdown, whatever), because
|
||||
it looks for the `[ref]` and `[/ref]` once the conversion to HTML has happened.
|
||||
|
||||
Stuart Langridge, http://www.kryogenix.org/, February 2014.
|
1
complex_footnotes/__init__.py
Normal file
1
complex_footnotes/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .simple_footnotes import *
|
108
complex_footnotes/simple_footnotes.py
Normal file
108
complex_footnotes/simple_footnotes.py
Normal file
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*- #
|
||||
|
||||
from pelican import signals
|
||||
import html5lib
|
||||
import six
|
||||
|
||||
RAW_FOOTNOTE_CONTAINERS = ["code"]
|
||||
|
||||
|
||||
def getText(node, recursive=False):
|
||||
"""Get all the text associated with this node.
|
||||
With recursive == True, all text from child nodes is retrieved."""
|
||||
L = [u'']
|
||||
for n in node.childNodes:
|
||||
if n.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE):
|
||||
L.append(n.data)
|
||||
else:
|
||||
if not recursive:
|
||||
return None
|
||||
L.append(getText(n))
|
||||
return u''.join(L)
|
||||
|
||||
|
||||
def sequence_gen(genlist):
|
||||
for gen in genlist:
|
||||
for elem in gen:
|
||||
yield elem
|
||||
|
||||
|
||||
def parse_for_footnotes(article_or_page_generator):
|
||||
all_content = [
|
||||
getattr(article_or_page_generator, attr, None) \
|
||||
for attr in [u'articles', u'drafts', u'pages']]
|
||||
all_content = [x for x in all_content if x is not None]
|
||||
for article in sequence_gen(all_content):
|
||||
if u"[ref]" in article._content and u"[/ref]" in article._content:
|
||||
content = article._content.replace(u"[ref]", u"<x-simple-footnote>").replace(u"[/ref]",
|
||||
u"</x-simple-footnote>")
|
||||
parser = html5lib.HTMLParser(tree=html5lib.getTreeBuilder(u"dom"))
|
||||
dom = parser.parse(content)
|
||||
endnotes = []
|
||||
count = 0
|
||||
for footnote in dom.getElementsByTagName(u"x-simple-footnote"):
|
||||
pn = footnote
|
||||
leavealone = False
|
||||
while pn:
|
||||
if pn.nodeName in RAW_FOOTNOTE_CONTAINERS:
|
||||
leavealone = True
|
||||
break
|
||||
pn = pn.parentNode
|
||||
if leavealone:
|
||||
continue
|
||||
count += 1
|
||||
fnid = u"sf-%s-%s" % (article.slug, count)
|
||||
fnbackid = u"%s-back" % (fnid,)
|
||||
endnotes.append((footnote, fnid, fnbackid))
|
||||
number = dom.createElement(u"sup")
|
||||
number.setAttribute(u"id", fnbackid)
|
||||
|
||||
numbera = dom.createElement(u"a")
|
||||
numbera.setAttribute(u"href", u"#%s" % fnid)
|
||||
numbera.setAttribute(u"class", u"simple-footnote")
|
||||
numbera.appendChild(dom.createTextNode(six.text_type(count)))
|
||||
txt = getText(footnote, recursive=True).replace(u"\n", u" ")
|
||||
|
||||
footnote_container = dom.createElement(u"span")
|
||||
footnote_container.setAttribute(u"class", u"simple-footnote-container")
|
||||
footnote_content = dom.createElement(u"span")
|
||||
footnote_content.appendChild(footnote.firstChild)
|
||||
footnote_content.setAttribute(u"class", u"simple-footnote-content")
|
||||
footnote_container.appendChild(footnote_content)
|
||||
print(footnote.firstChild)
|
||||
|
||||
numbera.setAttribute(u"title", txt)
|
||||
number.appendChild(footnote_container)
|
||||
number.appendChild(numbera)
|
||||
|
||||
footnote.parentNode.insertBefore(number, footnote)
|
||||
footnote.parentNode.insertBefore(footnote_container, footnote)
|
||||
if endnotes:
|
||||
ol = dom.createElement(u"ol")
|
||||
ol.setAttribute(u"class", u"simple-footnotes")
|
||||
for e, fnid, fnbackid in endnotes:
|
||||
# li = dom.createElement(u"li")
|
||||
# li.setAttribute(u"id", fnid)
|
||||
# while e.firstChild:
|
||||
# li.appendChild(e.firstChild)
|
||||
# backlink = dom.createElement(u"a")
|
||||
# backlink.setAttribute(u"href", u"#%s" % fnbackid)
|
||||
# backlink.setAttribute(u"class", u"simple-footnote-back")
|
||||
# backlink.appendChild(dom.createTextNode(u'\u21a9'))
|
||||
# li.appendChild(dom.createTextNode(u" "))
|
||||
# li.appendChild(backlink)
|
||||
# ol.appendChild(li)
|
||||
e.parentNode.removeChild(e)
|
||||
dom.getElementsByTagName(u"body")[0].appendChild(ol)
|
||||
s = html5lib.serializer.HTMLSerializer(omit_optional_tags=False, quote_attr_values='legacy')
|
||||
output_generator = s.serialize(
|
||||
html5lib.treewalkers.getTreeWalker(u"dom")(dom.getElementsByTagName(u"body")[0]))
|
||||
article._content = u"".join(list(output_generator)).replace(
|
||||
u"<x-simple-footnote>", u"[ref]").replace(u"</x-simple-footnote>", u"[/ref]").replace(
|
||||
u"<body>", u"").replace(u"</body>", u"")
|
||||
|
||||
|
||||
def register():
|
||||
signals.article_generator_finalized.connect(parse_for_footnotes)
|
||||
signals.page_generator_finalized.connect(parse_for_footnotes)
|
33
complex_footnotes/test_simple_footnotes.py
Normal file
33
complex_footnotes/test_simple_footnotes.py
Normal file
@ -0,0 +1,33 @@
|
||||
import unittest
|
||||
from simple_footnotes import parse_for_footnotes
|
||||
|
||||
class PseudoArticleGenerator(object):
|
||||
articles = []
|
||||
class PseudoArticle(object):
|
||||
_content = ""
|
||||
slug = "article"
|
||||
|
||||
class TestFootnotes(unittest.TestCase):
|
||||
|
||||
def _expect(self, input, expected_output):
|
||||
ag = PseudoArticleGenerator()
|
||||
art = PseudoArticle()
|
||||
art._content = input
|
||||
ag.articles = [art]
|
||||
parse_for_footnotes(ag)
|
||||
self.assertEqual(art._content, expected_output)
|
||||
|
||||
def test_simple(self):
|
||||
self._expect("words[ref]footnote[/ref]end",
|
||||
('words<sup id="sf-article-1-back"><a title="footnote" '
|
||||
'href="#sf-article-1" class="simple-footnote">1</a></sup>end'
|
||||
'<ol class="simple-footnotes">'
|
||||
u'<li id="sf-article-1">footnote <a href="#sf-article-1-back" class="simple-footnote-back">\u21a9</a></li>'
|
||||
'</ol>'))
|
||||
|
||||
def test_no_footnote_inside_code(self):
|
||||
self._expect("words<code>this is code[ref]footnote[/ref] end code </code> end",
|
||||
"words<code>this is code[ref]footnote[/ref] end code </code> end")
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user