Créer une table des matières avec django
À nettoyer, modifier, améliorer… Emprunté au snippet MediaWikiMarkup
Usage :
{{ object.html_text|createToc }}
Code :
```
-- coding: utf-8 --
from django.template import Library
import re
from django.template.defaultfilters import slugify, striptags
register = Library()
_headerPat = re.compile(ur"<Hh(.?)>(.?)", re.UNICODE)
_tagPat = re.compile(ur"<.*?>", re.UNICODE)
def createToc(text, extractToc=None, noToc=None):
# Get all headlines for numbering them and adding funky stuff like [edit]
# links - this is for later, but we need the number of headlines right now
matches = _headerPat.findall(text)
numMatches = len(matches)
# if there are fewer than 4 headlines in the article, do not show TOC
# unless it's been explicitly enabled.
enoughToc = (numMatches >= 3)
# headline counter
headlineCount = 0
# Ugh .. the TOC should have neat indentation levels which can be
# passed to the skin functions. These are determined here
toc = []
head = {}
sublevelCount = {}
levelCount = {}
toclevel = 0
level = 0
prevlevel = 0
toclevel = 0
prevtoclevel = 0
refers = {}
refcount = {}
wgMaxTocLevel = 5
for match in matches:
headline = match[2]
if toclevel:
prevlevel = level
prevtoclevel = toclevel
level = matches[headlineCount][0]
if enoughToc:
if level > prevlevel:
toclevel += 1
sublevelCount[toclevel] = 0
if toclevel < wgMaxTocLevel:
toc.append(u'\n<ul class="toc">')
elif level < prevlevel and toclevel > 1:
# Decrease TOC level, find level to jump to
if toclevel == 2 and level < levelCount[1]:
toclevel = 1
else:
for i in range(toclevel, 0, -1):
if levelCount[i] == level:
# Found last matching level
toclevel = i
break
elif levelCount[i] < level:
toclevel = i + 1
break
if toclevel < wgMaxTocLevel:
toc.append(u"</li>\n")
toc.append(u"</ul>\n</li>\n" * max(prevtoclevel - toclevel, 0))
else:
if toclevel < wgMaxTocLevel:
toc.append(u"</li>\n")
levelCount[toclevel] = level
# count number of headlines for each level
sublevelCount[toclevel] += 1
# The canonized header is a version of the header text safe to use for links
canonized_headline = slugify(headline)
# strip out HTML
tocline = striptags(headline)
# Save headline for section edit hint before it's escaped
headline_hint = tocline
canonized_headline = slugify(tocline)
refers[headlineCount] = canonized_headline
# count how many in assoc. array so we can track dupes in anchors
if canonized_headline not in refers:
refers[canonized_headline] = 1
else:
refers[canonized_headline] += 1
refcount[headlineCount] = refers[canonized_headline]
# Create the anchor for linking from the TOC to the section
anchor = canonized_headline;
if refcount[headlineCount] > 1:
anchor += u'_' + unicode(refcount[headlineCount])
if enoughToc:
toc.append(u'\n<li class="toclevel-')
toc.append(unicode(toclevel))
toc.append(u'"><a href="#')
toc.append(anchor)
toc.append(u'">')
toc.append(u'<span class="toctext">')
toc.append(tocline)
toc.append(u'</span></a>')
# give headline the correct <h#> tag
if headlineCount not in head:
head[headlineCount] = []
h = head[headlineCount]
h.append(u'<h')
h.append(unicode(level))
h.append(u' id="')
h.append(anchor)
h.append('">')
h.append(matches[headlineCount][1].strip())
h.append(headline.strip())
h.append(u'</h')
h.append(unicode(level))
h.append(u'>')
headlineCount += 1
if enoughToc:
if toclevel < wgMaxTocLevel:
toc.append(u"</li>\n")
toc.append(u"</ul>\n</li>\n" * max(0, toclevel - 1))
#toc.insert(0, u'<table id="toc" class="toc" summary="Contents"><tr><td><div id="toctitle"><h2>Contents</h2></div>')
toc.append(u'</ul>\n')
# split up and insert constructed headlines
if extractToc is not None:
full = []
if enoughToc :
full += toc
full = u''.join(full)
return full
else:
blocks = _headerPat.split(text)
i = 0
len_blocks = len(blocks)
full = []
while i < len_blocks:
j = i/4
full.append(blocks[i])
if enoughToc and not i :
if noToc is not None :
full += toc
toc = None
if j in head and head[j]:
full += head[j]
head[j] = None
i += 4
full = u''.join(full)
return full
"""
return text
"""
register.filter(createToc)
```