ShowCategory

1. Description

Default category page of Moin using FullSearch macro. It is slow and not good looking. I write a ShowCategory macro, which display a MediaWiki alike category page.

A typical usage: simply write a <<ShowCategory>> in any category page.

2. Snapshot

category_news.png

new_subcategory.png

new_subpage.png

3. Example

4. Download

4.1. ShowCategory macro source code

   1 new macro ShowCategory: display a MediaWiki style category page
   2 
   3 diff -r 0bfe351fb737 MoinMoin/macro/ShowCategory.py
   4 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   5 +++ b/MoinMoin/macro/ShowCategory.py	Tue Nov 25 10:17:40 2008 +0800
   6 @@ -0,0 +1,210 @@
   7 +# -*- coding: utf-8 -*-
   8 +"""
   9 +    CategoryList macro
  10 +
  11 +    List Categories in Category.
  12 +
  13 +    @copyright: 2008 Jiang Xin <worldhello.net@gmail.com>
  14 +    @license: GNU GPL, see COPYING for details.
  15 +"""
  16 +
  17 +from MoinMoin import wikiutil2
  18 +from MoinMoin.Page import Page
  19 +
  20 +_sysmsg = '<p><strong class="%s">%s</strong></p>'
  21 +
  22 +
  23 +def show_category(request, categorylist, column=3, show_cat=True, show_page=True, 
  24 +                  show_summary=True, show_capital=True, sort=[], reverse=False, 
  25 +                  recursive=False, items=0, skipitems=0, exclude_template=True):
  26 +    cc = wikiutil2.CategoryCache(request)
  27 +    _ = request.getText
  28 +    
  29 +    if "all" in categorylist:
  30 +        show_cat = True
  31 +        show_page = False
  32 +        recursive = False
  33 +        summary_of_subcategories = "<h2>" + _("All categories") + "</h2>\n" + \
  34 +                                   _("There are %(count)d categories in this wiki.")
  35 +        summary_of_subpages      = ""
  36 +    else:
  37 +        summary_of_subcategories = "<h2>" + _("Subcategories of <b>%(category)s</b>") + "</h2>\n" + \
  38 +                                   _("This category has the following %(count)d subcategories.")
  39 +        summary_of_subpages      = "<h2>" + _("Pages in category <b>%(category)s</b>") + "</h2>\n" + \
  40 +                                   _("There are %(count)d pages are in this category.")
  41 +        
  42 +    result = []
  43 +
  44 +    # show sub category
  45 +    if show_cat:
  46 +        for category in categorylist:
  47 +            itemlist = []
  48 +            for i in sorted( cc.get_sub_categories(category,recursive=recursive, exclude_template=exclude_template) ):
  49 +                name = i
  50 +                page = Page(request, name)
  51 +                entries = []
  52 +                for s in sort:
  53 +                    if "title".startswith(s):
  54 +                        pagetitle = page.pi.get("pragma_page_title" ,page.page_name)
  55 +                        entries.append( pagetitle )
  56 +                        name = pagetitle
  57 +                    elif "timestamp".startswith(s):
  58 +                        edit_info = page.edit_info()
  59 +                        timestamp = edit_info.get('timestamp', 0)
  60 +                        entries.append(timestamp)
  61 +                    else:
  62 +                        return (_sysmsg % ('error', _('Invalid sort arguments "%s"!')) % (s, ))
  63 +                linktext = "%s(%d/%d)" % ( name, len(cc.catcatdict.get(i,[])), len(cc.catpagedict.get(i,[])) ) 
  64 +                link = page.link_to(request, text=linktext, attachment_indicator=1)
  65 +                entries.extend( [name, link] )
  66 +                itemlist.append( entries )
  67 +
  68 +            if itemlist:
  69 +                itemlist.sort(reverse=reverse)
  70 +                if len(itemlist[0]) > 2:
  71 +                    itemlist=[ (x[-2], x[-1]) for x in itemlist ]
  72 +    
  73 +            if show_summary:
  74 +                result += [ summary_of_subcategories % {'category': category, 'count': len(itemlist)} ]
  75 +            
  76 +            if skipitems:
  77 +                itemlist=itemlist[skipitems:]
  78 +            if items:
  79 +                itemlist=itemlist[:items]
  80 +            result += wikiutil2.formatList(request, itemlist, column=column, show_capital=show_capital)
  81 +    
  82 +    # show pages belong to this category
  83 +    if show_page:
  84 +        for category in categorylist:
  85 +            itemlist = []
  86 +            for i in sorted( cc.get_sub_pages(category,recursive=recursive, exclude_template=exclude_template) ):
  87 +                name = i
  88 +                page = Page(request, name)
  89 +                entries = []
  90 +                for s in sort:
  91 +                    if "title".startswith(s):
  92 +                        pagetitle = page.pi.get("pragma_page_title" ,page.page_name)
  93 +                        entries.append( pagetitle )
  94 +                        name = pagetitle
  95 +                    elif "timestamp".startswith(s):
  96 +                        edit_info = page.edit_info()
  97 +                        timestamp = edit_info.get('timestamp', 0)
  98 +                        entries.append(timestamp)
  99 +                    else:
 100 +                        return (_sysmsg % ('error', _('Invalid sort arguments "%s"!')) % (s, ))
 101 +                link = page.link_to(request, text=name, attachment_indicator=1)
 102 +                entries.extend( [name, link] )
 103 +                itemlist.append( entries )
 104 +            
 105 +            if itemlist:
 106 +                itemlist.sort(reverse=reverse)
 107 +                if len(itemlist[0]) > 2:
 108 +                    itemlist=[ (x[-2], x[-1]) for x in itemlist ]
 109 +            
 110 +            if show_summary:
 111 +                result += [ summary_of_subpages % {'category': category, 'count': len(itemlist)} ]
 112 +
 113 +            if skipitems:
 114 +                itemlist=itemlist[skipitems:]
 115 +            if items:
 116 +                itemlist=itemlist[:items]
 117 +            result += wikiutil2.formatList(request, itemlist, column=column, show_capital=show_capital)
 118 +    
 119 +    return "\n".join(result)
 120 +
 121 +
 122 +
 123 +def execute(macro, args):
 124 +    global category_cache
 125 +    request = macro.request
 126 +    _ = request.getText
 127 +    show_cat = True
 128 +    show_page = True
 129 +    show_summary = True
 130 +    show_capital = True
 131 +    exclude_template = True
 132 +    column = 3
 133 +    category = []
 134 +    sort = []
 135 +    reverse = False
 136 +    recursive = False
 137 +    items = 0
 138 +    skipitems = 0
 139 +    
 140 +    if args:
 141 +        for i in args.split(','):
 142 +            i=i.strip()
 143 +            if "=" in i:
 144 +                key, val = i.split('=',1)
 145 +            else:
 146 +                key = i
 147 +                val = "yes"
 148 +            boolval = (val=="1" or val.lower().startswith("t") or val.lower().startswith("y"))
 149 +            if key.startswith("no"):
 150 +                boolval = not boolval
 151 +
 152 +            if "nocategories".startswith(key) or "categories".startswith(key):
 153 +                show_cat = boolval
 154 +                continue
 155 +            elif "nopages".startswith(key) or "pages".startswith(key):
 156 +                show_page = boolval
 157 +                continue
 158 +            elif "nosummary".startswith(key) or "summary".startswith(key):
 159 +                show_summary = boolval
 160 +                continue
 161 +            elif "nocapital".startswith(key) or "capital".startswith(key):
 162 +                show_capital = boolval
 163 +                continue
 164 +            elif "notemplates".startswith(key) or "templates".startswith(key):
 165 +                exclude_template = not boolval
 166 +                continue
 167 +            elif "descending".startswith(key):
 168 +                reverse = boolval
 169 +                continue
 170 +            elif "ascending".startswith(key):
 171 +                reverse = not boolval
 172 +                continue
 173 +            elif "recursive".startswith(key):
 174 +                recursive = boolval
 175 +                continue
 176 +            elif "sort".startswith(key):
 177 +                sort.append(val)
 178 +                continue
 179 +            elif "column".startswith(key):
 180 +                column = int(val)
 181 +                continue
 182 +            elif "items".startswith(key):
 183 +                items = int(val)
 184 +                continue
 185 +            elif "skipitems".startswith(key):
 186 +                skipitems = int(val)
 187 +                continue
 188 +            elif "=" in i:
 189 +                return (_sysmsg % ('error', _('Invalid ShowCategory arguments "%s"!')) % (i, ))
 190 +                   
 191 +            if i.lower() == "all":
 192 +                category.append("all")
 193 +                continue
 194 +            else:
 195 +                category_check = request.cfg.cache.page_category_regex.search(i)
 196 +                if category_check and category_check.group("all") == i:
 197 +                    category.append(i)
 198 +                    continue
 199 +            try:
 200 +                i = int(i)
 201 +                column = i
 202 +            except:
 203 +                return (_sysmsg % ('error', _('Invalid ShowCategory arguments "%s"!')) % (i, ))
 204 +
 205 +    if not sort:
 206 +        sort = ["title"]
 207 +    
 208 +    if not category:
 209 +        category.append(macro.formatter.page.page_name)
 210 +    
 211 +    return show_category(request, category, column=column, show_cat=show_cat, show_page=show_page, 
 212 +                         show_summary=show_summary, show_capital=show_capital, sort=sort, 
 213 +                         reverse=reverse, recursive=recursive, items=items, skipitems=skipitems, 
 214 +                         exclude_template=exclude_template)
 215 +
 216 +# vim:ts=4:sw=4:et
 217 diff -r 0bfe351fb737 MoinMoin/wikiutil2.py
 218 --- a/MoinMoin/wikiutil2.py	Tue Nov 25 09:40:25 2008 +0800
 219 +++ b/MoinMoin/wikiutil2.py	Tue Nov 25 10:17:40 2008 +0800
 220 @@ -8,6 +8,9 @@
 221  
 222  import re
 223  from MoinMoin import wikiutil
 224 +from MoinMoin import caching
 225 +from MoinMoin.Page import Page
 226 +from MoinMoin.logfile import editlog
 227  
 228  from MoinMoin import log
 229  logging = log.getLogger(__name__)
 230 @@ -66,3 +69,292 @@
 231  
 232      return raw_body
 233  
 234 +class CategoryCache(object):
 235 +    cache_date, pagedict, catcatdict, catpagedict = 0, {}, {}, {}
 236 +    
 237 +    def __init__(self, request):
 238 +        self.request = request
 239 +        self._update_category_cache_data()
 240 +
 241 +    def _update_category_cache_data(self):
 242 +        cache = caching.CacheEntry(self.request, 'category', 'dict', scope='wiki', use_pickle=True)
 243 +        if cache.exists():
 244 +            try:
 245 +                self.cache_date, self.pagedict, self.catcatdict, self.catpagedict = cache.content()
 246 +            except:
 247 +                cache.remove() # cache gone bad
 248 +    
 249 +        log = editlog.EditLog(self.request)
 250 +        try:
 251 +            new_date = log.date()
 252 +        except logfile.LogMissing:
 253 +            new_date = self.cache_date
 254 +    
 255 +        if not (self.pagedict or self.catcatdict or self.catpagedict):
 256 +            pagelist = self.request.rootpage.getPageList(user="",return_objects=True)
 257 +        else:
 258 +            pagenamelist = set()
 259 +            pagelist = []
 260 +    
 261 +            if new_date > self.cache_date:
 262 +                for event in log.reverse():
 263 +                    if event.ed_time_usecs <= self.cache_date:
 264 +                        break
 265 +                    # action: [ATTDEL, ATTNEW, SAVE, SAVENEW, SAVE/RENAME, SAVE/REVERT]
 266 +                    if event.action not in ['ATTNEW', 'ATTDEL']:
 267 +                        pagenamelist.add(event.pagename)
 268 +                    if event.action == 'SAVE/RENAME':
 269 +                        pagenamelist.add(event.extra)
 270 +    
 271 +                for pagename in pagenamelist:
 272 +                    page = Page(self.request, pagename)
 273 +                    pagelist.append(page)
 274 +                self.cache_date = new_date
 275 +        
 276 +        # cache outof date since there are changed pages.
 277 +        if pagelist:
 278 +            pattern = re.compile(r'(?:^-----*\s*\r?\n)(?:^##.*\r?\n)*^(?!##)(?P<category>.+?)$', re.M)
 279 +            for page in pagelist:
 280 +                body = page.get_raw_body()
 281 +                pagename = page.page_name
 282 +                
 283 +                name_checked = self.request.cfg.cache.page_category_regexact.search(pagename)
 284 +                if name_checked and name_checked.group("all") == pagename:
 285 +                    page_is_category = True
 286 +                else:
 287 +                    page_is_category = False
 288 +                # reset self.pagedict, catdict for pagename
 289 +                if self.pagedict.has_key(pagename):
 290 +                    for catname in self.pagedict[pagename]:
 291 +                        if page_is_category:
 292 +                            catdict = self.catcatdict
 293 +                        else:
 294 +                            catdict = self.catpagedict
 295 +                        if catdict.has_key(catname):
 296 +                            if pagename in catdict[catname]:
 297 +                                catdict[catname].remove(pagename)
 298 +                            if not catdict[catname]:
 299 +                                del catdict[catname]
 300 +                    del self.pagedict[pagename]
 301 +                
 302 +                # if deleted page is a category, delete category if blank.
 303 +                if not body and page_is_category:
 304 +                    if self.catcatdict.has_key(pagename):
 305 +                        if not self.catcatdict[pagename]:
 306 +                            del self.catcatdict[pagename]
 307 +                    if self.catpagedict.has_key(pagename):
 308 +                        if not self.catpagedict[pagename]:
 309 +                            del self.catpagedict[pagename]
 310 +                
 311 +                for match in pattern.finditer(body):
 312 +                    for item in match.group('category').split():
 313 +                        
 314 +                        if item.startswith("[["):
 315 +                            item = item[2:-2]
 316 +                        name_checked = self.request.cfg.cache.page_category_regexact.search(item)
 317 +                        if name_checked and name_checked.group("all") == item:
 318 +                            self.pagedict[pagename] = self.pagedict.get(pagename, set())
 319 +                            self.pagedict[pagename].add(item)
 320 +                            if page_is_category:
 321 +                                self.catcatdict[item] = self.catcatdict.get(item, set())
 322 +                                self.catcatdict[item].add(pagename)
 323 +                            else:
 324 +                                self.catpagedict[item] = self.catpagedict.get(item, set())
 325 +                                self.catpagedict[item].add(pagename)
 326 +            
 327 +            # Update cache
 328 +            cache.update((new_date, self.pagedict, self.catcatdict, self.catpagedict))
 329 +
 330 +    def _get_all_categories(self):
 331 +        result = set(self.catcatdict.keys())
 332 +        for value in self.catcatdict.values():
 333 +            result |= value
 334 +        result |= set(self.catpagedict.keys())
 335 +        return result
 336 +
 337 +    def get_sub_categories(self, category, recursive=False, exclude_template=True):
 338 +        """ Return all sub categories of this category.
 339 +        
 340 +        @param category: category name, or list of names of categories
 341 +        @param recursive: if True, scan sub categories recursively.
 342 +                          Default is False.
 343 +        @param exclude_template: if True, exclude template page.
 344 +                                 Default is True.
 345 +        @rtype: set()
 346 +        @return: set of sub categories
 347 +        """
 348 +        result = self._get_sub_categories(category, recursive, set())
 349 +
 350 +        # exclude template from result
 351 +        if exclude_template:
 352 +            templates = []
 353 +            for item in result:
 354 +                if self.request.cfg.cache.page_template_regexact.search(item) is not None:
 355 +                    templates.append(item)
 356 +            for item in templates:
 357 +                result.remove(item)
 358 +
 359 +        return result
 360 +        
 361 +    def _get_sub_categories(self, category, recursive=False, scanned=set()):
 362 +        """ Return all subcategories of the category.
 363 +        
 364 +        scanned store already scanned categories, to prevent deadly loop.
 365 +        """
 366 +        result = set()
 367 +        scanned.add(category)
 368 +        if isinstance(category, (list,dict,set)):
 369 +            if "all" in category:
 370 +                result = self._get_all_categories()
 371 +            else:
 372 +                for c in category:
 373 +                    result = result | self._get_sub_categories(c, recursive, set())
 374 +
 375 +        elif "all" == category:
 376 +            result = self._get_all_categories()
 377 +
 378 +        else:
 379 +            children = self.catcatdict.get(category)
 380 +            if children:
 381 +                for child in children:
 382 +                    result.add(child)
 383 +                    if child not in scanned and recursive:
 384 +                        result = result | self._get_sub_categories(child, recursive, scanned)
 385 +
 386 +        return result
 387 +    
 388 +    def get_sub_pages(self, category, recursive=False, exclude_template=True):
 389 +        result = set()
 390 +    
 391 +        if isinstance(category, (list,dict,set)):
 392 +            for c in category:
 393 +                result = result | get_sub_pages(c, recursive=recursive)
 394 +            return result
 395 +    
 396 +        if isinstance(category, (list,dict,set)):
 397 +            category_list = set(category)
 398 +        else:
 399 +            category_list = set([category])
 400 +        
 401 +        if recursive:
 402 +            category_list = category_list | self.get_sub_categories(category, recursive=recursive)
 403 +    
 404 +        for c in category_list:
 405 +            result = result | self.catpagedict.get(c, set())
 406 +
 407 +        # exclude template from result
 408 +        if exclude_template:
 409 +            templates = []
 410 +            for item in result:
 411 +                if self.request.cfg.cache.page_template_regex.search(item) is not None:
 412 +                    templates.append(item)
 413 +            for item in templates:
 414 +                result.remove(item)
 415 +        
 416 +        return result    
 417 +
 418 +    def get_templates(self, category, recursive=False):
 419 +        result = set()
 420 +        subpages = self.get_sub_pages(category, recursive, exclude_template=False)
 421 +        for item in subpages:
 422 +            if self.request.cfg.cache.page_template_regexact.search(item) is not None:
 423 +                result.add(item)
 424 +        return result
 425 +    
 426 +    def get_page_category_trail(self, pagename, level=9):
 427 +        result = []
 428 +        self._get_page_category_trail( pagename, level, result)
 429 +        return result
 430 +        
 431 +    def _get_page_category_trail(self, pagename, level, result, scanned=[]):
 432 +        categories = self.pagedict.get(pagename, set())
 433 +        if categories:
 434 +            level -= 1
 435 +            for category in categories: 
 436 +                if category in scanned:
 437 +                    continue
 438 +                branch = scanned[:]
 439 +                branch.append(category)
 440 +                if not self.pagedict.get(category) or level == 0:
 441 +                    result.append(branch)
 442 +                else:
 443 +                    self._get_page_category_trail(category, level, result, branch)
 444 +
 445 +
 446 +def formatList(request, itemlist, column=3, show_capital=True):
 447 +    """
 448 +    These functions: formatList, shorList, columnList is from MediaWiki.
 449 +    Modified by Jiang Xin <worldhello.net@gmail.com>
 450 +    """
 451 +    cutoff = max(column*2, column+1)
 452 +    if len(itemlist) > cutoff and column>1:
 453 +        return columnList(request, itemlist, column=column, show_capital=show_capital)
 454 +    elif len(itemlist) > 0:
 455 +        return shortList(request, itemlist, show_capital=show_capital)
 456 +    else:
 457 +        return [""]
 458 +
 459 +def shortList(request, itemlist, show_capital=True):
 460 +    _ = request.getText
 461 +    startchar = itemlist[0][0][0]
 462 +    result = []
 463 +
 464 +    if show_capital:
 465 +        result += ["<h3>" + startchar + "</h3>"]
 466 +
 467 +    result += ["<ul><li>" + itemlist[0][1] + "</li>"]
 468 +
 469 +    for i in range(1,len(itemlist)):
 470 +        if show_capital and startchar != itemlist[i][0][0]:
 471 +            startchar = itemlist[i][0][0]
 472 +            result += ["</ul><h3>" + startchar + "</h3>\n<ul>"]
 473 +        result += ["<li>"+itemlist[i][1]+"</li>"]
 474 +    result += ["</ul>"]
 475 +    return result
 476 +
 477 +def columnList(request, itemlist, column=3, show_capital=True):
 478 +    _ = request.getText
 479 +    if not column:
 480 +        column = 3
 481 +    chunk = len(itemlist) // column
 482 +    result = ['<table class="borderless" width="100%"><tr valign="top">']
 483 +    
 484 +    startChunk = 0
 485 +    endChunk = chunk
 486 +    startchar = 'none'
 487 +    
 488 +    for chunkIndex in range(0, column):
 489 +        result.append("<td>")
 490 +        atColumnTop = True
 491 +        
 492 +        for i in range(startChunk, endChunk):
 493 +            if i >= len(itemlist):
 494 +                break
 495 +            
 496 +            if startchar != itemlist[i][0][0] or atColumnTop:
 497 +                if show_capital and not atColumnTop:
 498 +                    result.append("</ul>")
 499 +                if not show_capital:
 500 +                    if atColumnTop:
 501 +                        result.append("<ul>")
 502 +                else:
 503 +                    if itemlist[i][0][0] == startchar:
 504 +                        result.append("<h3>" + startchar + " " + _("cont.") + "</h3>\n<ul>")
 505 +                    else:
 506 +                        startchar = itemlist[i][0][0]
 507 +                        result.append("<h3>" + startchar + "</h3>\n<ul>")
 508 +                atColumnTop = False
 509 +
 510 +            result.append("<li>" + itemlist[i][1] + "</li>")
 511 +        
 512 +        startChunk = endChunk
 513 +        endChunk += chunk + 1
 514 +        if not atColumnTop:
 515 +            result.append("</ul>")
 516 +      
 517 +        result.append("</td>")
 518 +    
 519 +    result.append("</tr></table>")
 520 +
 521 +    return result
 522 +
 523 
60010_macro_showcategory.patch

4.2. ShowCategory extension

Extension: add new page dialog for creating new sub category or sub page.

{i} This patch depends on MoinMoinPatch/MultipleTemplatesSupportForNewPageMaro

   1 diff -r 7401f51c198b MoinMoin/macro/ShowCategory.py
   2 --- a/MoinMoin/macro/ShowCategory.py	Tue Nov 25 11:08:51 2008 +0800
   3 +++ b/MoinMoin/macro/ShowCategory.py	Tue Nov 25 11:13:23 2008 +0800
   4 @@ -8,7 +8,7 @@
   5      @license: GNU GPL, see COPYING for details.
   6  """
   7  
   8 -from MoinMoin import wikiutil2
   9 +from MoinMoin import wikiutil, wikiutil2
  10  from MoinMoin.Page import Page
  11  
  12  _sysmsg = '<p><strong class="%s">%s</strong></p>'
  13 @@ -19,26 +19,55 @@
  14                    recursive=False, items=0, skipitems=0, exclude_template=True):
  15      cc = wikiutil2.CategoryCache(request)
  16      _ = request.getText
  17 +    summary_of_subcategories = []
  18 +    summary_of_subpages = []
  19      
  20      if "all" in categorylist:
  21 +        categorylist = ["all"]
  22          show_cat = True
  23          show_page = False
  24          recursive = False
  25 -        summary_of_subcategories = "<h2>" + _("All categories") + "</h2>\n" + \
  26 -                                   _("There are %(count)d categories in this wiki.")
  27 -        summary_of_subpages      = ""
  28 +        summary_of_subcategories = ["<h2>" + _("All categories") + "</h2>",
  29 +                                    _("There are %(count)d categories in this wiki."),
  30 +                                   ]
  31 +        summary_of_subpages      = []
  32      else:
  33 -        summary_of_subcategories = "<h2>" + _("Subcategories of <b>%(category)s</b>") + "</h2>\n" + \
  34 -                                   _("This category has the following %(count)d subcategories.")
  35 -        summary_of_subpages      = "<h2>" + _("Pages in category <b>%(category)s</b>") + "</h2>\n" + \
  36 -                                   _("There are %(count)d pages are in this category.")
  37 -        
  38 +        summary_of_subcategories = ["<h2>" + _("Subcategories of <b>%(category)s</b>") + "</h2>",
  39 +                                    u"<span id='subcategory-heading'>" + _("This category has the following %(count)d subcategories.") + u"</span>",
  40 +                                    u"<div id='new-subcategory-dialog' class='new-subcategory-dialog'>",
  41 +                                    "%(newsubcategory)s"
  42 +                                    u"</div>",
  43 +                                    "<script type=\"text/javascript\">",
  44 +                                    "if (window.showToggle) {",
  45 +                                    "  showToggle('subcategory-heading', ['new-subcategory-dialog'], '', \"" + _("add") + "\", \"" + _("hide") + "\", true);",
  46 +                                    "}",
  47 +                                    "</script>\n",
  48 +                                   ]
  49 +        summary_of_subpages      = ["<h2>" + _("Pages in category <b>%(category)s</b>") + "</h2>",
  50 +                                    u"<span id='subpage-heading'>" + _("There are %(count)d pages are in this category.") + u"</span>",
  51 +                                    u"<div id='new-subpage-dialog' class='new-subpage-dialog'>",
  52 +                                    "%(newsubpage)s"
  53 +                                    u"</div>",
  54 +                                    "<script type=\"text/javascript\">",
  55 +                                    "if (window.showToggle) {",
  56 +                                    "  showToggle('subpage-heading', ['new-subpage-dialog'], '', \"" + _("add") + "\", \"" + _("hide") + "\", true);",
  57 +                                    "}",
  58 +                                    "</script>\n",
  59 +                                   ]
  60 +    
  61 +    summary_of_subcategories = '\n'.join(summary_of_subcategories)
  62 +    summary_of_subpages = '\n'.join(summary_of_subpages)
  63      result = []
  64  
  65      # show sub category
  66 +    Parser = wikiutil.searchAndImportPlugin(request.cfg, "parser", request.page.pi['format'])
  67      if show_cat:
  68          for category in categorylist:
  69              itemlist = []
  70 +            if category != "all":
  71 +                newsubcategory = wikiutil.renderText(request, Parser, u" <<NewPage(CategoryTemplate, %s, category=%s, validate=category)>>" % (_("Create a sub category"),category))
  72 +            else:
  73 +                newsubcategory = u""
  74              for i in sorted( cc.get_sub_categories(category,recursive=recursive, exclude_template=exclude_template) ):
  75                  name = i
  76                  page = Page(request, name)
  77 @@ -65,7 +94,7 @@
  78                      itemlist=[ (x[-2], x[-1]) for x in itemlist ]
  79      
  80              if show_summary:
  81 -                result += [ summary_of_subcategories % {'category': category, 'count': len(itemlist)} ]
  82 +                result += [ summary_of_subcategories % {'category': category, 'count': len(itemlist), 'newsubcategory': newsubcategory} ]
  83              
  84              if skipitems:
  85                  itemlist=itemlist[skipitems:]
  86 @@ -76,7 +105,11 @@
  87      # show pages belong to this category
  88      if show_page:
  89          for category in categorylist:
  90 +            template_pages = cc.get_templates(category, True)
  91 +            if template_pages:
  92 +                template_pages.insert(0, ('', _('<No addition>')))
  93              itemlist = []
  94 +            newsubpage = wikiutil.renderText(request, Parser, u" <<NewPage(%s, %s, category=%s, validate=nocategory)>>" % (template_pages, _("Create a sub page"),category))
  95              for i in sorted( cc.get_sub_pages(category,recursive=recursive, exclude_template=exclude_template) ):
  96                  name = i
  97                  page = Page(request, name)
  98 @@ -102,7 +135,7 @@
  99                      itemlist=[ (x[-2], x[-1]) for x in itemlist ]
 100              
 101              if show_summary:
 102 -                result += [ summary_of_subpages % {'category': category, 'count': len(itemlist)} ]
 103 +                result += [ summary_of_subpages % {'category': category, 'count': len(itemlist), 'newsubpage': newsubpage} ]
 104  
 105              if skipitems:
 106                  itemlist=itemlist[skipitems:]
 107 diff -r 7401f51c198b MoinMoin/wikiutil2.py
 108 --- a/MoinMoin/wikiutil2.py	Tue Nov 25 11:08:51 2008 +0800
 109 +++ b/MoinMoin/wikiutil2.py	Tue Nov 25 11:13:23 2008 +0800
 110 @@ -254,20 +254,44 @@
 111          return result    
 112  
 113      def get_templates(self, category, recursive=False):
 114 -        result = set()
 115 -        subpages = self.get_sub_pages(category, recursive, exclude_template=False)
 116 -        for item in subpages:
 117 -            if self.request.cfg.cache.page_template_regexact.search(item) is not None:
 118 -                result.add(item)
 119 +        """ Get templates list suitable for category.
 120 +        """
 121 +        result = []
 122 +        category_list = self._get_page_category_list('', category=category)
 123 +        for category in category_list:
 124 +            if category == 'CategoryCategory':
 125 +                continue
 126 +            subpages = self.get_sub_pages(category, recursive, exclude_template=False)
 127 +            for item in subpages:
 128 +                if self.request.cfg.cache.page_template_regexact.search(item) is not None:
 129 +                    if item not in result:
 130 +                        result.append(item)
 131 +            if result:
 132 +                break
 133          return result
 134 -    
 135 -    def get_page_category_trail(self, pagename, level=9):
 136 +
 137 +    def get_page_category_trail(self, pagename, level=9, category=''):
 138 +        """ Get category trail for page.
 139 +        
 140 +        For non-exist page, if we known category it should belong to, set category parameter.
 141 +        """
 142          result = []
 143 -        self._get_page_category_trail( pagename, level, result)
 144 +        catlist = set()
 145 +        if category:
 146 +            catlist = set(category.split(','))
 147 +        if pagename:
 148 +            catlist = catlist | self.pagedict.get(pagename, set())
 149 +        if catlist:
 150 +            self._get_page_category_trail( catlist, level, result)
 151          return result
 152 -        
 153 +
 154      def _get_page_category_trail(self, pagename, level, result, scanned=[]):
 155 -        categories = self.pagedict.get(pagename, set())
 156 +        # the first argument maybe a set of categories
 157 +        if isinstance(pagename, set):
 158 +            categories = pagename
 159 +        # the first argument is page name.
 160 +        else:
 161 +            categories = self.pagedict.get(pagename, set())
 162          if categories:
 163              level -= 1
 164              for category in categories: 
 165 @@ -280,6 +304,18 @@
 166                  else:
 167                      self._get_page_category_trail(category, level, result, branch)
 168  
 169 +    def _get_page_category_list(self, pagename, level=9, category=''):
 170 +        category_list = []
 171 +        category_trail = self.get_page_category_trail(pagename, level=level, category=category)
 172 +        if category_trail:
 173 +            maxdepth = max ([len(trail) for trail in category_trail])
 174 +            for i in range(0,maxdepth):
 175 +                for trail in category_trail:
 176 +                    if len(trail) < i+1:
 177 +                        continue
 178 +                    if trail[i] != 'CategoryCategory' and trail[i] not in category_list:
 179 +                        category_list.append(trail[i])
 180 +        return category_list
 181  
 182  def formatList(request, itemlist, column=3, show_capital=True):
 183      """
60015_newpage_dialog_in_showcategory_page.patch

5. Usage

Code

Description

<<ShowCategory(CategoryNews)>>

Display a summary page for CategoryNews

<<ShowCategory>>

The category name is the name of current page. Display a summary page for it.

<<ShowCategory(all)>>

Display a list of all categories

<<ShowCategory(CategoryNews, nocategories)>>

Only display sub pages of CategoryNews, do not show sub categories.

<<ShowCategory(CategoryNews, nopages)>>

Only display sub categories of CategoryNews, do not show sub pages.

<<ShowCategory(CategoryNews, nocat, nosummary)>>

Do not show sub categories, and do not show summary of sub pages, only display list of sub pages.

<<ShowCategory(CategoryNews, nocapital,nosum)>>

Do not show summarys, and not show capital word in column list.

<<ShowCategory(CategoryNews, recursive, descending)>>

Show sub categories and sub pages recursively, and order by descending.

<<ShowCategory(CategoryNews, rec, cat=0, items=20,skipitems=5,column=2,sort=timestamp)>>

Show subpages recursively, sort by modify time, and only show item 6 to 26 in two columns.

JiangXin

7. License

GPL.

8. Bugs

I tried to adopt "ShowCategory" to MoinMoin 1.8.6. Unfortunately the file MoinMoin/wikiutil2.py does not exist. The following happened:

rudi@rudi72:~/moin-1.8.6$ patch <60010_macro_showcategory.patch
The next patch would create the file ShowCategory.py,
which already exists!  Assume -R? [n]
Apply anyway? [n]
Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file ShowCategory.py.rej
can't find file to patch at input line 220
Perhaps you should have used the -p or --strip option?
The text leading up to this was:
--------------------------
|diff -r 0bfe351fb737 MoinMoin/wikiutil2.py
|--- a/MoinMoin/wikiutil2.py    Tue Nov 25 09:40:25 2008 +0800
|+++ b/MoinMoin/wikiutil2.py    Tue Nov 25 10:17:40 2008 +0800
--------------------------
File to patch: MoinMoin/wikiutil2.py
patching file MoinMoin/wikiutil2.py
Hunk #1 FAILED at 8.
Hunk #2 FAILED at 69.
2 out of 2 hunks FAILED -- saving rejects to file MoinMoin/wikiutil2.py.rej

What can I do to fix it? RudolfReuter 2009-12-30 11:13 MEZ

Hi RudolfReuter

please read HelpOnVariables and use SIG for a signature. wikiutil2 was never a second file from moin. May be the author has done a copy of it. -- ReimarBauer 2009-12-31 14:26:48

9. Discussion

9.1. Feature Request

First of all thanks for such a nice macro for moinmoin "ShowCategory". I am using it for my categories in my wiki by using the sort=timestamp. I have one question regarding to this macro. Is it possible to show the modify timeStamp with pages name list? e.g.
pageX 15m ago by Jiang
pageY 07:14 by Tom
PageZ 2010-02-16 by Jiang

At the moment, i am using it like this.

<<ShowCategory(nocapital,items=20,nosum,nocat,recursive,descending,column=1,sort=timestamp)>>

it shows me the pages list for my category and sort it by time stamp. I want to see also time stamp with page name (like moinmoin Recent Changes). So i can easily see that, at what time i made changes for my category pages. Maybe it would be also better to see that who has changed.

I tried some ways, but i couldn't able to print time stamp with page list.

from MoinMoin.util import timefuncs
date = time.strftime("%d.%m.%y", timefuncs.tmtuple((wikiutil.version2timestamp(timestamp))) ) # UTC

Anybody has an idea, that how can i print the time stamp with page list. I shall be very thankful.

@SIG

MoinMoin: MacroMarket/ShowCategory (last edited 2010-07-30 21:03:19 by 178)