Attachment 'TableOfContents-1.9beta2.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 MoinMoin - TableOfContents Macro
4
5 The macro works as follows: First, it renders the page using
6 the TOCFormatter (below) to get access to the outline of the
7 page. During the page rendering, only macros whose
8 'generates_headings' property is set and True are rendered,
9 most macros don't generate any headings and thus need not be
10 executed speeding up the process considerably.
11
12 The generated outline is then written to the output.
13
14 However, this is not all. Consider included pages that include
15 a TOC themselves! First of all, TOCs don't generate headings
16 so we avoid recursion during the collection process. Secondly,
17 we always keep track of which content we are in and the
18 formatter's heading method is responsible for making all
19 IDs they generate unique. We use the same algorithm to make
20 the IDs unique during the TOCFormatter rendering step so that
21 in the end we can output the same IDs and the TOC is linked
22 correctly, even in the case of multiple nested inclusions.
23
24 @copyright: 2007 MoinMoin:JohannesBerg
25 @license: GNU GPL, see COPYING for details.
26 """
27
28 from MoinMoin.formatter import FormatterBase
29 from MoinMoin.Page import Page
30 from MoinMoin import wikiutil
31
32
33 # cannot be cached because of TOCs in included pages
34 Dependencies = ['time']
35
36 class TOCFormatter(FormatterBase):
37 def __init__(self, request, **kw):
38 FormatterBase.__init__(self, request, **kw)
39 self.in_heading = False
40 self.collected_headings = request._tocfm_collected_headings
41
42 def _text(self, text):
43 if self.in_heading:
44 self.collected_headings[-1][2] += text
45 return text
46
47 def startContent(self, *args, **kw):
48 res = FormatterBase.startContent(self, *args, **kw)
49 self.collected_headings.append([1, self.request.uid_generator.include_id, None])
50 return res
51
52 def endContent(self):
53 res = FormatterBase.endContent(self)
54 self.collected_headings.append([0, self.request.uid_generator.include_id, None])
55 return res
56
57 def heading(self, on, depth, **kw):
58 id = kw.get('id', None)
59 self.in_heading = on
60 if not id is None:
61 id = self.request._tocfm_orig_formatter.make_id_unique(id)
62 if on:
63 self.collected_headings.append([depth, id, u''])
64 return ''
65
66 def macro(self, macro_obj, name, args, markup=None):
67 try:
68 # plugins that are defined in the macro class itself
69 # can't generate headings this way, but that's fine
70 gen_headings = wikiutil.importPlugin(self.request.cfg, 'macro',
71 name, 'generates_headings')
72 if gen_headings:
73 return FormatterBase.macro(self, macro_obj, name, args, markup)
74 except (wikiutil.PluginMissingError, wikiutil.PluginAttributeError):
75 pass
76 return ''
77
78 def _anything_return_empty(self, *args, **kw):
79 return ''
80
81 lang = _anything_return_empty
82 sysmsg = _anything_return_empty
83 startDocument = _anything_return_empty
84 endDocument = _anything_return_empty
85 pagelink = _anything_return_empty
86 interwikilink = _anything_return_empty
87 url = _anything_return_empty
88 attachment_link = _anything_return_empty
89 attachment_image = _anything_return_empty
90 attachment_drawing = _anything_return_empty
91 attachment_inlined = _anything_return_empty
92 anchordef = _anything_return_empty
93 line_anchordef = _anything_return_empty
94 anchorlink = _anything_return_empty
95 line_anchorlink = _anything_return_empty
96 image = _anything_return_empty
97 smiley = _anything_return_empty
98 nowikiword = _anything_return_empty
99 strong = _anything_return_empty
100 emphasis = _anything_return_empty
101 underline = _anything_return_empty
102 highlight = _anything_return_empty
103 sup = _anything_return_empty
104 sub = _anything_return_empty
105 strike = _anything_return_empty
106 code = _anything_return_empty
107 preformatted = _anything_return_empty
108 small = _anything_return_empty
109 big = _anything_return_empty
110 code_area = _anything_return_empty
111 code_line = _anything_return_empty
112 code_token = _anything_return_empty
113 linebreak = _anything_return_empty
114 paragraph = _anything_return_empty
115 rule = _anything_return_empty
116 icon = _anything_return_empty
117 number_list = _anything_return_empty
118 bullet_list = _anything_return_empty
119 listitem = _anything_return_empty
120 definition_list = _anything_return_empty
121 definition_term = _anything_return_empty
122 definition_desc = _anything_return_empty
123 table = _anything_return_empty
124 table_row = _anything_return_empty
125 table_cell = _anything_return_empty
126 _get_bang_args = _anything_return_empty
127 parser = _anything_return_empty
128 div = _anything_return_empty
129 span = _anything_return_empty
130 escapedText = _anything_return_empty
131 comment = _anything_return_empty
132 transclusion = _anything_return_empty
133
134 def macro_TableOfContents(macro, maxdepth=int):
135 """
136 Prints a table of contents.
137
138 maxdepth:: maximum depth the table of contents is generated for (defaults to unlimited)
139 """
140 if maxdepth is None:
141 maxdepth = 99
142
143 pname = macro.formatter.page.page_name
144
145 macro.request.uid_generator.push()
146
147 macro.request._tocfm_collected_headings = []
148 macro.request._tocfm_orig_formatter = macro.formatter
149
150 tocfm = TOCFormatter(macro.request)
151 p = Page(macro.request, pname, formatter=tocfm, rev=macro.request.rev)
152
153 # this is so we get a correctly updated TOC if we just preview in the editor -
154 # the new content is not stored on disk yet, but available as macro.parser.raw:
155 p.set_raw_body(macro.parser.raw, modified=1)
156
157 output = macro.request.redirectedOutput(p.send_page,
158 content_only=True,
159 count_hit=False,
160 omit_footnotes=True)
161
162 _ = macro.request.getText
163
164 result = [
165 macro.formatter.div(1, css_class="table-of-contents", id="toc"),
166 macro.formatter.paragraph(1, css_class="table-of-contents-heading"),
167 macro.formatter.text(_('Contents')),
168 macro.formatter.paragraph(0),
169 ]
170
171
172 # find smallest used level and use that as the outer-most indentation,
173 # to fix pages like HelpOnMacros that only use h2 and lower levels.
174 lastlvl = 100
175 for lvl, id, txt in macro.request._tocfm_collected_headings:
176 if txt is None:
177 incl_id = id
178 continue
179 if lvl > maxdepth or id is None:
180 continue
181 if lvl < lastlvl:
182 lastlvl = lvl
183
184 # headings are 1-based, lastlvl needs to be one less so that one is closed
185 lastlvl -= 1
186
187 # variables needed to provide with nice, leveled prefixes
188 # (part of the hierarhical TOC prefix code)
189 levelnumbers = None
190 levelnumbers = {}
191 counter = 1
192 lowest_lvl = None
193
194 for lvl, id, txt in macro.request._tocfm_collected_headings:
195 if txt is None:
196 incl_id = id
197 continue
198 if lvl > maxdepth or id is None:
199 continue
200
201 # determine the lowest level available
202 # (part of the hierarhical TOC prefix)
203 if lowest_lvl is None or lowest_lvl > lvl:
204 lowest_lvl = lvl
205
206 # determine number prefix for the TOC line
207 # (part of the hierarhical TOC prefix)
208 if lvl > lastlvl:
209 levelnumbers[lastlvl] = counter
210 counter = 0
211 elif lvl < lastlvl:
212 counter = levelnumbers[lvl]
213 counter = counter + 1
214 levelnumbers[lvl] = counter
215
216 line_number = ""
217 for i in range(lowest_lvl, lvl):
218 line_number = line_number + str(levelnumbers[i]) + "."
219 line_number = line_number + str(counter) + "."
220
221
222 # will be reset by pop_unique_ids below
223 macro.request.include_id = incl_id
224
225 need_li = lastlvl >= lvl
226 while lastlvl > lvl:
227 result.extend([
228 macro.formatter.listitem(0),
229 macro.formatter.bullet_list(0),
230 ])
231 lastlvl -= 1
232 while lastlvl < lvl:
233 result.extend([
234 macro.formatter.bullet_list(1, type="none"),
235 macro.formatter.listitem(1),
236 ])
237 lastlvl += 1
238 if need_li:
239 result.extend([
240 macro.formatter.listitem(0),
241 macro.formatter.listitem(1),
242 ])
243 result.extend([
244 '\n',
245 macro.formatter.anchorlink(1, id),
246 macro.formatter.text(line_number + " " + txt),
247 macro.formatter.anchorlink(0),
248 ])
249
250 while lastlvl > 0:
251 result.append(macro.formatter.listitem(0))
252 result.append(macro.formatter.bullet_list(0))
253 lastlvl -= 1
254
255 macro.request.uid_generator.pop()
256
257 result.append(macro.formatter.div(0))
258 return ''.join(result)
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.