diff options
-rwxr-xr-x[-rw-r--r--] | markdown.py | 154 | ||||
-rw-r--r-- | mdx_footnotes.py | 117 | ||||
-rw-r--r-- | mdx_rss.py | 102 | ||||
-rw-r--r-- | tests/extensions-x-footnotes/footnote.html | 82 | ||||
-rwxr-xr-x | tests/markdown-test/angle-links-and-img.html | 7 | ||||
-rwxr-xr-x | tests/markdown-test/angle-links-and-img.txt | 4 | ||||
-rwxr-xr-x | tests/misc/blockquote-below-paragraph.html | 6 | ||||
-rwxr-xr-x | tests/misc/blockquote-below-paragraph.txt | 3 | ||||
-rwxr-xr-x | tests/misc/html-comments.html | 2 | ||||
-rwxr-xr-x | tests/misc/html-comments.txt | 2 |
10 files changed, 263 insertions, 216 deletions
diff --git a/markdown.py b/markdown.py index e4235ff..3891ac3 100644..100755 --- a/markdown.py +++ b/markdown.py @@ -62,26 +62,32 @@ def message(level, text): def isstr(s): return isinstance(s, unicode) or isinstance(s, str) -try: - # Python 2.5+ - import xml.etree.cElementTree as etree -except ImportError: +def importETree(): + """ Importing best variant of ElementTree + and returning module object """ + try: # Python 2.5+ - import xml.etree.ElementTree as etree + import xml.etree.cElementTree as etree except ImportError: try: - # normal cElementTree install - import cElementTree as etree + # Python 2.5+ + import xml.etree.ElementTree as etree except ImportError: try: - # normal ElementTree install - import elementtree.ElementTree as etree + # normal cElementTree install + import cElementTree as etree except ImportError: - message(CRITICAL, - "Failed to import ElementTree from any known place") - sys.exit(1) + try: + # normal ElementTree install + import elementtree.ElementTree as etree + except ImportError: + message(CRITICAL, + "Failed to import ElementTree from any known place") + sys.exit(1) + return etree +etree = importETree() def indentETree(elem, level=0): @@ -173,8 +179,8 @@ def isBlockLevel (tag): def codepoint2name(code): - """ Returns entity defenition by code, or code - if there is no such entity defenition""" + """ Returns entity definition by code, or code + if there is no such entity definition""" entity = htmlentitydefs.codepoint2name.get(code) if entity: return "%s%s;" % (AND_SUBSTITUTE, entity) @@ -351,7 +357,7 @@ class HeaderPreprocessor(Preprocessor): """ Replace underlined headers with hashed headers to avoid - the nead for lookahead later. + the need for lookahead later. """ def run (self, lines): @@ -394,7 +400,7 @@ class LinePreprocessor(Preprocessor): blockquote_re = re.compile(r'^(> )+') def run (self, lines): - """ Find a store HR lines. """ + """ Find and replace HR lines. """ for i in range(len(lines)): prefix = '' @@ -467,9 +473,8 @@ expression and needs support the following methods: pattern.getCompiledRegExp() - returns a regular expression - pattern.handleMatch(m, doc) - takes a match object and returns - a NanoDom node (as a part of the provided - doc) or None + pattern.handleMatch(m) - takes a match object and returns + a ElementTree element or just plain text All of python markdown's built-in patterns subclass from Pattern, but you can add additional patterns that don't. @@ -521,16 +526,20 @@ else: #LINK_RE = NOIMG + BRK + r'\s*\(([^\)]*)\)' # [text](url) LINK_RE = NOIMG + BRK + \ -r'''\(\s*(((?:(?:\(.*?\))|[^\(\)]))*?|<\10*?>)\s*((['"])(.*)\12)?\)''' # [text](url) or [text](<url>) +r'''\(\s*(<.*?>|((?:(?:\(.*?\))|[^\(\)]))*?)\s*((['"])(.*)\12)?\)''' # [text](url) or [text](<url>) +#r'''\(\s*(<.*?>|((?:(?:\(.*?\))|[^\(\)]))*)\s*((['"])(.*)\12)?\)''' # [text](url) or [text](<url>) + +#LINK_RE2 = NOIMG + BRK + \ +#r'''\(\s*(((?:(?:\(.*?\))|[^\(\)]))*?|<\10*?>)\s*((['"])(.*)\12)?\)''' # [text](url) or [text](<url>) -IMAGE_LINK_RE = r'\!' + BRK + r'\s*\(([^\)]*)\)' # ![alttxt](http://x.com/) +IMAGE_LINK_RE = r'\!' + BRK + r'\s*\((<.*?>|([^\)]*))\)' # ![alttxt](http://x.com/) or ![alttxt](<http://x.com/>) REFERENCE_RE = NOIMG + BRK+ r'\s*\[([^\]]*)\]' # [Google][3] IMAGE_REFERENCE_RE = r'\!' + BRK + '\s*\[([^\]]*)\]' # ![alt text][2] NOT_STRONG_RE = r'( \* )' # stand-alone * or _ AUTOLINK_RE = r'<((?:f|ht)tps?://[^>]*)>' # <http://www.123.com> AUTOMAIL_RE = r'<([^> \!]*@[^> ]*)>' # <me@example.com> #HTML_RE = r'(\<[^\>]*\>)' # <...> -HTML_RE = r'(\<[a-zA-Z/][^\>]*\>)' # <...> +HTML_RE = r'(\<([a-zA-Z/][^\>]*?|\!--.*?--)\>)' # <...> ENTITY_RE = r'(&[\#a-zA-Z0-9]*;)' # & LINE_BREAK_RE = r' \n' # two spaces at end of line LINE_BREAK_2_RE = r' $' # two spaces at end of text @@ -559,15 +568,13 @@ class Pattern: def handleMatch(self, m): """ - Return a NanoDom element from the given match. Subclasses should + Return a ElementTree element from the given match. Subclasses should override this method. Keyword arguments: * m: A re match object containing a match of the pattern. - * doc: An instance of a NanoDom Document. - """ pass @@ -578,7 +585,7 @@ class Pattern: BasePattern = Pattern # for backward compatibility class SimpleTextPattern (Pattern): - """ Return a simple TextNode of group(2) of a Pattern. """ + """ Return a simple text of group(2) of a Pattern. """ def handleMatch(self, m): text = m.group(2) if text == INLINE_PLACEHOLDER_PREFIX: @@ -587,7 +594,7 @@ class SimpleTextPattern (Pattern): class SimpleTagPattern (Pattern): """ - Return NanoDom Element of type `tag` with a child TextNode of group(2) + Return element of type `tag` with a text attribute of group(3) of a Pattern. """ @@ -601,12 +608,12 @@ class SimpleTagPattern (Pattern): return el class SubstituteTagPattern (SimpleTagPattern): - """ Return a NanoDom ELement of type `tag` with no children. """ + """ Return a eLement of type `tag` with no children. """ def handleMatch (self, m): return etree.Element(self.tag) class BacktickPattern (Pattern): - """ Return a NanoDom `<code>` Element containing the matching text. """ + """ Return a `<code>` element containing the matching text. """ def __init__ (self, pattern): Pattern.__init__(self, pattern) self.tag = "code" @@ -619,7 +626,7 @@ class BacktickPattern (Pattern): class DoubleTagPattern (SimpleTagPattern): """ - Return a TextNode nested in tag2 nested in tag1. + Return a ElementTree element nested in tag2 nested in tag1. Usefull for strong emphasis etc. """ @@ -642,7 +649,7 @@ class HtmlPattern (Pattern): class LinkPattern (Pattern): - """ Return a NanoDom link Element from the given match. """ + """ Return a link element from the given match. """ def handleMatch(self, m): el = etree.Element("a") el.text = m.group(2) @@ -693,13 +700,16 @@ class LinkPattern (Pattern): return urlunparse(url) class ImagePattern(LinkPattern): - """ Return a NanoDom img Element from the given match. """ + """ Return a img element from the given match. """ def handleMatch(self, m): el = etree.Element("img") src_parts = m.group(9).split() if src_parts: - el.set('src', self.sanatize_url(src_parts[0])) + src = src_parts[0] + if src[0] == "<" and src[-1] == ">": + src = src[1:-1] + el.set('src', self.sanatize_url(src)) else: el.set('src', "") if len(src_parts) > 1: @@ -714,7 +724,7 @@ class ImagePattern(LinkPattern): return el class ReferencePattern(LinkPattern): - """ Match to a stored reference and return a NanoDom link Element. """ + """ Match to a stored reference and return link element. """ def handleMatch(self, m): if m.group(9): @@ -743,7 +753,7 @@ class ReferencePattern(LinkPattern): class ImageReferencePattern (ReferencePattern): - """ Match to a stored reference and return a NanoDom img Element. """ + """ Match to a stored reference and return img element. """ def makeTag(self, href, title, text): el = etree.Element("img") el.set("src", self.sanatize_url(href)) @@ -821,10 +831,10 @@ There are two types of post-processors: Postprocessor and TextPostprocessor class Postprocessor: """ - Postprocessors are run before the dom it converted back into text. + Postprocessors are run before the ElementTree serialization. Each Postprocessor implements a "run" method that takes a pointer to a - NanoDom document, modifies it as necessary and returns a NanoDom + ElementTree, modifies it as necessary and returns a ElementTree document. Postprocessors must extend markdown.Postprocessor. @@ -834,11 +844,10 @@ class Postprocessor: """ - def run(self, dom): + def run(self, et): """ Subclasses of Postprocessor should implement a `run` method, which - takes a NanoDOm document and returns a (possably modified) NanoDom - document. + takes a ElementTree and returns a (possably modified) ElementTree. """ pass @@ -847,7 +856,7 @@ class Postprocessor: class TextPostprocessor: """ - TextPostprocessors are run after the dom it converted back into text. + TextPostprocessors are run after the ElementTree it converted back into text. Each TextPostprocessor implements a "run" method that takes a pointer to a text string, modifies it as necessary and returns a text string. @@ -1107,6 +1116,7 @@ class CorePatterns: 'isline2': r'(\-*)', # --- 'isline3': r'(\_*)', # ___ 'tabbed': r'((\t)|( ))(.*)', # an indented line + 'tabbed2': r'(()( ))(.*)', # an indented line 'quoted': r'[ ]{0,2}> ?(.*)', # a quoted block ("> ...") } @@ -1279,8 +1289,7 @@ class Markdown: for prep in self.preprocessors : self.lines = prep.run(self.lines) - # Create a NanoDom tree from the lines and attach it to Document - + # Create a ElementTree from the lines buffer = [] for line in self.lines: @@ -1292,16 +1301,7 @@ class Markdown: buffer.append(line) self._processSection(self.root, buffer) - - #self._processSection(self.top_element, self.lines) - - # Not sure why I put this in but let's leave it for now. - #self.top_element.appendChild(self.doc.createTextNode('\n')) - - # Run the post-processors - for postprocessor in self.postprocessors: - postprocessor.run(self.doc) - + return etree.ElementTree(self.root) @@ -1323,10 +1323,15 @@ class Markdown: Returns: None """ - + # Loop through lines until none left. while lines: - + + # Skipping empty line + if not lines[0]: + lines = lines[1:] + continue + # Check if this section starts with a list, a blockquote or # a code block @@ -1370,7 +1375,7 @@ class Markdown: else: # Ok, so it's just a simple block paragraph, lines = self._linesUntil(lines, lambda line: - not line.strip()) + not line.strip() or line[0] == '>') if len(paragraph) and paragraph[0].startswith('#'): self._processHeader(parent_elem, paragraph) @@ -1448,7 +1453,7 @@ class Markdown: Keyword arguments: - * parent_elem: A dom element to which the content will be added + * parent_elem: A ElementTree element to which the content will be added * lines: a list of lines * inList: a level @@ -1486,7 +1491,7 @@ class Markdown: # Check if the next non-blank line is still a part of the list if ( RE.regExp['ul'].match(next) or RE.regExp['ol'].match(next) or - RE.regExp['tabbed'].match(next) ): + RE.regExp['tabbed'].match(next)): # get rid of any white space in the line items[item].append(line.strip()) looseList = loose or looseList @@ -1497,7 +1502,7 @@ class Markdown: # Now we need to detect list items (at the current level) # while also detabing child elements if necessary - for expr in ['ul', 'ol', 'tabbed']: + for expr in ['ul', 'ol', 'tabbed', 'tabbed2']: m = RE.regExp[expr].match(line) if m: @@ -1507,7 +1512,7 @@ class Markdown: # at the beginning of the list item items.append([m.group(1)]) item += 1 - elif expr == 'tabbed': # This line needs to be detabbed + elif expr == 'tabbed' or expr == 'tabbed2': # This line needs to be detabbed items[item].append(m.group(4)) #after the 'tab' i += 1 @@ -1518,7 +1523,7 @@ class Markdown: else: i += 1 - # Add the dom elements + # Add the ElementTree elements for item in items: li = etree.SubElement(ul, "li") @@ -1540,7 +1545,8 @@ class Markdown: i = -1 for line in lines: i += 1 - if condition(line): break + if condition(line): + break else: i += 1 return lines[:i], lines[i:] @@ -1554,7 +1560,7 @@ class Markdown: Keyword arguments: - * parent_elem: DOM element to which the content will be added + * parent_elem: ElementTree element to which the content will be added * lines: a list of lines * inList: a level @@ -1592,13 +1598,13 @@ class Markdown: def _processCodeBlock(self, parent_elem, lines, inList): """ Given a list of document lines starting with a code block - finds the end of the block, puts it into the dom verbatim + finds the end of the block, puts it into the ElementTree verbatim wrapped in ("<pre><code>") and recursively processes the the remainder of the text file. Keyword arguments: - * parent_elem: DOM element to which the content will be added + * parent_elem: ElementTree element to which the content will be added * lines: a list of lines * inList: a level @@ -1710,11 +1716,11 @@ class Markdown: def _processPlaceholders(self, data, parent): """ - Processes string with placeholders and generates DOM tree. + Processes string with placeholders and generates ElementTree tree. - * data: string with placeholders instead of DOM elements. + * data: string with placeholders instead of ElementTree elements. - Returns: NanoDOM Document object with applied inline patterns. + Returns: list with ElementTree elements with applied inline patterns. """ def linkText(text): @@ -1880,7 +1886,6 @@ class Markdown: markdownTree = self._transform() - return markdownTree @@ -1898,9 +1903,16 @@ class Markdown: """ tree = self.markdownToTree(source) - + root = self.applyInlinePatterns(tree).getroot() - + + # Run the post-processors + for postprocessor in self.postprocessors: + postprocessor.stash = self.htmlStash + newRoot = postprocessor.run(root) + if newRoot: + root = newRoot + indentETree(root) xml = codecs.decode(etree.tostring(root, encoding="utf8"), "utf8") diff --git a/mdx_footnotes.py b/mdx_footnotes.py index 4464c50..b46efbb 100644 --- a/mdx_footnotes.py +++ b/mdx_footnotes.py @@ -27,6 +27,7 @@ FN_BACKLINK_TEXT = "zz1337820767766393qq" import re, markdown, random +from markdown import etree class FootnoteExtension (markdown.Extension): @@ -80,15 +81,21 @@ class FootnoteExtension (markdown.Extension): self.used_footnotes={} self.footnotes = {} - def findFootnotesPlaceholder(self, doc) : - def findFootnotePlaceholderFn(node=None, indent=0): - if node.type == 'text': - if node.value.find(self.getConfig("PLACE_MARKER")) > -1 : - return True - - fn_div_list = doc.find(findFootnotePlaceholderFn) - if fn_div_list : - return fn_div_list[0] + def findFootnotesPlaceholder(self, root): + + def finder(element): + for child in element: + if child.text: + if child.text.find(self.getConfig("PLACE_MARKER")) > -1: + return child, True + if child.tail: + if child.tail.find(self.getConfig("PLACE_MARKER")) > -1: + return (child, element), False + finder(child) + return None + + res = finder(root) + return res def setFootnote(self, id, text) : @@ -100,7 +107,7 @@ class FootnoteExtension (markdown.Extension): def makeFootnoteRefId(self, num) : return 'fnr%d%s' % (num, self.footnote_suffix) - def makeFootnotesDiv (self, doc) : + def makeFootnotesDiv (self, root) : """Creates the div with class='footnote' and populates it with the text of the footnotes. @@ -109,45 +116,39 @@ class FootnoteExtension (markdown.Extension): if not self.footnotes.keys() : return None - div = doc.createElement("div") - div.setAttribute('class', 'footnote') - hr = doc.createElement("hr") - div.appendChild(hr) - ol = doc.createElement("ol") - div.appendChild(ol) + div = etree.Element("div") + div.set('class', 'footnote') + hr = etree.SubElement(div, "hr") + ol = etree.SubElement(div, "ol") + footnotes = [(self.used_footnotes[id], id) for id in self.footnotes.keys()] footnotes.sort() for i, id in footnotes : - li = doc.createElement('li') - li.setAttribute('id', self.makeFootnoteId(i)) + li = etree.SubElement(ol, "li") + li.set("id", self.makeFootnoteId(i)) self.md._processSection(li, self.footnotes[id].split("\n"), looseList=1) - #li.appendChild(doc.createTextNode(self.footnotes[id])) - - backlink = doc.createElement('a') - backlink.setAttribute('href', '#' + self.makeFootnoteRefId(i)) - backlink.setAttribute('class', 'footnoteBackLink') - backlink.setAttribute('title', - 'Jump back to footnote %d in the text' % i) - backlink.appendChild(doc.createTextNode(FN_BACKLINK_TEXT)) - - if li.childNodes : - node = li.childNodes[-1] - if node.type == "text" : - li.appendChild(backlink) - elif node.nodeName == "p": - node.appendChild(backlink) + backlink = etree.Element("a") + backlink.set("href", "#" + self.makeFootnoteRefId(i)) + backlink.set("class", "footnoteBackLink") + backlink.set("title", + "Jump back to footnote %d in the text" % i) + backlink.text = FN_BACKLINK_TEXT + + if li.getchildren(): + node = li[-1] + if node.text: + li.append(backlink) + elif node.tag == "p": + node.append(backlink) else: - p = doc.createElement('p') - p.appendChild(backlink) - li.appendChild(p) - - ol.appendChild(li) - + p = etree.SubElement(li, "p") + p.append(backlink) + div = self.md.applyInlinePatterns(etree.ElementTree(div)).getroot() return div @@ -194,7 +195,7 @@ class FootnotePreprocessor : plain = lines[:i] detabbed, theRest = self.blockGuru.detectTabbed(lines[i+1:]) - + self.footnotes.setFootnote(id, footnote + "\n" + "\n".join(detabbed)) @@ -227,15 +228,14 @@ class FootnotePattern (markdown.Pattern) : markdown.Pattern.__init__(self, pattern) self.footnotes = footnotes - def handleMatch(self, m, doc) : - sup = doc.createElement('sup') - a = doc.createElement('a') - sup.appendChild(a) + def handleMatch(self, m) : + sup = etree.Element("sup") + a = etree.SubElement(sup, "a") id = m.group(2) num = self.footnotes.used_footnotes[id] - sup.setAttribute('id', self.footnotes.makeFootnoteRefId(num)) - a.setAttribute('href', '#' + self.footnotes.makeFootnoteId(num)) - a.appendChild(doc.createTextNode(str(num))) + sup.set('id', self.footnotes.makeFootnoteRefId(num)) + a.set('href', '#' + self.footnotes.makeFootnoteId(num)) + a.text = str(num) return sup class FootnotePostprocessor (markdown.Postprocessor): @@ -243,14 +243,25 @@ class FootnotePostprocessor (markdown.Postprocessor): def __init__ (self, footnotes) : self.footnotes = footnotes - def run(self, doc) : - footnotesDiv = self.footnotes.makeFootnotesDiv(doc) - if footnotesDiv : - fnPlaceholder = self.extension.findFootnotesPlaceholder(doc) - if fnPlaceholder : + def run(self, root): + footnotesDiv = self.footnotes.makeFootnotesDiv(root) + if footnotesDiv: + result = self.extension.findFootnotesPlaceholder(root) + + if result: + node, isText = result + if isText: + node.text = None + node.getchildren().insert(0, footnotesDiv) + else: + child, element = node + ind = element.getchildren().find(child) + element.getchildren().insert(ind + 1, footnotesDiv) + child.tail = None + fnPlaceholder.parent.replaceChild(fnPlaceholder, footnotesDiv) else : - doc.documentElement.appendChild(footnotesDiv) + root.append(footnotesDiv) class FootnoteTextPostprocessor (markdown.Postprocessor): @@ -1,4 +1,5 @@ import markdown +from markdown import etree DEFAULT_URL = "http://www.freewisdom.org/projects/python-markdown/" DEFAULT_CREATOR = "Yuri Takhteyev" @@ -18,7 +19,7 @@ month_map = { "Jan" : "01", "November" : "11", "December" : "12" } -def get_time(heading) : +def get_time(heading): heading = heading.split("-")[0] heading = heading.strip().replace(",", " ").replace(".", " ") @@ -28,7 +29,7 @@ def get_time(heading) : return rdftime(" ".join((month, date, year, "12:00:00 AM"))) -def rdftime(time) : +def rdftime(time): time = time.replace(":", " ") time = time.replace("/", " ") @@ -37,12 +38,12 @@ def rdftime(time) : time[3], time[4], time[5]) -def get_date(text) : +def get_date(text): return "date" class RssExtension (markdown.Extension): - def extendMarkdown(self, md, md_globals) : + def extendMarkdown(self, md, md_globals): self.config = { 'URL' : [DEFAULT_URL, "Main URL"], 'CREATOR' : [DEFAULT_CREATOR, "Feed creator's name"], @@ -59,62 +60,59 @@ class RssExtension (markdown.Extension): class RssPostProcessor (markdown.Postprocessor): - def __init__(self, md) : + def __init__(self, md): pass - def run (self, doc) : + def run (self, root): - oldDocElement = doc.documentElement - rss = doc.createElement("rss") - rss.setAttribute('version', '2.0') + rss = etree.Element("rss") + rss.set("version", "2.0") - doc.appendChild(rss) + channel = etree.SubElement(rss, "channel") - channel = doc.createElement("channel") - rss.appendChild(channel) for tag, text in (("title", self.ext.getConfig("TITLE")), ("link", self.ext.getConfig("URL")), ("description", None)): - channel.appendChild(doc.createElement(tag, textNode = text)) - - for child in oldDocElement.childNodes : - - if child.type == "element" : - - if child.nodeName in ["h1", "h2", "h3", "h4", "h5"] : - - heading = child.childNodes[0].value.strip() - - item = doc.createElement("item") - channel.appendChild(item) - item.appendChild(doc.createElement("link", - self.ext.getConfig("URL"))) - - item.appendChild(doc.createElement("title", heading)) - - guid = ''.join([x for x in heading if x.isalnum()]) - - guidElem = doc.createElement("guid", guid) - guidElem.setAttribute("isPermaLink", "false") - item.appendChild(guidElem) - - elif child.nodeName in ["p"] : - - description = doc.createElement("description") - - - content = "\n".join([node.toxml() - for node in child.childNodes]) - - cdata = doc.createCDATA(content) - - description.appendChild(cdata) - - if item : - item.appendChild(description) - - -def makeExtension(configs) : + + element = etree.SubElement(channel, tag) + element.text = text + + for child in root: + + + if child.tag in ["h1", "h2", "h3", "h4", "h5"] : + + heading = child.text.strip() + + item = etree.SubElement(channel, "item") + + link = etree.SubElement(item, "link") + link.text = self.ext.getConfig("URL") + + title = etree.SubElement(item, "title") + title.text = heading + + guid = ''.join([x for x in heading if x.isalnum()]) + + guidElem = etree.SubElement(item, "guid") + guidElem.text = guid + guidElem.set("isPermaLink", "false") + + elif child.tag in ["p"] : + if item: + description = etree.SubElement(item, "description") + if len(child): + content = "\n".join([etree.tostring(node) + for node in child]) + else: + content = child.text + pholder = self.stash.store("<![CDATA[ %s]]>" % content) + description.text = pholder + + return rss + + +def makeExtension(configs): return RssExtension(configs) diff --git a/tests/extensions-x-footnotes/footnote.html b/tests/extensions-x-footnotes/footnote.html index de0070d..4a844be 100644 --- a/tests/extensions-x-footnotes/footnote.html +++ b/tests/extensions-x-footnotes/footnote.html @@ -1,40 +1,42 @@ -<p>This is the body with a footnote<sup id="fnr1-5771256"><a href="#fn1-5771256">1</a></sup> or two<sup id="fnr2-5771256"><a href="#fn2-5771256">2</a></sup> or more<sup id="fnr3-5771256"><a href="#fn3-5771256">3</a></sup> <sup id="fnr4-5771256"><a href="#fn4-5771256">4</a></sup>. -</p> - -<div class="footnote"><hr/><ol> - <li id="fn1-5771256"><p>Footnote that ends with a list: -</p> -<ul> - <li> - item 1 - </li> - - <li> - item 2 - </li> -</ul> -<p><a href="#fnr1-5771256" class="footnoteBackLink" title="Jump back to footnote 1 in the text">↩</a> -</p> - - </li> - - <li id="fn2-5771256"><blockquote><p>This footnote is a blockquote. -</p> -</blockquote><p><a href="#fnr2-5771256" class="footnoteBackLink" title="Jump back to footnote 2 in the text">↩</a> -</p> - - </li> - - <li id="fn3-5771256"><p>A simple oneliner.<a href="#fnr3-5771256" class="footnoteBackLink" title="Jump back to footnote 3 in the text">↩</a> -</p> - - </li> - - <li id="fn4-5771256"><p>A footnote with multiple paragraphs. -</p> -<p>Paragraph two.<a href="#fnr4-5771256" class="footnoteBackLink" title="Jump back to footnote 4 in the text">↩</a> -</p> - - </li> -</ol> -</div>
\ No newline at end of file +<p>This is the body with a footnote<sup id="fnr1-506476047"> + <a href="#fn1-506476047">1</a> + </sup> or two<sup id="fnr2-506476047"> + <a href="#fn2-506476047">2</a> + </sup> or more<sup id="fnr3-506476047"> + <a href="#fn3-506476047">3</a> + </sup> + <sup id="fnr4-506476047"> + <a href="#fn4-506476047">4</a> + </sup>.</p> +<div class="footnote"> + <hr /> + <ol> + <li id="fn1-506476047"> + <p>Footnote that ends with a list:</p> + <ul> + <li>item 1</li> + <li>item 2</li> + </ul> + <p> + <a class="footnoteBackLink" href="#fnr1-506476047" title="Jump back to footnote 1 in the text">↩</a> + </p> + </li> + <li id="fn2-506476047"> + <blockquote> + <p>This footnote is a blockquote.</p> + </blockquote> + <p> + <a class="footnoteBackLink" href="#fnr2-506476047" title="Jump back to footnote 2 in the text">↩</a> + </p> + </li> + <li id="fn3-506476047"> + <p>A simple oneliner.<a class="footnoteBackLink" href="#fnr3-506476047" title="Jump back to footnote 3 in the text">↩</a> + </p> + </li> + <li id="fn4-506476047"> + <p>A footnote with multiple paragraphs.</p> + <p>Paragraph two.<a class="footnoteBackLink" href="#fnr4-506476047" title="Jump back to footnote 4 in the text">↩</a> + </p> + </li> + </ol> +</div> diff --git a/tests/markdown-test/angle-links-and-img.html b/tests/markdown-test/angle-links-and-img.html new file mode 100755 index 0000000..e32b6e6 --- /dev/null +++ b/tests/markdown-test/angle-links-and-img.html @@ -0,0 +1,7 @@ +<p> + <a href="simple link" title="title">link</a> + <img alt="image" src="http://example.com/image.jpg" /> + <a href="http://example.com/(()((())923)(">link</a> + <img alt="image" src="link(()))(" /> +</p> + diff --git a/tests/markdown-test/angle-links-and-img.txt b/tests/markdown-test/angle-links-and-img.txt new file mode 100755 index 0000000..1dbf404 --- /dev/null +++ b/tests/markdown-test/angle-links-and-img.txt @@ -0,0 +1,4 @@ +[link](<simple link> "title") +![image](<http://example.com/image.jpg>) +[link](<http://example.com/(()((())923)(>) +![image](<link(()))(>) diff --git a/tests/misc/blockquote-below-paragraph.html b/tests/misc/blockquote-below-paragraph.html new file mode 100755 index 0000000..5757a9a --- /dev/null +++ b/tests/misc/blockquote-below-paragraph.html @@ -0,0 +1,6 @@ +<p>Paragraph</p> +<blockquote> + <p>Block quote +Yep</p> +</blockquote> + diff --git a/tests/misc/blockquote-below-paragraph.txt b/tests/misc/blockquote-below-paragraph.txt new file mode 100755 index 0000000..0dd4d5c --- /dev/null +++ b/tests/misc/blockquote-below-paragraph.txt @@ -0,0 +1,3 @@ +Paragraph +>Block quote +>Yep diff --git a/tests/misc/html-comments.html b/tests/misc/html-comments.html new file mode 100755 index 0000000..ac08082 --- /dev/null +++ b/tests/misc/html-comments.html @@ -0,0 +1,2 @@ +<p>Here is HTML <!-- **comment** --> +and once more <p><!--comment--></p></p> diff --git a/tests/misc/html-comments.txt b/tests/misc/html-comments.txt new file mode 100755 index 0000000..cac4da5 --- /dev/null +++ b/tests/misc/html-comments.txt @@ -0,0 +1,2 @@ +Here is HTML <!-- **comment** --> +and once more <p><!--comment--></p> |