ModelMiddleware: toc_builder.py

File toc_builder.py, 5.2 KB (added by Gevara, 18 years ago)

Needed for the ReSTMiddleware example.

Line 
1"""
2Mostly stolen from www.djangoproject.com, with a slight change that involves putting
3<a>'s on headings back into the mix - TOC didn't want to work without them for me.
4"""
5
6from docutils import nodes, utils
7from docutils.core import publish_parts
8from docutils.writers import html4css1
9
10
11def build_document(input_string, source_path=None, destination_path=None,
12 input_encoding='unicode', doctitle=1, initial_header_level=1):
13 overrides = {'input_encoding': input_encoding,
14 'doctitle_xform': doctitle,
15 'initial_header_level': initial_header_level}
16 writer = DjangoHTMLWriter()
17 parts = publish_parts(
18 input_string,
19 writer=writer,
20 settings_overrides=overrides,
21 )
22 return {'html_body' : parts['html_body'], 'toc' : parts['toc']}
23
24
25
26class DjangoHTMLWriter(html4css1.Writer):
27 def __init__(self):
28 html4css1.Writer.__init__(self)
29 self.translator_class = DjangoHTMLTranslator
30
31 def translate(self):
32 # build the document
33 html4css1.Writer.translate(self)
34
35 # build the contents
36 contents = self.build_contents(self.document)
37 contents_doc = self.document.copy()
38 contents_doc.children = contents
39 contents_visitor = self.translator_class(contents_doc)
40 contents_doc.walkabout(contents_visitor)
41 self.parts['toc'] = "<ul class='toc'>%s</ul>" % ''.join(contents_visitor.fragment)
42
43 def build_contents(self, node, level=0):
44 level += 1
45 sections = []
46 i = len(node) - 1
47 while i >= 0 and isinstance(node[i], nodes.section):
48 sections.append(node[i])
49 i -= 1
50 sections.reverse()
51 entries = []
52 autonum = 0
53 depth = 4 # XXX FIXME
54 for section in sections:
55 title = section[0]
56 entrytext = title
57 try:
58 reference = nodes.reference('', '', refid=section['ids'][0], *entrytext)
59 except IndexError:
60 continue
61 ref_id = self.document.set_id(reference)
62 entry = nodes.paragraph('', '', reference)
63 item = nodes.list_item('', entry)
64 if level < depth:
65 subsects = self.build_contents(section, level)
66 item += subsects
67 entries.append(item)
68 if entries:
69 contents = nodes.bullet_list('', *entries)
70 return contents
71 else:
72 return []
73
74class DjangoHTMLTranslator(html4css1.HTMLTranslator):
75 def visit_table(self, node):
76 """Remove the damn border=1 from the standard HTML writer"""
77 self.body.append(self.starttag(node, 'table', CLASS='docutils'))
78
79 def visit_title(self, node, move_ids=1):
80 """Only 6 section levels are supported by HTML."""
81 check_id = 0
82 close_tag = '</p>\n'
83 if isinstance(node.parent, nodes.topic):
84 self.body.append(
85 self.starttag(node, 'p', '', CLASS='topic-title first'))
86 check_id = 1
87 elif isinstance(node.parent, nodes.sidebar):
88 self.body.append(
89 self.starttag(node, 'p', '', CLASS='sidebar-title'))
90 check_id = 1
91 elif isinstance(node.parent, nodes.Admonition):
92 self.body.append(
93 self.starttag(node, 'p', '', CLASS='admonition-title'))
94 check_id = 1
95 elif isinstance(node.parent, nodes.table):
96 self.body.append(
97 self.starttag(node, 'caption', ''))
98 check_id = 1
99 close_tag = '</caption>\n'
100 elif isinstance(node.parent, nodes.document):
101 self.body.append(self.starttag(node, 'h1', '', CLASS='title'))
102 self.context.append('</h1>\n')
103 self.in_document_title = len(self.body)
104 else:
105 assert isinstance(node.parent, nodes.section)
106 h_level = self.section_level + self.initial_header_level - 1
107 atts = {}
108 if (len(node.parent) >= 2 and
109 isinstance(node.parent[1], nodes.subtitle)):
110 atts['CLASS'] = 'with-subtitle'
111 self.body.append(
112 self.starttag(node, 'h%s' % h_level, '', **atts))
113 atts = {}
114 # !!! conditional to be removed in Docutils 0.5:
115 if move_ids:
116 if node.parent['ids']:
117 atts['ids'] = node.parent['ids']
118 if node.hasattr('refid'):
119 atts['class'] = 'toc-backref'
120 atts['href'] = '#' + node['refid']
121 if atts:
122 self.body.append(self.starttag({}, 'a', '', **atts))
123 self.context.append('</a></h%s>\n' % (h_level))
124 else:
125 self.context.append('</h%s>\n' % (h_level))
126 # !!! conditional to be removed in Docutils 0.5:
127 if check_id:
128 if node.parent['ids']:
129 atts={'ids': node.parent['ids']}
130 self.body.append(
131 self.starttag({}, 'a', '', **atts))
132 self.context.append('</a>' + close_tag)
133 else:
134 self.context.append(close_tag)
135
Back to Top