Attachment 'TableOfContents.py'

Download

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

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