""" Table of Contents Extension for Python-Markdown * * * (c) 2008 [Jack Miller](http://codezen.org) Dependencies: * [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/) """ import markdown from markdown import etree import re class TocTreeprocessor (markdown.Treeprocessor): # Iterator wrapper to get parent and child all at once def iterparent(self, root): for parent in root.getiterator(): for child in parent: yield parent, child def run(self, doc) : div = etree.Element("div") div.attrib["class"] = "toc" last_li = None # Add title to the div if self.config["title"][0]: header = etree.SubElement(div, "span") header.attrib["class"] = "toctitle" header.text = self.config["title"][0] level = 0 list_stack=[div] header_rgx = re.compile("[Hh][123456]") # Get a list of id attributes used_ids = [] for c in doc.getiterator(): if c.attrib.has_key("id"): used_ids.append(c.attrib["id"]) for (p, c) in self.iterparent(doc): if not c.text: continue # To keep the output from screwing up the # validation by putting a
# we actually replace the
in its entirety. if c.text.find(self.config["marker"][0]) > -1: for i in range(len(p)): if p[i] == c: p[i] = div break if header_rgx.match(c.tag): tag_level = int(c.tag[-1]) # Regardless of how many levels we jumped # only one list should be created, since # empty lists containing lists are illegal. if tag_level < level: list_stack.pop() level = tag_level if tag_level > level: newlist = etree.Element("ul") if last_li: last_li.append(newlist) else: list_stack[-1].append(newlist) list_stack.append(newlist) level = tag_level # Do not override pre-existing ids if not c.attrib.has_key("id"): id = self.config["slugify"][0](c.text) if id in used_ids: ctr = 1 while "%s_%d" % (id, ctr) in used_ids: ctr += 1 id = "%s_%d" % (id, ctr) used_ids.append(id) c.attrib["id"] = id else: id = c.attrib["id"] # List item link, to be inserted into the toc div last_li = etree.Element("li") link = etree.SubElement(last_li, "a") link.text = c.text link.attrib["href"] = '#' + id if int(self.config["anchorlink"][0]): anchor = etree.SubElement(c, "a") anchor.text = c.text anchor.attrib["href"] = "#" + id anchor.attrib["class"] = "toclink" c.text = "" list_stack[-1].append(last_li) class TocExtension (markdown.Extension): def __init__(self, configs): self.config = { "marker" : ["[TOC]", "Text to find and replace with Table of Contents -" "Defaults to \"[TOC]\""], "slugify" : [self.slugify, "Function to generate anchors based on header text-" "Defaults to a built in slugify function."], "title" : [None, "Title to insert into TOC