Attachment 'explorer_-_categories_update_debug.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     MoinMoin - explorer theme
   4     
   5     @copyright: 2007 Wolfgang Fischer
   6     @license: GNU GPL, see COPYING for details.
   7 """
   8 
   9 from MoinMoin.theme import ThemeBase
  10 
  11 class Theme(ThemeBase):
  12     from MoinMoin.action import AttachFile
  13     from MoinMoin import i18n, wikiutil
  14     from MoinMoin.Page import Page
  15 
  16     name = "explorer"
  17 
  18     
  19     # ========================================
  20     # Iconbar and UI text definition
  21     # ========================================
  22     # fake _ function to get gettext recognize those texts:
  23     _ = lambda x: x
  24 
  25     ui_text = { 'splitbar_title' : _('Drag to resize. Double click to show or hide tree.') }
  26 
  27     iconbar_list = ['home', 'changes', 'separator', 'login', 'separator', 'showcomments', 'subscribe', 'quicklink', 'separator', 'edit', 'rename', 'copy', 'load', 'save', 'delete', 'separator', 'attach', 'spellcheck', 'diff', 'info', 'print', 'raw', 'refresh', 'separator', 'help', 'separator', 'find', 'likepages', 'sitemap', 'separator', 'searchform']
  28 
  29     button_table = {
  30         # key           page, query dict, title, icon-key
  31         'separator':   ("", {}, _(""), "separator"),
  32         'searchform':  ("", {}, _(""), "searchform"),
  33         'login':       ("", {'action': 'login'}, _("Login"), "login"),
  34         'logout':      ("", {'action': 'logout', 'logout': 'logout'}, _("Logout"), "logout"),
  35         'preferences': ("", {'action': 'userprefs'}, _("Preferences"), "preferences"),
  36         'showcomments':  ("", {}, _("Comments"), "showcomments"),
  37         'hidecomments':  ("", {}, _("Comments"), "hidecomments"),
  38         'subscribe':   ("", {'action': 'subscribe'}, _("Subscribe"), "subscribe"),
  39         'unsubscribe': ("", {'action': 'unsubscribe'}, _("UnSubscribe"), "unsubscribe"),
  40         'quicklink':   ("", {'action': 'quicklink'}, _("Add Link"), "quicklink"),
  41         'unquicklink': ("", {'action': 'quickunlink'}, _("Remove Link"), "unquicklink"),
  42         'home':        ("%(page_front_page)s", {}, _("Home"), "home"),
  43         'find':        ("%(page_find_page)s", {}, "%(page_find_page)s", "find"),
  44         'changes':     ("RecentChanges", {}, "RecentChanges", "changes"),
  45         'likepages':   ("", {'action': 'LikePages'}, _("Like Pages"), "likepages"),
  46         'sitemap':     ("", {'action': 'LocalSiteMap'}, _("Local Site Map"), "sitemap"),
  47         'edit_text':   ("", {'action': 'edit', 'editor': 'text'}, _("Edit (Text)"), "edit_text"),
  48         'edit_gui':    ("", {'action': 'edit', 'editor': 'gui'}, _("Edit (GUI)"), "edit_gui"),
  49         'attach':      ("", {'action': 'AttachFile'}, _("Attachments"), "attach"),
  50         'spellcheck':  ("", {'action': 'SpellCheck'}, _("Check Spelling"), "spellcheck"),
  51         'rename':      ("", {'action': 'RenamePage'}, _("Rename Page"), "rename"),
  52         'delete':      ("", {'action': 'DeletePage'}, _("Delete Page"), "delete"),
  53         'copy':        ("", {'action': 'CopyPage'}, _("Copy Page"), "copy"),
  54         'load':        ("", {'action': 'Load'}, _("Load Page"), "load"),
  55         'save':        ("", {'action': 'Save'}, _("Save Page"), "save"),
  56         'diff':        ("", {'action': 'diff'}, _("Diffs"), "diff"),
  57         'info':        ("", {'action': 'info'}, _("Info"), "info"),
  58         'print':       ("", {'action': 'print'}, _("Print View"), "print"),
  59         'raw':         ("", {'action': 'raw'}, _("Raw Text"), "raw"),
  60         'refresh':     ("", {'action': 'refresh'}, _("Delete Cache"), "refresh"),
  61         'xml':         ("", {'action': 'format', 'mimetype': 'text/xml'}, _("XML"), "xml"),
  62         'docbook':     ("", {'action': 'RenderAsDocbook'}, _("Render as Docbook"), "docbook"),
  63         'help':        ("%(page_help_contents)s", {}, "%(page_help_contents)s", "help"),
  64         'subscribeuser': ("", {'action': 'SubscribeUser'}, _("Subscribe User"), "subscribeuser"),
  65         'despam':      ("", {'action': 'Despam'}, _("Remove Spam"), "despam"),
  66         'packagepages':  ("", {'action': 'PackagePages'}, _("Package Pages"), "packagepages")
  67         }
  68 
  69 
  70     icons_updates = {
  71         # key         alt                        icon filename              w   h
  72         # ------------------------------------------------------------------------
  73         # iconbar
  74         'login':      (_("Login"),               "moin-login.png",          16, 16),
  75         'logout':     (_("Logout"),              "moin-login.png",          16, 16),
  76         'preferences':   (_("Preferences"),      "moin-preferences.png",    16, 16),
  77         'showcomments':  (_("Comments"),         "moin-comments.png",       16, 16),
  78         'hidecomments':  (_("Comments"),         "moin-comments.png",       16, 16),
  79         'subscribe':  (_("Subscribe"),           "moin-subscribe.png",      16, 16),
  80         'unsubscribe':(_("Unsubscribe"),         "moin-subscribe.png",      16, 16),
  81         'quicklink':  (_("Add Link"),            "moin-quicklink.png",      16, 16),
  82         'unquicklink':  (_("Remove Link"),       "moin-quicklink.png",      16, 16),
  83         'home':       (_("Home"),                "moin-home.png",           16, 16),
  84         'find':       ("%(page_find_page)s",     "moin-search.png",         16, 16),
  85         'likepages':  (_("Like Pages"),          "moin-likepages.png",      16, 16),
  86         'sitemap':    (_("Local Site Map"),      "moin-sitemap.png",        16, 16),
  87         'changes':    (_("RecentChanges"),       "moin-rc.png",             16, 16),
  88         'edit':       (_("Edit"),                "moin-edit-text.png",      16, 16),
  89         'edit_text':  (_("Edit (Text)"),         "moin-edit-text.png",      16, 16),
  90         'edit_text_disabled':  (_("Edit (Text)"),         "moin-edit-text-disabled.png",      16, 16),
  91         'edit_gui':   (_("Edit (GUI)"),          "moin-edit-gui.png",       16, 16),
  92         'edit_gui_disabled':   (_("Edit (GUI)"),          "moin-edit-gui-disabled.png",       16, 16),
  93         'attach':     (_("Attachments"),         "moin-attach.png",         16, 16),
  94         'spellcheck': (_("Check Spelling"),      "moin-check-spelling.png", 16, 16),
  95         'rename':     (_("Rename Page"),         "moin-rename.png",         16, 16),
  96         'rename_disabled':     (_("Rename Page"), "moin-rename-disabled.png", 16, 16),
  97         'copy':       (_("Copy Page"),           "moin-copy.png",           16, 16),
  98         'copy_disabled': (_("Copy Page"),        "moin-copy-disabled.png",  16, 16),
  99         'load':       (_("Load Page"),           "moin-load.png",           16, 16),
 100         'load_disabled': (_("Load Page"),        "moin-load-disabled.png",           16, 16),
 101         'save':       (_("Save Page"),           "moin-save.png",           16, 16),
 102         'save_disabled':       (_("Save Page"),           "moin-save-disabled.png",           16, 16),
 103         'delete':     (_("Delete Page"),         "moin-delete.png",         16, 16),
 104         'delete_disabled':     (_("Delete Page"),         "moin-delete-disabled.png",         16, 16),
 105         'diff':       (_("Diffs"),               "moin-diff.png",           16, 16),
 106         'info':       (_("Info"),                "moin-info.png",           16, 16),
 107         'print':      (_("Print View"),          "moin-print.png",          16, 16),
 108         'raw':        (_("Raw Text"),            "moin-raw.png",            16, 16),
 109         'refresh':    (_("Delete Cache"),        "moin-refresh.png",        16, 16),
 110         'xml':        (_("XML"),                 "moin-xml.png",            16, 16),
 111         'docbook':    (_("Render as Docbook"),   "moin-docbook.png",        16, 16),
 112         'help':       ("%(page_help_contents)s", "moin-help.png",           16, 16),
 113         'subscribeuser': (_("Subscribe User"),   "moin-subscribe.png",      16, 16),
 114         'view':       (_("View"),                "moin-show.png",           16, 16),
 115         'up':         (_("Up"),                  "moin-parent.png",         16, 16),
 116         'mypages':    (_("My Pages"),            "moin-mypages.png",        16, 16),
 117         'despam':     (_("Remove Spam"),         "moin-despam.png",         16, 16),
 118         'packagepages':  (_("Package Pages"),    "moin-package.png",        16, 16),
 119         # RecentChanges
 120         'deleted':    (_("[DELETED]"),           "moin-delete.png",         16, 16),
 121         'updated':    (_("[UPDATED]"),           "moin-edit-text.png",      16, 16),
 122         'renamed':    (_("[RENAMED]"),           "moin-rename.png",         16, 16),
 123         'conflict':   (_("[CONFLICT]"),          "moin-conflict.png",       16, 16),
 124         'new':        (_("[NEW]"),               "moin-new.png",            16, 16),
 125         'diffrc':     (_("[DIFF]"),              "moin-diff.png",           16, 16),
 126         }
 127    
 128     del _
 129 
 130 
 131     def __init__(self, request):
 132         """ Initialize the explorer theme
 133         
 134         @param request: the request object
 135         """
 136         ThemeBase.__init__(self, request)
 137         # Get the cookies
 138         self.cookies = request.parse_cookie()
 139 
 140         self.icons.update(self.icons_updates)
 141 
 142         cfg = self.cfg
 143         if hasattr(cfg, 'explorer_site_mode'):
 144             self.site_mode = cfg.explorer_site_mode
 145         else:  # the default is false if the request goes to localhost, otherwise true
 146             self.site_mode = not request.http_host.startswith('localhost')
 147         if hasattr(cfg, 'explorer_iconbar'):  # Get admin configured iconbar
 148             self.iconbar_list = cfg.explorer_iconbar
 149         if hasattr(cfg, 'explorer_default_sidebar_width'):
 150             # Get admin configured default tree width
 151             self.default_sidebar_width = cfg.explorer_default_sidebar_width
 152         else:
 153             self.default_sidebar_width = "20em"
 154         if hasattr(cfg, 'explorer_page_header'):
 155             # Get admin configured page_header status
 156             self.page_header = cfg.explorer_page_header
 157         else:  # the default is true <=> theme is in desktop mode
 158             self.page_header = not self.site_mode
 159         if hasattr(cfg, 'explorer_attachments'):
 160             # Get admin configured attachments status
 161             self.attachments = cfg.explorer_attachments
 162         else:  # the default is true <=> theme is in desktop mode
 163             self.attachments = not self.site_mode
 164         if not self.site_mode:
 165             # Add additional stylesheet for desktop mode
 166             self.stylesheets += (('screen', 'desktop'),)
 167 
 168 
 169     def header(self, d, **kw):
 170         """ Assemble the wiki header
 171         
 172         @param d: parameter dictionary
 173         @rtype: unicode
 174         @return: page header html
 175         """
 176         # Init the wiki tree
 177         self.wiki_tree = WikiTree(self, d)
 178         self.page = d['page']
 179         self.page_name = d['page_name']
 180 
 181         # Initialize default settings
 182         self.sidebar_width, main_height, page_content_height = self.default_sidebar_width, "auto", "auto"
 183 
 184         # Apply setings from cookie
 185         if self.cookies:
 186             if self.cookies.has_key('explorer_hide_sidebar'):
 187                 self.sidebar_width = "0px"
 188             elif self.cookies.has_key('explorer_sidebar_width'):
 189                 self.sidebar_width = self.cookies['explorer_sidebar_width'].value
 190             if self.cookies.has_key('explorer_main_height'):
 191                 main_height = self.cookies['explorer_main_height'].value
 192             if self.cookies.has_key('explorer_page_content_height'):
 193                 page_content_height = self.cookies['explorer_page_content_height'].value
 194 
 195         is_ltr = self.i18n.getDirection(self.request.lang) == "ltr"
 196 
 197         header_html = page_header_html = page_header_html = []
 198         page_title_html = attachment_html = u''
 199         if self.site_mode:
 200             # Build site header
 201             header_html = [
 202                 u'<div id="header">',
 203                 u'<div></div>',  # IE Fix: Logo and searchform float over the header
 204                 self.logo(),
 205                 u'<span id="searchform_container">',  # IE 6 Fix: To enable searchform to float
 206                 self.searchform(d),
 207                 u'</span>',
 208                 self.username(d),
 209                 u'<div style="clear:both;"></div>',  # IE Fix: Navibar tabs move at hover
 210                 self.navibar(d),
 211                 u'</div>',
 212                 u'<div id="pageline"><hr style="display:none;"></div>',
 213             ]
 214         if self.attachments:
 215             # Build attachment list
 216             attachment_html = self.attachment_list()
 217         if self.page_header:
 218             # Build wiki page header
 219             page_header_html = [
 220                 u'<div id="page_header">',
 221                 self.wiki_tree.page_summary_html(),
 222                 self.wiki_tree.parents_html(),
 223                 self.interwiki(d),
 224                 self.title(d),
 225                 self.page_header_info(self.page),
 226                 u'<div class="bottom"></div>'
 227                 u'</div>',  # page_header
 228             ]
 229         else:
 230             # Build wiki page title
 231             page_title_html = [
 232                 u'<div id="page_title">',
 233                 self.interwiki(d),
 234                 self.title(d),
 235                 u'</div>',  # page_title
 236             ]
 237 
 238         html = [
 239             # Pre header custom html
 240             self.emit_custom_html(self.cfg.page_header1),
 241             u'',
 242             u'\n'.join(header_html),
 243             self.trail(d),
 244             [self.iconbar(d), u''][self.site_mode],
 245             u'',
 246             # u'<div id="main" style="height:%s;">' % main_height,
 247             u'<div id="main">',
 248             u'',
 249             u'<div id="page_area">',
 250             u'',
 251             [u'', self.iconbar(d)][self.site_mode],
 252             u'\n'.join(page_header_html),
 253             self.msg(d),
 254             u'',
 255             # u'<div id="page_content" style="height:%s;">' % page_content_height,
 256             u'<div id="page_content">',
 257             attachment_html,
 258             u'\n'.join(page_title_html),
 259 
 260             # Post header custom html (not recommended)
 261             self.emit_custom_html(self.cfg.page_header2),
 262             
 263             # Start of page
 264             self.startPage(),
 265         ]
 266         return u'\n'.join(html)
 267         
 268         
 269     def editorheader(self, d, **kw):
 270         """ Assemble wiki header for editor
 271         
 272         @param d: parameter dictionary
 273         @rtype: unicode
 274         @return: page header html
 275         """
 276         return self.header(d, **kw)
 277 
 278         
 279     def footer(self, d, **keywords):
 280         """ Assemble wiki footer
 281         
 282         @param d: parameter dictionary
 283         @keyword ...:...
 284         @rtype: unicode
 285         @return: page footer html
 286         """
 287         # Uncomment to display the cookies (for test purpose)
 288         # cookies = ['<li>%s</li>' % self.cookies[i] for i in self.cookies]
 289         wiki_tree_html = self.wiki_tree.wiki_tree_html()
 290         _ = self.ui_text
 291         pageinfo_html = [self.pageinfo(self.page), u''][self.page_header]
 292 
 293         html = [
 294             pageinfo_html,
 295             # End of page
 296             self.endPage(),
 297             
 298             # Pre footer custom html (not recommended!)
 299             self.emit_custom_html(self.cfg.page_footer1),
 300 
 301             u'</div>',  # page_content
 302             u'</div>',  # page
 303             u'',
 304             u'<div id="splitbar" title="%s"></div>' % _['splitbar_title'],
 305             u'',
 306             u'<div id="sidebar" style="width:%s;">' % self.sidebar_width,
 307             wiki_tree_html,
 308             u'</div>',  # sidebar
 309             u'</div>',  # main
 310             u'',
 311             # Footer
 312             u'<div id="footer">',
 313             self.wiki_tree.wiki_summary_html(),
 314             self.credits(d),
 315             self.showversion(d, **keywords),
 316             # Uncomment to display the cookies (for test purpose)
 317             # u'<ul id="cookies">\n%s\n</ul>\n' % ''.join(cookies),
 318             u'</div>',
 319             u'',
 320             # Post footer custom html
 321             self.emit_custom_html(self.cfg.page_footer2),
 322             ]
 323         return u'\n'.join(html)
 324 
 325 
 326     
 327     # =============================
 328     # Iconbar
 329     # =============================
 330 
 331     def iconbar(self, d):
 332         """
 333         Assemble the iconbar
 334         
 335         @param d: parameter dictionary
 336         @rtype: string
 337         @return: iconbar html
 338         """
 339         request = self.request
 340         available_actions = request.getAvailableActions(self.page)
 341         iconbar = []
 342         iconbar.append('<div id="iconbar">')
 343         iconbar.append('<ul class="iconbar">')
 344         icons = self.iconbar_list[:]
 345         for icon in icons:
 346             if icon == "separator":
 347                 if iconbar[-1] != '<ul class="iconbar">':
 348                     iconbar.append('</ul>')
 349                     iconbar.append('<ul class="iconbar">')
 350             elif icon == "home" and self.site_mode:
 351                 # Don't include the home icon in site mode
 352                 icon = "invalid"
 353             elif icon == "edit":
 354                 iconbar.append(self.editor_link(d))
 355             elif icon == "rename":
 356                 if (self.page.isWritable()
 357                     and self.request.user.may.read(self.page_name)
 358                     and self.request.user.may.write(self.page_name)
 359                     and self.request.user.may.delete(self.page_name)):
 360                     iconbar.append('<li>%s</li>' % self.make_iconlink(icon, d))
 361                 else:
 362                     iconbar.append('<li>%s</li>' % self.make_icon('rename_disabled', d))
 363             elif icon == "delete":
 364                 if (self.page.isWritable()
 365                     and self.request.user.may.delete(self.page_name)):
 366                     iconbar.append('<li>%s</li>' % self.make_iconlink(icon, d))
 367                 else:
 368                     iconbar.append('<li>%s</li>' % self.make_icon('delete_disabled', d))
 369             elif icon == "copy":
 370                 if self.request.user.may.read(self.page_name):
 371                     iconbar.append('<li>%s</li>' % self.make_iconlink(icon, d))
 372                 else:
 373                     iconbar.append('<li>%s</li>' % self.make_icon('copy_disabled', d))
 374             elif icon == "load":
 375                 if self.request.user.may.read(self.page_name):
 376                     iconbar.append('<li>%s</li>' % self.make_iconlink(icon, d))
 377                 else:
 378                     iconbar.append('<li>%s</li>' % self.make_icon('load_disabled', d))
 379             elif icon == "save":
 380                 if self.request.user.may.read(self.page_name):
 381                     iconbar.append('<li>%s</li>' % self.make_iconlink(icon, d))
 382                 else:
 383                     iconbar.append('<li>%s</li>' % self.make_icon('save_disabled', d))
 384             elif icon == "login":
 385                 if not self.site_mode:
 386                     if request.user.valid and request.user.name:
 387                         iconbar.append('<li>%s&nbsp;</li>' % self.username_link(d))
 388                     if self.cfg.show_login:
 389                         if request.user.valid:
 390                             iconbar.append('<li class="ib_selected">%s</li>' % self.make_iconlink("logout", d))
 391                             iconbar.append('<li>%s</li>' % self.make_iconlink("preferences", d))
 392                         else:
 393                             iconbar.append('<li>%s</li>' % self.make_iconlink(icon, d))
 394             elif icon == "quicklink" and request.user.valid:
 395                 # Only display for logged in users
 396                 iconbar.append('<li%s>%s</li>' % [('', self.make_iconlink(icon, d)), (' class="ib_selected"', self.make_iconlink("unquicklink", d))][request.user.isQuickLinkedTo([self.page_name])])
 397             elif icon == "showcomments":
 398                 iconbar.append('<li%s><a href="#" onClick="toggle_comments(this);return false;">%s</a></li>' % [('', self.make_icon(icon, d)), (' class="ib_selected"', self.make_icon("hidecomments", d))][self.request.user.show_comments])
 399             elif icon == "subscribe" and self.cfg.mail_enabled:
 400                 iconbar.append('<li%s>%s</li>' % [('', self.make_iconlink(icon, d)), (' class="ib_selected"', self.make_iconlink("unsubscribe", d))][self.request.user.isSubscribedTo([self.page_name])])
 401             elif icon == "searchform":
 402                 if not self.site_mode:
 403                     iconbar.append('<li>%s</li>' % self.searchform(d))
 404             else:
 405                 page_name, querystr, title, icon = self.button_table[icon]
 406                 if not (self.site_mode and page_name and self.cfg.navi_bar and ((page_name % d) in self.cfg.navi_bar)):
 407                     iconbar.append('<li>%s</li>' % self.make_iconlink(icon, d))
 408         iconbar.append('</ul></div>\n')
 409         return ''.join(iconbar)
 410 
 411         
 412     def editor_link(self, d):
 413         """ Return links to the editor if the user can edit
 414         """
 415         page = self.page
 416         enabled = page.isWritable() and self.request.user.may.write(page.page_name)
 417         guiworks = self.guiworks(page)
 418         editor = self.editor_to_show()
 419         if editor == 'freechoice' and guiworks:
 420             if enabled:
 421                 return '<li>%s</li><li>%s</li>' % (self.make_iconlink('edit_gui', d), self.make_iconlink('edit_text', d))
 422             else:
 423                 return '<li>%s</li><li>%s</li>' % (self.make_icon('edit_gui_disabled', d), self.make_icon('edit_text_disabled', d))
 424         else:
 425             if enabled:
 426                 icon = ['edit_text', 'edit_gui'][editor == 'gui' and guiworks]
 427                 return '<li>%s</li>' % self.make_iconlink(icon, d)
 428             else:
 429                 icon = ['edit_text_disabled', 'edit_gui_disabled'][editor == 'gui' and guiworks]
 430                 return '<li>%s</li>' % self.make_icon(icon, d)
 431 
 432 
 433     def editor_to_show(self):
 434         """ Returns the editor to show
 435         depending on global or user configuration
 436         
 437         @return: 'freechoice', 'gui' or 'text'
 438         """
 439         cfg = self.cfg
 440         user = self.request.user
 441         if cfg.editor_force:
 442             editor = cfg.editor_ui
 443             if editor == 'theonepreferred':
 444                 editor = cfg.editor_default
 445         else:
 446             editor = user.editor_ui
 447             if editor == '<default>':
 448                 editor = cfg.editor_ui
 449                 if editor == 'theonepreferred':
 450                     editor = user.editor_default
 451                     if editor == '<default>':
 452                         editor = cfg.editor_default
 453             elif editor == 'theonepreferred':
 454                 editor = user.editor_default
 455                 if editor == '<default>':
 456                     editor = cfg.editor_default
 457         return editor
 458 
 459                     
 460     def username_link(self, d):
 461         """ Assemble the username link
 462         
 463         @param d: parameter dictionary
 464         @rtype: unicode
 465         @return: username html
 466         """
 467         request = self.request
 468 
 469         html = u''
 470         # Add username/homepage link for registered users. We don't care
 471         # if it exists, the user can create it.
 472         if request.user.valid and request.user.name:
 473             interwiki = self.wikiutil.getInterwikiHomePage(request)
 474             name = request.user.name
 475             aliasname = request.user.aliasname
 476             if not aliasname:
 477                 aliasname = name
 478             title = "%s @ %s" % (aliasname, interwiki[0])
 479             # link to (interwiki) user homepage
 480             html = (request.formatter.interwikilink(1, title=title, id="userhome", generated=True, *interwiki) +
 481                         request.formatter.text(name) +
 482                         request.formatter.interwikilink(0, title=title, id="userhome", *interwiki))
 483         return html
 484 
 485         
 486     def make_iconlink(self, which, d):
 487         """
 488         Make a link with an icon
 489 
 490         @param which: icon id (dictionary key)
 491         @param d: parameter dictionary
 492         @rtype: string
 493         @return: html link tag
 494         """
 495         page_name, querystr, title, icon = self.button_table[which]
 496         d['title'] = title % d
 497         d['i18ntitle'] = self.request.getText(d['title'], formatted=False)
 498         img_src = self.make_icon(icon, d)
 499         # rev = d['rev']
 500         # if rev and which in ['raw', 'print', ]:
 501         #    querystr['rev'] = str(rev)
 502         attrs = {'rel': 'nofollow', 'title': d['i18ntitle'], }
 503         if page_name:
 504             page = self.Page(self.request, page_name % d)
 505         else:
 506             page = self.page
 507         return page.link_to_raw(self.request, text=img_src, querystr=querystr, **attrs)
 508 
 509 
 510 
 511     # =============================
 512     # Page Area
 513     # =============================
 514 
 515     def page_header_info(self, page):
 516         """ Return html fragment with page meta data
 517 
 518         Based on pageinfo function.
 519         
 520         Since page information uses translated text, it uses the ui
 521         language and direction. It looks strange sometimes, but
 522         translated text using page direction looks worse.
 523         
 524         @param page: current page
 525         @rtype: unicode
 526         @return: page last edit information
 527         """
 528         _ = self.request.getText
 529         html = ''
 530         if self.shouldShowPageinfo(page):
 531             info = page.lastEditInfo()
 532             if info:
 533                 if info['editor']:
 534                     info = _("last edited %(time)s by %(editor)s", formatted=False) % info
 535                 else:
 536                     info = _("last modified %(time)s", formatted=False) % info
 537                 html = '<p id="page_header_info"%(lang)s>%(info)s, page size: %(size)s</p>' % {
 538                     'lang': self.ui_lang_attr(),
 539                     'info': info,
 540                     'size': self.wiki_tree.human_readable_size(page.size())
 541                     }
 542         return html
 543 
 544 
 545     def attachment_list(self):
 546         html = self.AttachFile._build_filelist(self.request, self.page_name, showheader=0, readonly=0)
 547         if html:
 548             html = u'<div id="attachments">\n%s\n</div>' % html
 549         return html
 550 
 551 
 552 
 553     # ========================================
 554     # Include explorer.js
 555     # ========================================
 556 
 557     def externalScript(self, name):
 558         # Overwritten from ThemeBase
 559         """ Format external script html """
 560         # modified to supply an additional script file
 561         url_prefix_static = self.cfg.url_prefix_static
 562         html = [ ThemeBase.externalScript(self, name) ]
 563         
 564         html.append('''
 565 <script type="text/javascript">
 566 <!--
 567 var url_prefix_static = "%s";
 568 var DEFAULT_SIDEBAR_WIDTH = "%s";
 569 //-->
 570 </script>
 571 ''' % (url_prefix_static, self.default_sidebar_width))
 572 
 573         html.append('<script type="text/javascript" src="%s/explorer/js/%s.js"></script>' % (url_prefix_static, self.name))
 574 
 575         return '\n'.join(html)
 576 
 577 
 578 
 579 def execute(request):
 580     """
 581     Generate and return a theme object
 582         
 583     @param request: the request object
 584     @rtype: MoinTheme
 585     @return: Theme object
 586     """
 587     return Theme(request)
 588 
 589 
 590 class WikiNode:
 591     """
 592     A WikiNode is an object representing a page (resp. category)
 593     or an attachment and has the following attributes:
 594         display_name : displayed name of the node
 595         type         : node type (0 = category, 1 = page or 2 = attachment)
 596         exists       : flag indicating that a node exists
 597         url          : url of this node
 598         html         : html code representing the node
 599         parents      : list of parents of the node
 600         size         : size of the node
 601         total_size   : size including the size of all sub pages and attachments
 602         categories   : list of sub categories of this category
 603         pages        : list of pages in this category or subpages of page
 604         attachments  : list of attachments of this node
 605     """
 606     import re
 607     
 608     url = ''
 609     html = ''
 610     exists = False
 611     size = 0
 612     total_size = 0
 613 
 614     
 615     def __init__(self, request, name, is_attachment=False):
 616         """ Init the wiki node
 617 
 618         @param request: the request object
 619         @param name: string
 620         @param is_attachment: boolean
 621         """
 622         self.display_name = name
 623         self.parents, self.categories, self.pages, self.attachments = [], [], [], []
 624         self.subnodes = [ self.categories, self.pages, self.attachments ]
 625         if is_attachment:
 626             self.type = 2  # attachment
 627         else:  # Identify the node type
 628             match_object = self.re.match(request.cfg.cache.page_category_regex, name)
 629             if match_object:
 630                 self.type = 0  # category
 631                 # On categories remove the key string identifying a category (default 'Category')
 632                 if match_object.lastindex:
 633                     self.display_name = match_object.group(1).lstrip()
 634             else:
 635                 self.type = 1  # page
 636 
 637 
 638     def addSubNode(self, name, type):
 639         """ Add a sub node of the given type
 640         """
 641         self.subnodes[type].append(name)
 642 
 643 
 644     def removeSubNode(self, name, type):
 645         """ Remove a sub node of the given type
 646         """
 647         self.subnodes[type].remove(name)
 648 
 649         
 650     
 651 class WikiTree:
 652     """
 653     The wiki tree represents the tree of all pages (resp. categories) and
 654     attachments of the wiki. It has the following attributes:
 655         wiki_tree   : a dictionary of WikiNodes { node_name : node, ... }
 656         root        : name of the root category
 657         orphaned    : name of the orphaned category
 658         missing     : name of the missing category
 659         underlay    : name of the underlay category
 660         root_category, orphaned_category, missing_category, underlay_category
 661         type_counts : list of total counts of categories, pages and attachments
 662         total_size  : total size of all nodes
 663         
 664     These are cached in the meta cache server object and are updated on changes.
 665     """
 666     # import time
 667     import thread, math, os
 668     from MoinMoin.action import AttachFile
 669     from MoinMoin import wikiutil, config
 670     from MoinMoin.Page import Page
 671 
 672     # fake _ function to get gettext recognize those texts:
 673     _ = lambda x: x
 674     ui_text = {
 675         'toggle_title' : _("Toggle display"),
 676         # used in node_description
 677         'categories' :   _('categories'),
 678         'pages' :        _('pages'),
 679         'attachments' :  _('attachments'),
 680         'size' :         _('size'),
 681         }
 682     del _
 683 
 684     orphaned_category = missing_category = underlay_category = None
 685 
 686     wiki_tree = { }
 687     # Special categories of the wiki tree (generally these should be a categories) 
 688     root = u'CategoryRoot'
 689     orphaned = u'CategoryOrphaned'
 690     missing = u'CategoryMissing'
 691     underlay = u'CategoryUnderlay'
 692 
 693     type_counts = [ 0, 0, 0 ]  # categories, pages, attachments
 694     total_size = 0  # Total size of all nodes
 695 
 696     touched = set([])  # Nodes changed since last tree update
 697 
 698 
 699     def __init__(self, theme, d):
 700         """ Inits the wiki tree structure and wiki tree info
 701             or loads it from cache
 702         """
 703         self.request = theme.request
 704         # Get the cookies of the request
 705         self.cookies = self.request.parse_cookie()
 706         self.page_name = d['page_name']
 707 
 708         # Define image tags for node icons
 709         self.node_icon_html = [
 710             u'<img src="%s">' % theme.img_url('category.png'),
 711             u'<img src="%s">' % theme.img_url('page.png'),
 712             u'<img src="%s">' % theme.img_url('attachment.png'),
 713             u'<img src="%s">' % theme.img_url('category-missing.png'),
 714             u'<img src="%s">' % theme.img_url('page-missing.png'),
 715             ]
 716         self.expand_icon_url = theme.img_url('expand.png')
 717         self.collapse_icon_url = theme.img_url('collapse.png')
 718 
 719         # Get cached lock on wiki tree
 720         self.lock = self.request.cfg.cache.meta.getItem(self.request, u'', u'wiki_tree_lock')
 721         if not self.lock:  # If lock doesn't exist build one
 722             self.lock = self.thread.allocate_lock()
 723             self.request.cfg.cache.meta.putItem(self.request, u'', u'wiki_tree_lock', self.lock)
 724 
 725         # Get cached wiki tree
 726         self.cache = self.request.cfg.cache.meta.getItem(self.request, u'', u'wiki_tree')
 727         if not self.cache and self.lock.acquire(0):
 728             # No cached tree exists: Set lock and build tree.
 729             try:
 730                 self.categories_formatter = CategoriesFormatter(self.request, store_pagelinks=1)
 731                 self.build_wiki_tree()
 732                 self.log_pos, items = self.request.editlog.news(None)
 733                 self.request.cfg.cache.meta.putItem(self.request, u'', u'wiki_tree',
 734                         [ self.log_pos, self.wiki_tree, self.type_counts, self.total_size,
 735                             self.root, self.root_category,
 736                             self.orphaned, self.orphaned_category,
 737                             self.missing, self.missing_category,
 738                             self.underlay, self.underlay_category,
 739                             self.categories_formatter
 740                         ])
 741             finally:
 742                 self.lock.release()
 743         else:
 744             # If cached tree exists: Set lock and refresh tree.
 745             self.lock.acquire()
 746             try:
 747                 self.refresh_wiki_tree()            
 748             finally:
 749                 self.lock.release()
 750 
 751 
 752     def refresh_wiki_tree(self):
 753         """ Refresh the wiki nodes changed
 754             if anything has changed in the wiki, we see it
 755             in the edit-log and update the wiki_tree accordingly
 756         """
 757         # Get wiki tree data from cache.
 758         if not self.cache:
 759             self.cache = self.request.cfg.cache.meta.getItem(self.request, u'', u'wiki_tree')
 760         self.log_pos, self.wiki_tree, self.type_counts, self.total_size, self.root, self.root_category, self.orphaned, self.orphaned_category, self.missing, self.missing_category, self.underlay, self.underlay_category, self.categories_formatter = self.cache
 761         elog = self.request.editlog
 762         old_pos = self.log_pos
 763         new_pos, items = elog.news(old_pos)
 764         if self.request.action == 'refresh':
 765             if self.page_name not in items:
 766                 items.append(self.page_name)
 767             page = self.Page(self.request, self.page_name, formatter=self.categories_formatter)
 768             parent_categories = self.categories_formatter.getCategories(page, update_cache=True)
 769         if items:
 770             for item in items:
 771                 self.remove_page(item)
 772             for item in items:
 773                 self.add_page(item)
 774             self.finalize_touched()
 775         self.log_pos = new_pos  # important to do this at the end -
 776                                 # avoids threading race conditions
 777         self.cache[0] = self.log_pos
 778 
 779 
 780     def build_wiki_tree(self):
 781         """ Builds the wiki tree structure and wiki tree info
 782         """
 783         cfg = self.request.cfg
 784         if hasattr(cfg, 'wiki_tree_root'):
 785             self.root = cfg.wiki_tree_root
 786         if hasattr(cfg, 'wiki_tree_orphaned'):
 787             self.orphaned = cfg.wiki_tree_orphaned
 788         if hasattr(cfg, 'wiki_tree_missing'):
 789             self.missing = cfg.wiki_tree_missing
 790         if hasattr(cfg, 'wiki_tree_underlay'):
 791             self.underlay = cfg.wiki_tree_underlay
 792 
 793         self.root_category = self.get_assured_node(self.root)
 794         if self.orphaned:
 795             self.orphaned_category = self.get_assured_node(self.orphaned)
 796         if self.missing:
 797             self.missing_category = self.get_assured_node(self.missing)
 798         if self.underlay:
 799             self.underlay_category = self.get_assured_node(self.underlay)
 800 
 801         # print '>>>>>> Start Build WikiTree: ', self.time.clock()
 802         # Add all pages from the wiki
 803         for page_name in self.request.rootpage.getPageList(user=''):
 804             self.add_page(page_name)
 805         # print '>>>>>> Finish Build WikiTree: ', self.time.clock()
 806         self.finalize_touched()
 807 
 808         
 809     def add_page(self, page_name):
 810         """ Add a page to the wiki tree
 811         """
 812         request = self.request
 813         page = self.Page(self.request, page_name, formatter=self.categories_formatter)
 814         if page.exists():
 815             node = self.get_assured_node(page_name)
 816             node.exists = True
 817             node.size += page.size()
 818             node.total_size += node.size
 819             node.url = page.url(request, relative=False)
 820             self.type_counts[node.type] += 1
 821             self.total_size += node.size
 822 
 823             # Add attachments to the wiki tree
 824             attachments = self.get_attachment_dict(page_name)
 825             for (attachment_name, attachment_info) in attachments.iteritems():
 826                 attachment_key = page_name + '/' + attachment_name
 827                 attachment_node = self.get_assured_node(attachment_key, is_attachment=True)
 828                 attachment_node.display_name = attachment_name
 829                 attachment_node.exists = True
 830                 attachment_node.size = attachment_info[0]
 831                 attachment_node.total_size += attachment_node.size
 832                 attachment_node.url = attachment_info[1]
 833                 self.add_to_parent(attachment_key, attachment_node, page_name, node)
 834                 self.type_counts[2] += 1
 835                 self.total_size += attachment_info[0]
 836                 self.touched.add(attachment_key)
 837 
 838             pos = page_name.rfind('/')
 839             if pos > 0:  # page is subpage
 840                 node.display_name = page_name[pos+1:]
 841                 self.add_to_parent(page_name, node, page_name[:pos])
 842             else:
 843                 # Add the page to the categories it belongs to
 844                 parent_categories = self.categories_formatter.getCategories(page)
 845                 if self.underlay_category and page.isUnderlayPage():
 846                     parent_categories.append(self.underlay)
 847                 for parent_category in parent_categories:
 848                     self.add_to_parent(page_name, node, parent_category)
 849 
 850             self.touched.add(page_name)
 851 
 852 
 853     def get_assured_node(self, node_name, is_attachment=False):
 854         """ Get a wiki node with the specified name.
 855         If the node doesn't exist it is created.
 856         """
 857         if node_name in self.wiki_tree:
 858             node = self.wiki_tree[node_name]
 859         else:
 860             node = WikiNode(self.request, node_name, is_attachment=is_attachment)
 861             self.wiki_tree[node_name] = node
 862             self.touched.add(node_name)
 863         return node
 864 
 865 
 866     def add_to_parent(self, node_name, node, parent_name, parent = None):
 867         """ Add a node to a parent node
 868         """
 869         if not parent:
 870             parent = self.get_assured_node(parent_name)
 871         node.parents.append(parent_name)
 872         parent.addSubNode(node_name, node.type)
 873         parent.total_size += node.size
 874         self.touched.add(parent_name)
 875 
 876 
 877     def get_attachment_dict(self, page_name):
 878         """ Returns a dict of attachments
 879 
 880         The structure of the dictionary is:
 881         { file_name : [file_size, get_url], ... }
 882         
 883         @param page_name:
 884         @rtype: attachments dictionary
 885         @return: attachments dictionary
 886         """
 887         attach_dir = self.AttachFile.getAttachDir(self.request, page_name)
 888         files = self.AttachFile._get_files(self.request, page_name)
 889         attachments = {}
 890         for file in files:
 891             fsize = float(self.os.stat(self.os.path.join(attach_dir,file).encode(self.config.charset))[6])
 892             get_url = self.AttachFile.getAttachUrl(page_name, file, self.request, escaped=1)
 893             attachments[file] = [fsize, get_url]
 894         return attachments
 895 
 896 
 897     def remove_page(self, page_name):
 898         """ Remove a node from the wiki tree
 899         """
 900         if page_name in self.wiki_tree:
 901             node = self.wiki_tree[page_name]
 902             self.type_counts[node.type] -= 1
 903             self.total_size -= node.size
 904 
 905             while node.attachments:
 906                 self.remove_page(node.attachments[0])
 907 
 908             while node.parents:
 909                 self.remove_from_parent(page_name, node, node.parents[0])
 910 
 911             if node.categories or node.pages or (page_name in [self.root, self.orphaned, self.missing, self.underlay]):
 912                 node.exists = 0
 913                 node.html = ''
 914                 self.touched.add(page_name)
 915             else:
 916                 del self.wiki_tree[page_name]
 917 
 918 
 919     def remove_from_parent(self, node_name, node, parent_name):
 920         """ Add a node from the parent node
 921         """
 922         parent = self.wiki_tree[parent_name]
 923         parent.removeSubNode(node_name, node.type)
 924         parent.total_size -= node.size
 925         node.parents.remove(parent_name)
 926         if parent.exists or parent.categories or parent.pages or (node_name in [self.root, self.orphaned, self.missing, self.underlay]):
 927             self.touched.add(parent_name)
 928         else:
 929             self.remove_page(parent_name)
 930 
 931 
 932     def finalize_touched(self):
 933         """ Calculate totals, prepare the html code for each node
 934         that has changed (these nodes are stored in the touched set)
 935         """
 936         first_step_touched = self.touched
 937         self.touched = set([])
 938         for node_name in first_step_touched:
 939             self.finalize_node(node_name)
 940         second_step_touched = self.touched
 941         self.touched = set([])
 942         for node_name in second_step_touched:
 943             self.finalize_node(node_name)
 944 
 945 
 946     def finalize_node(self, node_name):
 947         """ Finalize the wiki tree node
 948         
 949         Calculates the totals and the html code for the node.
 950         
 951         @param node name:
 952         @param path: list of nodes up to this one
 953         """
 954         if node_name in self.wiki_tree:
 955             node = self.wiki_tree[node_name]
 956             # Sort sub nodes
 957             node.categories.sort()
 958             node.pages.sort()
 959             node.attachments.sort()
 960             # Calculate subnode counts
 961             node.categories_count = len(node.categories)
 962             node.pages_count = len(node.pages)
 963             node.attachments_count = len(node.attachments)
 964             icon_type = node.type
 965             if not node.exists:
 966                 # Page represented by node doesn't exist
 967                 icon_type += 3
 968                 node.url = '%s/%s' % (self.request.getScriptname(), self.wikiutil.quoteWikinameURL(node_name))
 969                 if node_name not in [self.missing, self.orphaned]:
 970                     if not node.parents and self.missing:
 971                         # Add page to category missing
 972                         self.add_to_parent(node_name, node, self.missing)
 973             if not node.parents and self.orphaned and node_name != self.root:
 974                 # Page is orphaned but not root, add it to orphaned category
 975                 self.add_to_parent(node_name, node, self.orphaned)
 976                 if node_name == self.orphaned:
 977                     # If orphaned category is orphaned add it to root
 978                     self.add_to_parent(node_name, node, self.root)
 979             # Build the html code for the link
 980             title = self.node_description(node)
 981             link_html = u'<a class="node" href="%s" title="%s">%s</a>' % (node.url, title, node.display_name)
 982             node.html = self.node_icon_html[icon_type] + link_html
 983 
 984 
 985     def node_description(self, node, include_name = 1, separator = u', '):
 986         """ Return a description of the node
 987         
 988         The description contains information about the size and
 989         counters of the sub tree of the node
 990         
 991         @param node: 
 992         @param include_name: integer denoting if the display_name should be included
 993         @param separator: separator unicode string
 994         @rtype: unicode
 995         @return: html describing the sub tree
 996         """
 997         description = u''
 998         categories_count = node.categories_count
 999         pages_count = node.pages_count
1000         attachments_count = node.attachments_count
1001         total_size = node.total_size
1002         if include_name:  # Should the node name be displayed?
1003             description = u'%s: ' % node.display_name
1004         _ = self.ui_text
1005         # if (categories_count + pages_count + attachments_count):  # Are there sub nodes?
1006         description = u'%s%i&nbsp;%s%s%i&nbsp;%s%s%i&nbsp;%s%s%s:&nbsp;%s' % (
1007                 description,
1008                 pages_count, _['pages'], separator,
1009                 categories_count, _['categories'], separator,
1010                 attachments_count, _['attachments'], separator,
1011                 _['size'], self.human_readable_size(total_size))
1012         # else:
1013         #    description = u'%s%s:&nbsp;%s' % (description, _['size'], self.human_readable_size(total_size))
1014         return description
1015 
1016 
1017     def human_readable_size(self, size):
1018         """ Return the size normalized with unit
1019         
1020         @param size: integer denoting a file size
1021         @rtype: unicode
1022         @return: html describing the file size
1023         """
1024         if size == 0:
1025             return u'0&nbsp;Bytes'
1026         file_size_name = [u'Bytes', u'KB', u'MB', u'GB', u'TB', u'PB', u'EB', u'ZB', u'YB']
1027         i = int(self.math.log(size, 1024))
1028         if i:
1029             return u'%.2f&nbsp;%s' % (round(size/pow(1024, i), 2), file_size_name[i])
1030         else:
1031             return u'%i&nbsp;Bytes' % size
1032 
1033             
1034             
1035     # =============================
1036     # UI
1037     # =============================
1038 
1039     def wiki_tree_html(self):
1040         """ Build the html code of the wiki tree
1041         """
1042         return self.wiki_subtree_html(self.root)
1043 
1044 
1045     def wiki_subtree_html(self, node_name, path=[]):
1046         """ Return wiki sub tree html code with the specified node as root
1047 
1048         The path contains the path of nodes from the root to the current node.
1049         This is used to avoid recursion in the wiki tree.
1050         
1051         @param node_name: root of the sub tree
1052         @param path: list of nodes up to this one
1053         @rtype: unicode
1054         @return: wiki tree html
1055         """
1056         items = []
1057         node = self.wiki_tree[node_name]
1058         if not node.exists or self.request.user.may.read(node_name):
1059             html = node.html
1060             if node_name == self.page_name:
1061                 html = html.replace('class="node"', 'class="node_selected"')
1062             sub_nodes = node.categories + node.pages + node.attachments
1063             if not sub_nodes:
1064                 if path:  #  If it's not the root node (which is not diplayed)
1065                     items = [u'<li class="leaf">' + html]  # Display the node
1066             else:
1067                 node_id = 'tree_%s' % self.wikiutil.url_quote(u''.join(path),'')
1068                 display_subtree = (not path) or (self.cookies and node_id in self.cookies) 
1069                 if path:  #  If it's not the root node (which is not diplayed)
1070                     if display_subtree:
1071                         toggle_icon_url = self.collapse_icon_url
1072                         toggle_icon_alt = "[-]"
1073                     else:
1074                         toggle_icon_url = self.expand_icon_url
1075                         toggle_icon_alt = "[+]"
1076                     items = [u'<li><img class="toggle" alt="%s" title="%s" src="%s" onclick="toggle_display_element(this, \'%s\');">%s' % (toggle_icon_alt, self.ui_text["toggle_title"], toggle_icon_url, node_id, html)]
1077                 if display_subtree:
1078                     items.append(u'<ul class="wiki_tree" id="%s">' % node_id)
1079                     for sub_node_name in sub_nodes:
1080                         items.append(self.wiki_subtree_html(sub_node_name, path+[sub_node_name]))
1081                     items.append(u'</ul>')
1082         return u'\n'.join(items)
1083 
1084 
1085     def wiki_summary_html(self):
1086         """ Return a description of the wiki (counters and size) """
1087         _ = self.ui_text
1088         return u'<ul id="wiki_summary"><li>%i&nbsp;%s<li>%i&nbsp;%s<li>%i&nbsp;%s<li>%s:&nbsp;%s</ul>' % (
1089                     self.type_counts[1], _['pages'],
1090                     self.type_counts[0], _['categories'],
1091                     self.type_counts[2], _['attachments'],
1092                     _['size'], self.human_readable_size(self.total_size))
1093                     
1094                     
1095     def page_summary_html(self):
1096         """ Return html fragment with summary of current page
1097         
1098         @rtype: unicode
1099         @return: page summary information
1100         """
1101         html = u''
1102         if self.page_name in self.wiki_tree:
1103             html = u'<ul id="page_summary"><li>%s</ul>' % self.node_description(self.wiki_tree[self.page_name], include_name=0, separator=u'<li>')
1104         return html
1105 
1106         
1107     def parents_html(self):
1108         """ Builds a html list of the parents of the current node
1109         """
1110         html = u''
1111         request = self.request
1112         # Get list of parents the page belongs to
1113         if self.page_name in self.wiki_tree:
1114             parents = self.wiki_tree[self.page_name].parents
1115             if parents:
1116                 items = [u'<ul id="parents">']
1117                 for parent in parents:
1118                     page = self.Page(request, parent)
1119                     title = page.split_title()
1120                     link = page.link_to(request, title)
1121                     items.append('<li>%s</li>' % link)
1122                 items.append(u'</ul>')
1123                 html = '\n'.join(items)
1124         return html        
1125 
1126 
1127 
1128 from MoinMoin.formatter import FormatterBase
1129     
1130 class CategoriesFormatter(FormatterBase):
1131     """
1132         categories Formatter
1133         @copyright: 2007 Wolfgang Fischer
1134 
1135         based on pagelinks formatter
1136         @copyright: 2005 Nir Soffer <nirs@freeshell.org>
1137         @license: GNU GPL, see COPYING for details.
1138     """
1139     """ Collect categories and format nothing :-) """
1140 
1141     def __init__(self, request, **kw):
1142         FormatterBase.__init__(self, request, **kw)
1143         import re
1144         self.page_category_regex = re.compile(request.cfg.page_category_regex, re.UNICODE)
1145 
1146     def pagelink(self, on, pagename='', page=None, **kw):
1147         if self.page_category_regex.search(pagename):
1148             FormatterBase.pagelink(self, on, pagename, page, **kw)
1149         return self.null()
1150 
1151 
1152     def getCategories(self, page, update_cache=False):
1153         """ Get a list of the links on this page.
1154         Based on getPageLinks function in Page module
1155 
1156         @page page: the page name
1157         @rtype: list
1158         @return: category names this page belongs to
1159         """
1160         request = self.request
1161         if page:
1162             self.setPage(page)
1163         page = self.page
1164         if page.exists():
1165             from MoinMoin import caching
1166             cache = caching.CacheEntry(request, page, 'categories', scope='item', do_locking=False, use_pickle=True)
1167             if update_cache or cache.needsUpdate(page._text_filename()):
1168                 print '### UPDATE Categories of page (needed): ', page.page_name
1169                 links = self.parseCategories()
1170                 cache.update(links)
1171             else:
1172                 try:
1173                     links = cache.content()
1174                 except caching.CacheError:
1175                     print '### UPDATE Categories of page (CacheError): ', page.page_name
1176                     links = self.parseCategories()
1177                     cache.update(links)
1178         else:
1179             links = []
1180 
1181         return links
1182 
1183 
1184     def parseCategories(self):
1185         """ Parse categories by formatting with a categories formatter 
1186         [Based on parsePageLinks function in Page module]
1187 
1188         This is a old hack to get the pagelinks by rendering the page
1189         with send_page. We can remove this hack after factoring
1190         send_page and send_page_content into small reuseable methods.
1191         
1192         More efficient now by using special pagelinks formatter and
1193         redirecting possible output into null file.
1194         """
1195         request = self.request
1196         page = self.page
1197         pagename = page.page_name
1198 
1199         request.clock.start('parseCategories')
1200 
1201         class Null:
1202             def write(self, data):
1203                 pass
1204 
1205         request.redirect(Null())
1206         try:
1207             self.pagelinks = []
1208             pi = page.pi
1209             page.send_page_content(request, page.data,
1210                                    format=pi['format'],
1211                                    format_args=pi['formatargs'],
1212                                    do_cache=1,
1213                                    start_line=pi['lines'])
1214         finally:
1215             request.redirect()
1216             # if hasattr(request, '_fmt_hd_counters'):
1217             #    del request._fmt_hd_counters
1218             request.clock.stop('parseCategories')
1219         return self.pagelinks
1220 
1221         
1222     def null(self, *args, **kw):
1223         return ''
1224         
1225     def macro(self, macro_obj, name, args, markup=None):
1226         return ''
1227         
1228     # All these must be overriden here because they raise
1229     # NotImplementedError!@#! or return html?! in the base class.
1230     set_highlight_re = rawHTML = url = image = smiley = text = null
1231     strong = emphasis = underline = highlight = sup = sub = strike = null
1232     code = preformatted = small = big = code_area = code_line = null
1233     code_token = linebreak = paragraph = rule = icon = null
1234     number_list = bullet_list = listitem = definition_list = null
1235     definition_term = definition_desc = heading = table = null
1236     table_row = table_cell = attachment_link = attachment_image = attachment_drawing = null
1237     transclusion = transclusion_param = null

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] (2008-03-11 12:44:08, 0.0 KB) [[attachment:categories]]
  • [get | view] (2008-03-11 12:43:55, 52.1 KB) [[attachment:explorer_-_categories_update_debug.py]]
  • [get | view] (2008-03-11 12:43:42, 12.2 KB) [[attachment:explorer_screenshot.png]]
 All files | Selected Files: delete move to page copy to page

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