1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - CategoryMenu Macro 4 5 @copyright: 2008 by Paul Boddie <paul@boddie.org.uk> 6 @copyright: 2000-2004 Juergen Hermann <jh@web.de>, 7 2005-2008 MoinMoin:ThomasWaldmann. 8 @license: GNU GPL (v2 or later), see COPYING.txt for details. 9 """ 10 11 from MoinMoin.Page import Page 12 from MoinMoin import wikiutil, search, version 13 import re 14 15 __version__ = "0.1" 16 17 Dependencies = ['pages'] 18 19 # Regular expressions where MoinMoin does not provide the required support. 20 21 category_regexp = None 22 23 # Utility functions. 24 25 def isMoin15(): 26 return version.release.startswith("1.5.") 27 28 def getCategoryPattern(request): 29 global category_regexp 30 31 try: 32 return request.cfg.cache.page_category_regexact 33 except AttributeError: 34 35 # Use regular expression from MoinMoin 1.7.1 otherwise. 36 37 if category_regexp is None: 38 category_regexp = re.compile(u'^%s$' % ur'(?P<all>Category(?P<key>(?!Template)\S+))', re.UNICODE) 39 return category_regexp 40 41 # The main activity functions. 42 43 def getCategories(request): 44 45 """ 46 From the AdvancedSearch macro, return a list of category page names using 47 the given 'request'. 48 """ 49 50 # This will return all pages with "Category" in the title. 51 52 cat_filter = getCategoryPattern(request).search 53 pagenames = request.rootpage.getPageList(filter=cat_filter) 54 pagenames.sort() 55 return pagenames 56 57 def getCategoryMapping(category_pagenames, request): 58 59 """ 60 For the given 'category_pagenames' return a list of tuples of the form 61 (category name, category page name) using the given 'request'. 62 """ 63 64 cat_pattern = getCategoryPattern(request) 65 mapping = [] 66 for pagename in category_pagenames: 67 name = cat_pattern.match(pagename).group("key") 68 if name != "Category": 69 mapping.append((name, pagename)) 70 mapping.sort() 71 return mapping 72 73 def getPages(pagename, request): 74 75 "Return the links minus category links for 'pagename' using the 'request'." 76 77 query = search.QueryParser().parse_query('"%s"' % pagename) 78 if isMoin15(): 79 results = search.searchPages(request, query) 80 results.sortByPagename() 81 else: 82 results = search.searchPages(request, query, "page_name") 83 84 cat_pattern = getCategoryPattern(request) 85 pages = [] 86 for page in results.hits: 87 if not cat_pattern.match(page.page_name): 88 pages.append(page) 89 return pages 90 91 def execute(macro, args): 92 93 """ 94 Execute the 'macro' with the given 'args': an optional list of selected 95 category names (categories whose pages are to be shown). 96 """ 97 98 request = macro.request 99 fmt = macro.formatter 100 page = fmt.page 101 102 # Interpret the arguments. 103 104 try: 105 selected_category_names = wikiutil.parse_quoted_separated(args, name_value=False) 106 except AttributeError: 107 selected_category_names = args.split(",") 108 109 selected_category_names = [arg for arg in selected_category_names if arg] 110 111 # Get the categories. 112 113 categories = getCategoryMapping(getCategories(request), request) 114 115 # Generate a menu with the categories, together with expanded submenus for 116 # the categories employed by the current page, the category represented by 117 # the current page, or for those categories specified in the macro 118 # arguments. 119 120 output = [] 121 output.append(fmt.bullet_list(on=1, attr={"class" : "category-menu"})) 122 123 for category in categories: 124 category_name, category_pagename = category 125 126 pages_in_category = getPages(category_pagename, request) 127 pagenames_in_category = [p.page_name for p in pages_in_category] 128 page_is_category = page.page_name == category_pagename 129 130 # Generate the submenu where appropriate. 131 132 if selected_category_names and category_name in selected_category_names or \ 133 not selected_category_names and ( 134 page_is_category or page.page_name in pagenames_in_category): 135 136 if page_is_category: 137 output.append(fmt.listitem(on=1, attr={"class" : "selected current"})) 138 output.append(fmt.text(category_name)) 139 else: 140 output.append(fmt.listitem(on=1, attr={"class" : "selected"})) 141 output.append(fmt.pagelink(on=1, pagename=category_pagename)) 142 output.append(fmt.text(category_name)) 143 output.append(fmt.pagelink(on=0, pagename=category_pagename)) 144 145 output.append(fmt.bullet_list(on=1, attr={"class" : "category-submenu"})) 146 147 # Visit each page in the category. 148 149 last_parts = [] 150 151 for page_in_category in pages_in_category: 152 pagename = page_in_category.page_name 153 154 if page.page_name == pagename: 155 output.append(fmt.listitem(on=1, attr={"class" : "selected"})) 156 else: 157 output.append(fmt.listitem(on=1)) 158 output.append(fmt.pagelink(on=1, pagename=pagename)) 159 160 # Abbreviate long hierarchical names. 161 162 parts = pagename.split("/") 163 common = 0 164 for last, current in map(None, last_parts, parts): 165 if last == current: 166 common += 1 167 else: 168 break 169 170 # Use an em-dash to indicate subpages. 171 172 prefix = u"\u2014" * common 173 suffix = "/".join(parts[common:]) 174 175 output.append(fmt.text("%s %s" % (prefix, suffix))) 176 output.append(fmt.pagelink(on=0, pagename=pagename)) 177 output.append(fmt.listitem(on=0)) 178 179 last_parts = parts 180 181 output.append(fmt.bullet_list(on=0)) 182 output.append(fmt.listitem(on=0)) 183 184 # Otherwise generate a simple link. 185 186 else: 187 output.append(fmt.listitem(on=1)) 188 output.append(fmt.pagelink(on=1, pagename=category_pagename)) 189 output.append(fmt.text(category_name)) 190 output.append(fmt.pagelink(on=0, pagename=category_pagename)) 191 output.append(fmt.listitem(on=0)) 192 193 output.append(fmt.bullet_list(on=0)) 194 195 return ''.join(output) 196 197 # vim: tabstop=4 expandtab shiftwidth=4