Attachment 'TableOfContents.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.include_id, None])
50 return res
51
52 def endContent(self):
53 res = FormatterBase.endContent(self)
54 self.collected_headings.append([0, self.request.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.push_unique_ids()
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 output = macro.request.redirectedOutput(p.send_page,
153 content_only=True,
154 count_hit=False,
155 omit_footnotes=True)
156
157 _ = macro.request.getText
158
159 result = [
160 macro.formatter.div(1, css_class="table-of-contents"),
161 macro.formatter.paragraph(1, css_class="table-of-contents-heading"),
162 macro.formatter.text(_('Contents')),
163 macro.formatter.paragraph(0),
164 ]
165
166 lastlvl = 0
167
168 # variables needed to provide with nice, leveled prefixes
169 levelnumbers = None
170 levelnumbers = {}
171 counter = 1
172
173 for lvl, id, txt in macro.request._tocfm_collected_headings:
174 if txt is None:
175 incl_id = id
176 continue
177 if lvl > maxdepth or id is None:
178 continue
179
180 # determine number prefix for the TOC line
181 if lvl > lastlvl:
182 levelnumbers[lastlvl] = counter
183 counter = 0
184 elif lvl < lastlvl:
185 counter = levelnumbers[lvl]
186
187 counter = counter + 1
188 levelnumbers[lvl] = counter
189
190 line_number = ""
191 for i in range(1, lvl):
192 line_number = line_number + str(levelnumbers[i]) + "."
193 line_number = line_number + str(counter) + "."
194
195
196 # will be reset by pop_unique_ids below
197 macro.request.include_id = incl_id
198
199 need_li = lastlvl >= lvl
200 while lastlvl > lvl:
201 result.extend([
202 macro.formatter.listitem(0),
203 macro.formatter.bullet_list(0),
204 ])
205 lastlvl -= 1
206 while lastlvl < lvl:
207 result.extend([
208 macro.formatter.bullet_list(1, type="none"),
209 macro.formatter.listitem(1),
210 ])
211 lastlvl += 1
212 if need_li:
213 result.extend([
214 macro.formatter.listitem(0),
215 macro.formatter.listitem(1),
216 ])
217 result.extend([
218 '\n',
219 macro.formatter.anchorlink(1, id),
220 macro.formatter.text(line_number + " " + txt),
221 macro.formatter.anchorlink(0),
222 ])
223
224 while lastlvl > 0:
225 result.append(macro.formatter.listitem(0))
226 result.append(macro.formatter.bullet_list(0))
227 lastlvl -= 1
228
229 macro.request.pop_unique_ids()
230
231 result.append(macro.formatter.div(0))
232 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.