import html5lib import six from pelican import signals 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) number.setAttribute(u"class", u"simple-footnote") number.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( dom.createTextNode("[" + six.text_type(count) + "] ") ) footnote_content.appendChild(footnote.firstChild) footnote_content.setAttribute(u"class", u"simple-footnote-content") footnote_container.appendChild(footnote_content) # print(footnote.firstChild) number.appendChild(footnote_container) 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)