00001
00002 """
00003 MoinMoin - TableOfContents Macro
00004
00005 The macro works as follows: First, it renders the page using
00006 the TOCFormatter (below) to get access to the outline of the
00007 page. During the page rendering, only macros whose
00008 'generates_headings' property is set and True are rendered,
00009 most macros don't generate any headings and thus need not be
00010 executed speeding up the process considerably.
00011
00012 The generated outline is then written to the output.
00013
00014 However, this is not all. Consider included pages that include
00015 a TOC themselves! First of all, TOCs don't generate headings
00016 so we avoid recursion during the collection process. Secondly,
00017 we always keep track of which content we are in and the
00018 formatter's heading method is responsible for making all
00019 IDs they generate unique. We use the same algorithm to make
00020 the IDs unique during the TOCFormatter rendering step so that
00021 in the end we can output the same IDs and the TOC is linked
00022 correctly, even in the case of multiple nested inclusions.
00023
00024 @copyright: 2007 MoinMoin:JohannesBerg
00025 @license: GNU GPL, see COPYING for details.
00026 """
00027
00028 from MoinMoin.formatter import FormatterBase
00029 from MoinMoin.Page import Page
00030 from MoinMoin import wikiutil
00031 from MoinMoin.formatter import text_html
00032
00033
00034 Dependencies = ['time']
00035
00036
00037 class TOCFormatter(text_html.Formatter):
00038 def __init__(self, request, **kw):
00039 text_html.Formatter.__init__(self, request, **kw)
00040 self.in_heading = False
00041 self.collected_headings = request._tocfm_collected_headings
00042
00043 def _text(self, text):
00044 if self.in_heading:
00045 self.collected_headings[-1][2] += text
00046 return text
00047
00048 def startContent(self, *args, **kw):
00049 res = FormatterBase.startContent(self, *args, **kw)
00050 self.collected_headings.append([1, self.request.include_id, None])
00051 return res
00052
00053 def endContent(self):
00054 res = FormatterBase.endContent(self)
00055 self.collected_headings.append([0, self.request.include_id, None])
00056 return res
00057
00058 def heading(self, on, depth, **kw):
00059 id = kw.get('id', None)
00060 self.in_heading = on
00061 if not id is None:
00062 id = self.request._tocfm_orig_formatter.make_id_unique(id)
00063 if on:
00064 self.collected_headings.append([depth, id, u''])
00065 return ''
00066
00067
00068
00069
00070
00071
00072 def macro(self, macro_obj, name, args, markup=None):
00073 try:
00074
00075
00076 gen_headings = wikiutil.importPlugin(self.request.cfg, 'macro',
00077 name, 'generates_headings')
00078 return FormatterBase.macro(self, macro_obj, name, args, markup)
00079 except (wikiutil.PluginMissingError, wikiutil.PluginAttributeError):
00080 pass
00081 return ''
00082
00083 def _anything_return_empty(self, *args, **kw):
00084 return ''
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 def macro_TOC(macro, maxdepth=int):
00140 """
00141 Prints a table of contents.
00142
00143 maxdepth:: maximum depth the table of contents is generated for (defaults to unlimited)
00144 """
00145 if maxdepth is None:
00146 maxdepth = 99
00147
00148 pname = macro.formatter.page.page_name
00149
00150 macro.request.push_unique_ids()
00151
00152 macro.request._tocfm_collected_headings = []
00153 macro.request._tocfm_orig_formatter = macro.formatter
00154
00155 tocfm = TOCFormatter(macro.request)
00156 p = Page(macro.request, pname, formatter=tocfm, rev=macro.request.rev)
00157
00158
00159
00160 p.set_raw_body(macro.parser.raw, modified=1)
00161
00162 output = macro.request.redirectedOutput(p.send_page,
00163 content_only=True,
00164 count_hit=False,
00165 omit_footnotes=True)
00166
00167 _ = macro.request.getText
00168
00169 result = [
00170 macro.formatter.div(1, css_class="table-of-contents"),
00171 macro.formatter.paragraph(1, css_class="table-of-contents-heading"),
00172 macro.formatter.text(_('Contents')),
00173 macro.formatter.paragraph(0),
00174 ]
00175
00176
00177
00178
00179 lastlvl = 100
00180 for lvl, id, txt in macro.request._tocfm_collected_headings:
00181 if txt is None:
00182 incl_id = id
00183 continue
00184 if lvl > maxdepth or id is None:
00185 continue
00186 if lvl < lastlvl:
00187 lastlvl = lvl
00188
00189
00190 lastlvl -= 1
00191
00192 for lvl, id, txt in macro.request._tocfm_collected_headings:
00193 if txt is None:
00194 incl_id = id
00195 continue
00196 if lvl > maxdepth or id is None:
00197 continue
00198
00199
00200 macro.request.include_id = incl_id
00201
00202 need_li = lastlvl >= lvl
00203 while lastlvl > lvl:
00204 result.extend([
00205 macro.formatter.listitem(0),
00206 macro.formatter.number_list(0),
00207 ])
00208 lastlvl -= 1
00209 while lastlvl < lvl:
00210 result.extend([
00211 macro.formatter.number_list(1),
00212 macro.formatter.listitem(1),
00213 ])
00214 lastlvl += 1
00215 if need_li:
00216 result.extend([
00217 macro.formatter.listitem(0),
00218 macro.formatter.listitem(1),
00219 ])
00220 result.extend([
00221 '\n',
00222 macro.formatter.anchorlink(1, id),
00223 macro.formatter.text(txt),
00224 macro.formatter.anchorlink(0),
00225 ])
00226
00227 while lastlvl > 0:
00228 result.append(macro.formatter.listitem(0))
00229 result.append(macro.formatter.number_list(0))
00230 lastlvl -= 1
00231
00232 macro.request.pop_unique_ids()
00233
00234 result.append(macro.formatter.div(0))
00235 return ''.join(result)