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