Attachment 'TableOfContents-1.9.3.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     try:
 141         mindepth = int(macro.request.getPragma('section-numbers', 1))
 142     except (ValueError, TypeError):
 143         mindepth = 1
 144 
 145     if maxdepth is None:
 146         maxdepth = 99
 147 
 148     pname = macro.formatter.page.page_name
 149 
 150     macro.request.uid_generator.push()
 151 
 152     macro.request._tocfm_collected_headings = []
 153     macro.request._tocfm_orig_formatter = macro.formatter
 154 
 155     tocfm = TOCFormatter(macro.request)
 156     p = Page(macro.request, pname, formatter=tocfm, rev=macro.request.rev)
 157 
 158     # this is so we get a correctly updated TOC if we just preview in the editor -
 159     # the new content is not stored on disk yet, but available as macro.parser.raw:
 160     p.set_raw_body(macro.parser.raw, modified=1)
 161 
 162     output = macro.request.redirectedOutput(p.send_page,
 163                                             content_only=True,
 164                                             count_hit=False,
 165                                             omit_footnotes=True)
 166 
 167     _ = macro.request.getText
 168 
 169     result = [
 170         macro.formatter.div(1, css_class="table-of-contents", id="toc"),
 171         macro.formatter.paragraph(1, css_class="table-of-contents-heading"),
 172         macro.formatter.text(_('Contents')),
 173         macro.formatter.paragraph(0),
 174     ]
 175 
 176 
 177     # find smallest used level and use that as the outer-most indentation,
 178     # to fix pages like HelpOnMacros that only use h2 and lower levels.
 179     lastlvl = 100
 180     for lvl, id, txt in macro.request._tocfm_collected_headings:
 181         if txt is None:
 182             incl_id = id
 183             continue
 184         if lvl > maxdepth or id is None:
 185             continue
 186         if lvl < lastlvl:
 187             lastlvl = lvl
 188 
 189     # headings are 1-based, lastlvl needs to be one less so that one is closed
 190     # variables needed to provide with nice, leveled prefixes
 191     # (part of the hierarhical TOC prefix code) 
 192     levelnumbers = None
 193     levelnumbers = {}
 194     counter = 1
 195     lowest_lvl = None
 196     lastlvl -= 1
 197 
 198     for lvl, id, txt in macro.request._tocfm_collected_headings:
 199         if txt is None:
 200             incl_id = id
 201             continue
 202         if lvl > maxdepth or id is None:
 203             continue
 204 
 205 
 206         # determine the lowest level available 
 207         # (part of the hierarhical TOC prefix)
 208         if lowest_lvl is None or lowest_lvl > lvl:
 209                 lowest_lvl = lvl
 210 
 211         # determine number prefix for the TOC line 
 212         # (part of the hierarhical TOC prefix) 
 213         if lvl > lastlvl:
 214                 levelnumbers[lastlvl] = counter
 215                 counter = 0
 216         elif lvl < lastlvl:
 217                 counter = levelnumbers[lvl]
 218         counter = counter + 1
 219         levelnumbers[lvl] = counter
 220    
 221         line_number = ""
 222         for i in range(lowest_lvl, lvl):
 223                 line_number = line_number + str(levelnumbers[i]) + "."
 224         line_number = line_number + str(counter) + "."
 225 
 226         # will be reset by pop_unique_ids below
 227         macro.request.uid_generator.include_id = incl_id
 228 
 229         need_li = lastlvl >= lvl
 230         while lastlvl > lvl:
 231             result.extend([
 232                 macro.formatter.listitem(0),
 233                 macro.formatter.bullet_list(0),
 234             ])
 235             lastlvl -= 1
 236         while lastlvl < lvl:
 237             result.extend([
 238                 macro.formatter.bullet_list(1, type="none"),
 239                 macro.formatter.listitem(1),
 240             ])
 241             lastlvl += 1
 242         if need_li:
 243             result.extend([
 244                 macro.formatter.listitem(0),
 245                 macro.formatter.listitem(1),
 246             ])
 247         result.extend([
 248             '\n',
 249             macro.formatter.anchorlink(1, id),
 250             macro.formatter.text(line_number + " " + txt),
 251             macro.formatter.anchorlink(0),
 252         ])
 253 
 254     while lastlvl > 0:
 255         result.append(macro.formatter.listitem(0))
 256         result.append(macro.formatter.bullet_list(0))
 257         lastlvl -= 1
 258 
 259     macro.request.uid_generator.pop()
 260 
 261     result.append(macro.formatter.div(0))
 262     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.
  • [get | view] (2009-03-27 02:31:52, 8.1 KB) [[attachment:TableOfContents-1.8.py]]
  • [get | view] (2009-03-27 02:27:46, 4.2 KB) [[attachment:TableOfContents-1.8.py.patch]]
  • [get | view] (2010-09-01 17:02:37, 9.0 KB) [[attachment:TableOfContents-1.9.3.py]]
  • [get | view] (2010-09-01 17:02:11, 3.2 KB) [[attachment:TableOfContents-1.9.3.py.patch]]
  • [get | view] (2009-03-27 02:31:20, 8.9 KB) [[attachment:TableOfContents-1.9beta2.py]]
  • [get | view] (2009-03-27 02:28:13, 2.8 KB) [[attachment:TableOfContents-1.9beta2.py.patch]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.