Skip to content

Commit facfd66

Browse files
facelessuserwaylan
authored andcommitted
Fix footnote parsing of footnote content (#536)
Fixes #412 and #493. First we parse footnote content as its own document avoid quirks with using li as a parent. Second, we surround placeholders with STX and ETX to prevent them from interfering with inline parsing; this is also consistent with how placeholders are used everywhere else in Python Markdown.
1 parent 8afeaaf commit facfd66

File tree

3 files changed

+78
-13
lines changed

3 files changed

+78
-13
lines changed

markdown/extensions/footnotes.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
from ..inlinepatterns import Pattern
2121
from ..treeprocessors import Treeprocessor
2222
from ..postprocessors import Postprocessor
23-
from ..util import etree, text_type
23+
from .. import util
2424
from ..odict import OrderedDict
2525
import re
2626
import copy
2727

28-
FN_BACKLINK_TEXT = "zz1337820767766393qq"
29-
NBSP_PLACEHOLDER = "qq3936677670287331zz"
28+
FN_BACKLINK_TEXT = util.STX + "zz1337820767766393qq" + util.ETX
29+
NBSP_PLACEHOLDER = util.STX + "qq3936677670287331zz" + util.ETX
3030
DEF_RE = re.compile(r'[ ]{0,3}\[\^([^\]]*)\]:\s*(.*)')
3131
TABBED_RE = re.compile(r'((\t)|( ))(.*)')
3232
RE_REF_ID = re.compile(r'(fnref)(\d+)')
@@ -169,16 +169,23 @@ def makeFootnotesDiv(self, root):
169169
if not list(self.footnotes.keys()):
170170
return None
171171

172-
div = etree.Element("div")
172+
div = util.etree.Element("div")
173173
div.set('class', 'footnote')
174-
etree.SubElement(div, "hr")
175-
ol = etree.SubElement(div, "ol")
174+
util.etree.SubElement(div, "hr")
175+
ol = util.etree.SubElement(div, "ol")
176+
surrogate_parent = util.etree.Element("div")
176177

177178
for id in self.footnotes.keys():
178-
li = etree.SubElement(ol, "li")
179+
li = util.etree.SubElement(ol, "li")
179180
li.set("id", self.makeFootnoteId(id))
180-
self.parser.parseChunk(li, self.footnotes[id])
181-
backlink = etree.Element("a")
181+
# Parse footnote with surrogate parent as li cannot be used.
182+
# List block handlers have special logic to deal with li.
183+
# When we are done parsing, we will copy everything over to li.
184+
self.parser.parseChunk(surrogate_parent, self.footnotes[id])
185+
for el in list(surrogate_parent):
186+
li.append(el)
187+
surrogate_parent.remove(el)
188+
backlink = util.etree.Element("a")
182189
backlink.set("href", "#" + self.makeFootnoteRefId(id))
183190
if self.md.output_format not in ['html5', 'xhtml5']:
184191
backlink.set("rev", "footnote") # Invalid in HTML5
@@ -196,7 +203,7 @@ def makeFootnotesDiv(self, root):
196203
node.text = node.text + NBSP_PLACEHOLDER
197204
node.append(backlink)
198205
else:
199-
p = etree.SubElement(li, "p")
206+
p = util.etree.SubElement(li, "p")
200207
p.append(backlink)
201208
return div
202209

@@ -303,14 +310,14 @@ def __init__(self, pattern, footnotes):
303310
def handleMatch(self, m):
304311
id = m.group(2)
305312
if id in self.footnotes.footnotes.keys():
306-
sup = etree.Element("sup")
307-
a = etree.SubElement(sup, "a")
313+
sup = util.etree.Element("sup")
314+
a = util.etree.SubElement(sup, "a")
308315
sup.set('id', self.footnotes.makeFootnoteRefId(id, found=True))
309316
a.set('href', '#' + self.footnotes.makeFootnoteId(id))
310317
if self.footnotes.md.output_format not in ['html5', 'xhtml5']:
311318
a.set('rel', 'footnote') # invalid in HTML5
312319
a.set('class', 'footnote-ref')
313-
a.text = text_type(self.footnotes.footnotes.index(id) + 1)
320+
a.text = util.text_type(self.footnotes.footnotes.index(id) + 1)
314321
return sup
315322
else:
316323
return None

tests/extensions/extra/footnote.html

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<p>Duplicate<sup id="fnref:a"><a class="footnote-ref" href="#fn:a" rel="footnote">6</a></sup> footnotes<sup id="fnref2:a"><a class="footnote-ref" href="#fn:a" rel="footnote">6</a></sup> test<sup id="fnref3:a"><a class="footnote-ref" href="#fn:a" rel="footnote">6</a></sup>.</p>
44
<p>Duplicate<sup id="fnref:b"><a class="footnote-ref" href="#fn:b" rel="footnote">7</a></sup> footnotes<sup id="fnref2:b"><a class="footnote-ref" href="#fn:b" rel="footnote">7</a></sup> test<sup id="fnref3:b"><a class="footnote-ref" href="#fn:b" rel="footnote">7</a></sup>.</p>
55
<p>Single after duplicates<sup id="fnref:c"><a class="footnote-ref" href="#fn:c" rel="footnote">8</a></sup>.</p>
6+
<p>Test emphasis at end of footnote<sup id="fnref:d"><a class="footnote-ref" href="#fn:d" rel="footnote">9</a></sup></p>
7+
<p>Complex footnote content<sup id="fnref:e"><a class="footnote-ref" href="#fn:e" rel="footnote">10</a></sup></p>
68
<div class="footnote">
79
<hr />
810
<ol>
@@ -41,5 +43,29 @@
4143
<li id="fn:c">
4244
<p>3&#160;<a class="footnote-backref" href="#fnref:c" rev="footnote" title="Jump back to footnote 8 in the text">&#8617;</a></p>
4345
</li>
46+
<li id="fn:d">
47+
<p><em>emphasis works</em></p>
48+
<p><em>emphasis still works</em>&#160;<a class="footnote-backref" href="#fnref:d" rev="footnote" title="Jump back to footnote 9 in the text">&#8617;</a></p>
49+
</li>
50+
<li id="fn:e">
51+
<ol>
52+
<li>
53+
<p>The top couple half figure, contrary sides and hands across with bottom couple,</p>
54+
<p>Half figure back on your own sides, and turn partner to places,</p>
55+
<p>Swing partners with right hands into straight line long-ways, as in a reel, and</p>
56+
<p>Set,</p>
57+
<p>Hey and return to places,</p>
58+
<p>The other three couples do the same.</p>
59+
</li>
60+
<li>
61+
<p>Top and bottom couples meet and set,</p>
62+
<p>Then each gentleman leas the opposite lady to the couple on his left, and set,</p>
63+
<p>Aach four right and left,</p>
64+
<p>Swing side couples to places, and turn partners all eight,</p>
65+
<p>The other two couple o the same.</p>
66+
</li>
67+
</ol>
68+
<p><a class="footnote-backref" href="#fnref:e" rev="footnote" title="Jump back to footnote 10 in the text">&#8617;</a></p>
69+
</li>
4470
</ol>
4571
</div>

tests/extensions/extra/footnote.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ Duplicate[^b] footnotes[^b] test[^b].
88

99
Single after duplicates[^c].
1010

11+
Test emphasis at end of footnote[^d]
12+
13+
Complex footnote content[^e]
14+
1115
[^1]: Footnote that ends with a list:
1216

1317
* item 1
@@ -28,3 +32,31 @@ Nor is third...
2832
[^a]: 1
2933
[^b]: 2
3034
[^c]: 3
35+
36+
[^d]:
37+
_emphasis works_
38+
39+
_emphasis still works_
40+
41+
[^e]:
42+
1. The top couple half figure, contrary sides and hands across with bottom couple,
43+
44+
Half figure back on your own sides, and turn partner to places,
45+
46+
Swing partners with right hands into straight line long-ways, as in a reel, and
47+
48+
Set,
49+
50+
Hey and return to places,
51+
52+
The other three couples do the same.
53+
54+
2. Top and bottom couples meet and set,
55+
56+
Then each gentleman leas the opposite lady to the couple on his left, and set,
57+
58+
Aach four right and left,
59+
60+
Swing side couples to places, and turn partners all eight,
61+
62+
The other two couple o the same.

0 commit comments

Comments
 (0)