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.
  • [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.