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 # 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 execute(macro, args): 94 95 """ 96 Execute the 'macro' with the given 'args': an optional list of selected 97 category names (categories whose pages are to be shown). 98 """ 99 100 request = macro.request 101 fmt = macro.formatter 102 page = fmt.page 103 104 # Interpret the arguments. 105 106 try: 107 selected_category_names = wikiutil.parse_quoted_separated(args, name_value=False) 108 except AttributeError: 109 selected_category_names = args.split(",") 110 111 selected_category_names = [arg for arg in selected_category_names if arg] 112 113 # Get the categories. 114 115 categories = getCategoryMapping(getCategories(request), request) 116 117 # Generate a menu with the categories, together with expanded submenus for 118 # the categories employed by the current page, the category represented by 119 # the current page, or for those categories specified in the macro 120 # arguments. 121 122 output = [] 123 output.append(fmt.bullet_list(on=1, attr={"class" : "category-menu"})) 124 125 for category in categories: 126 category_name, category_pagename = category 127 128 page_is_category = page.page_name == category_pagename 129 category_membership_regexp = re.compile(category_membership_regexp_str % category_pagename) 130 page_in_category = category_membership_regexp.search(page.get_raw_body()) 131 132 # Generate the submenu where appropriate. 133 134 if selected_category_names and category_name in selected_category_names or \ 135 not selected_category_names and (page_is_category or page_in_category): 136 137 if page_is_category: 138 output.append(fmt.listitem(on=1, attr={"class" : "selected current"})) 139 output.append(fmt.text(category_name)) 140 else: 141 output.append(fmt.listitem(on=1, attr={"class" : "selected"})) 142 output.append(fmt.pagelink(on=1, pagename=category_pagename)) 143 output.append(fmt.text(category_name)) 144 output.append(fmt.pagelink(on=0, pagename=category_pagename)) 145 146 output.append(fmt.bullet_list(on=1, attr={"class" : "category-submenu"})) 147 148 # Get the pages and page names in the category. 149 150 pages_in_category = getPages(category_pagename, request) 151 pagenames_in_category = [p.page_name for p in pages_in_category] 152 153 # Visit each page in the category. 154 155 last_parts = [] 156 157 for page_in_category in pages_in_category: 158 pagename = page_in_category.page_name 159 160 if page.page_name == pagename: 161 output.append(fmt.listitem(on=1, attr={"class" : "selected"})) 162 else: 163 output.append(fmt.listitem(on=1)) 164 output.append(fmt.pagelink(on=1, pagename=pagename)) 165 166 # Abbreviate long hierarchical names. 167 168 parts = pagename.split("/") 169 common = 0 170 for last, current in map(None, last_parts, parts): 171 if last == current: 172 common += 1 173 else: 174 break 175 176 # Use an em-dash to indicate subpages. 177 178 prefix = u"\u2014" * common 179 suffix = "/".join(parts[common:]) 180 181 output.append(fmt.text("%s %s" % (prefix, suffix))) 182 output.append(fmt.pagelink(on=0, pagename=pagename)) 183 output.append(fmt.listitem(on=0)) 184 185 last_parts = parts 186 187 output.append(fmt.bullet_list(on=0)) 188 output.append(fmt.listitem(on=0)) 189 190 # Otherwise generate a simple link. 191 192 else: 193 output.append(fmt.listitem(on=1)) 194 output.append(fmt.pagelink(on=1, pagename=category_pagename)) 195 output.append(fmt.text(category_name)) 196 output.append(fmt.pagelink(on=0, pagename=category_pagename)) 197 output.append(fmt.listitem(on=0)) 198 199 output.append(fmt.bullet_list(on=0)) 200 201 return ''.join(output) 202 203 # vim: tabstop=4 expandtab shiftwidth=4