Changeset 3083
- Timestamp:
- 03/23/06 00:18:07 (7 years ago)
- Location:
- trac/plugins
- Files:
-
- 9 added
- 2 copied
-
. (added)
-
tracnav (added)
-
tracnav/COPYING (added)
-
tracnav/README (added)
-
tracnav/setup.py (added)
-
tracnav/tracnav (added)
-
tracnav/tracnav/__init__.py (added)
-
tracnav/tracnav/htdocs (added)
-
tracnav/tracnav/htdocs/css (added)
-
tracnav/tracnav/htdocs/css/tracnav.css (copied) (copied from trac/trunk/htdocs/tracnav.css)
-
tracnav/tracnav/tracnav.py (copied) (copied from trac/trunk/wiki-macros/TracNav.py) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trac/plugins/tracnav/tracnav/tracnav.py
r3082 r3083 1 1 # -*- coding: utf-8 -*- 2 2 """ 3 = TracNav: The Navigation Bar for Trac =3 = !TracNav: The Navigation Bar for Trac = 4 4 5 5 This macro implements a fully customizable navigation bar for the Trac … … 7 7 and can be edited like any other wiki page through the web 8 8 interface. The navigation bar supports hierarchical ordering of 9 topics. The design of TracNav mimics the design of theTracGuideToc10 that was originally supplied with Trac. The drawback of TracGuideToc9 topics. The design of !TracNav mimics the design of the !TracGuideToc 10 that was originally supplied with Trac. The drawback of !TracGuideToc 11 11 is that it is not customizable without editing its source code and 12 12 that it does not support hierarchical ordering. 13 13 14 15 14 == Installation == 16 15 17 To install TracNav, place the file `TracNav.py` in the `wiki-macros` 18 subdirectory and the accompanying `tracnav.css` file in the 19 `htdocs` subdirectory of your Trac project. Add this line 20 {{{ 21 @import url(<?cs var:chrome.href ?>/site/tracnav.css); 22 }}} 23 to the `templates/site_css.cs` file of your Trac project. 24 25 The `tracnav.css` file defines the styles for displaying the 26 navigation bar. These styles build upon the styles for !TracGuideToc 27 that come with your Trac distribution. If you just install the macro 28 but miss to install the style file, TracNav will work but look 29 somewhat strange. 30 16 See http://projects.edgewall.com/trac/wiki/TracPlugins. 31 17 32 18 == Usage == 33 19 34 To use TracNav, create an index page for your site and call the20 To use !TracNav, create an index page for your site and call the 35 21 TracNav macro on each page, where the navigation bar should be 36 22 displayed. The index page is a regular wiki page. The page with the … … 38 24 be displayed in the navigation bar. 39 25 40 To display the navigation bar on a page, you must call the TracNav26 To display the navigation bar on a page, you must call the !TracNav 41 27 macro on that page an pass the name of your table of contents as 42 28 argument. 43 29 30 == Additional information and a life example == 31 32 Please visit: http://svn.ipd.uka.de/trac/javaparty/wiki/TracNav. 44 33 45 34 == Author and License == … … 65 54 }}} 66 55 67 == Additional information and a life example ==68 69 Please visit: http://svn.ipd.uka.de/trac/javaparty/wiki/TracNav70 56 """ 71 57 … … 73 59 74 60 import re 75 from trac.wiki.api import WikiSystem 61 from trac.core import Component 62 from trac.wiki.api import WikiSystem, IWikiMacroProvider 63 from trac.web.chrome import ITemplateProvider 76 64 from trac.wiki.model import WikiPage 77 65 from trac.wiki.formatter import Formatter, OneLinerFormatter … … 81 69 LISTRULE = re.compile(r"^(?P<indent>[ \t\v]+)\* +(?P<rest>.*)$", re.M) 82 70 ALLOWED_MACROS = ["image"] 83 84 def get_toc(hdf, env, preview, name):85 """86 Fetch the wiki page containing the toc, if available.87 """88 if preview:89 cur_path = hdf.getValue('HTTP.PathInfo', '')90 toc_path = "/wiki/" + name91 if cur_path == toc_path:92 return hdf.getValue('args.text', '')93 94 if WikiSystem(env).has_page(name):95 return WikiPage(env, name).text96 else:97 return ''98 71 99 72 … … 109 82 return out.getvalue(), self.link 110 83 111 def __init__(self, env ):84 def __init__(self, env, req = None): 112 85 OneLinerFormatter.__init__(self, env) 86 # OneLinerFormatter sets req to None 87 self.req = req 113 88 self.link = None 114 89 … … 133 108 134 109 135 def get_toc_entry(toc_text, env): 136 """ 137 Parse and format the entries in toc_text. 138 """ 139 formatter = TocFormatter(env) 140 for match in LISTRULE.finditer(toc_text): 141 indent = len(match.group('indent')) 142 label, link = formatter.format_toc(match.group('rest')) 143 yield indent, link, label 144 145 146 def get_toc_entry_and_indent(gen): 147 """ 148 Filter for get_toc_entry(). The first call to next() returns the 149 indentation level of the next entry (or -1 if there are no more 150 entries) and the second call returns the entry itself. 151 """ 152 while True: 153 try: 154 indent, link, label = gen.next() 155 except StopIteration: 156 yield -1 157 return 158 yield indent 159 yield link, label 160 161 162 def _parse_toc(gen, next_indent, level = 0): 163 toclist = [] 164 if next_indent > level: 165 sublist, next_indent = _parse_toc(gen, next_indent, level + 1) 166 if next_indent < level: # level is empty 167 return sublist, next_indent 168 else: # broken indentation structure 169 toclist.append((None, None, sublist)) 170 while True: 171 if next_indent == level: 172 (link, label), next_indent = gen.next(), gen.next() 173 if next_indent > level: 174 sublist, next_indent = _parse_toc(gen, next_indent, level + 1) 175 toclist.append((link, label, sublist)) 110 class TracNav(Component): 111 112 from trac.core import implements 113 implements(IWikiMacroProvider, ITemplateProvider) 114 115 def get_toc(self, req, name): 116 """ 117 Fetch the wiki page containing the toc, if available. 118 """ 119 preview = req.hdf.getValue('args.preview', "") 120 121 if preview: 122 cur_path = req.hdf.getValue('HTTP.PathInfo', '') 123 toc_path = "/wiki/" + name 124 if cur_path == toc_path: 125 return req.hdf.getValue('args.text', '') 126 127 if WikiSystem(self.env).has_page(name): 128 return WikiPage(self.env, name).text 129 else: 130 return '' 131 132 133 def get_toc_entry(self, toc_text, req): 134 """ 135 Parse and format the entries in toc_text. 136 """ 137 formatter = TocFormatter(self.env, req) 138 for match in LISTRULE.finditer(toc_text): 139 indent = len(match.group('indent')) 140 label, link = formatter.format_toc(match.group('rest')) 141 yield indent, link, label 142 143 144 def get_toc_entry_and_indent(self, gen): 145 """ 146 Filter for get_toc_entry(). The first call to next() returns the 147 indentation level of the next entry (or -1 if there are no more 148 entries) and the second call returns the entry itself. 149 """ 150 while True: 151 try: 152 indent, link, label = gen.next() 153 except StopIteration: 154 yield -1 155 return 156 yield indent 157 yield link, label 158 159 160 def _parse_toc(self, gen, next_indent, level = 0): 161 toclist = [] 162 if next_indent > level: 163 sublist, next_indent = self._parse_toc(gen, next_indent, level + 1) 164 if next_indent < level: # level is empty 165 return sublist, next_indent 166 else: # broken indentation structure 167 toclist.append((None, None, sublist)) 168 while True: 169 if next_indent == level: 170 (link, label), next_indent = gen.next(), gen.next() 171 if next_indent > level: 172 sublist, next_indent = self._parse_toc(gen, next_indent, level + 1) 173 toclist.append((link, label, sublist)) 174 else: 175 toclist.append((link, label, None)) 176 176 else: 177 toclist.append((link, label, None)) 178 else: 179 assert next_indent < level 180 return toclist, next_indent 181 182 183 def parse_toc(toc_text, env): 184 """ 185 Recursively construct the toc tree using _parse_toc(). 186 """ 187 gen = get_toc_entry_and_indent(get_toc_entry(toc_text, env)) 188 toc, _ = _parse_toc(gen, gen.next()) 189 return toc 190 191 192 def execute(hdf, args, env): 193 """ 194 Main routine of the wiki macro. 195 """ 196 #env.log.debug("hdf: %s", hdf) 197 preview = hdf.getValue('args.preview', "") 198 curpage = hdf.getValue('wiki.page_name', "") 199 200 # split the argument to get the wiki page names to include 201 names = (args or "TOC").split('|') 202 203 # Parsing the tocS 204 tocs = [] 205 for name in names: 206 toc = parse_toc(get_toc(hdf, env, preview, name), env) 207 if not toc: 208 toc = parse_toc(' * TOC "%s" is empty!' % name, env) 209 tocs.append((name, toc)) 210 211 col = 0 212 html = '%s<div class="wiki-toc trac-nav">\n' % indentation(col) 213 col += 1 214 html += '%s<h2><a href="%s">TracNav</a> menu</h2>\n' % \ 215 (indentation(col), TRACNAVHOME) 216 217 for name, toc in tocs: 218 (found, filtered) = filter_toc(curpage, toc, 0) 219 if found: 220 html += display_all(hdf, env, name, curpage, filtered, col) 221 else: 222 html += display_all(hdf, env, name, curpage, toc, col) 223 col -= 1 224 html += '%s</div>\n' % indentation(col) 225 return html 226 227 228 229 def filter_toc(curpage, toc, level): 230 found = 0 231 result = [] 232 for name, title, sub in toc: 233 if sub == None: 234 if name == curpage: 235 found = 1 236 result.append((name, title, None)) 237 else: 238 (subfound, subtoc) = filter_toc(curpage, sub, level + 1) 239 if subfound: 240 found = 1 241 if subfound or (name == None): 242 if level == 0 and name != None: 243 prepended = [(name, title, subtoc)] 244 prepended.extend(result) 245 result = prepended 177 assert next_indent < level 178 return toclist, next_indent 179 180 181 def parse_toc(self, toc_text, req = None): 182 """ 183 Recursively construct the toc tree using _parse_toc(). 184 """ 185 gen = self.get_toc_entry(toc_text, req) 186 gen = self.get_toc_entry_and_indent(gen) 187 toc, _ = self._parse_toc(gen, gen.next()) 188 return toc 189 190 191 def execute(self, req, args): 192 """ 193 Main routine of the wiki macro. 194 """ 195 curpage = req.hdf.getValue('wiki.page_name', "") 196 197 # split the argument to get the wiki page names to include 198 names = (args or "TOC").split('|') 199 200 # Parsing the tocS 201 tocs = [] 202 for name in names: 203 toc_text = self.get_toc(req, name) 204 toc = self.parse_toc(toc_text, req) 205 if not toc: 206 toc = self.parse_toc(' * TOC "%s" is empty!' % name) 207 tocs.append((name, toc)) 208 209 col = 0 210 html = '%s<div class="wiki-toc trac-nav">\n' % self.indentation(col) 211 col += 1 212 html += '%s<h2><a href="%s">TracNav</a> menu</h2>\n' % \ 213 (self.indentation(col), TRACNAVHOME) 214 215 for name, toc in tocs: 216 (found, filtered) = self.filter_toc(curpage, toc) 217 if found: 218 html += self.display_all(req, name, filtered, col) 219 else: 220 html += self.display_all(req, name, toc, col) 221 col -= 1 222 html += '%s</div>\n' % self.indentation(col) 223 224 from trac.web.chrome import add_stylesheet 225 add_stylesheet(req, 'tracnav/css/tracnav.css') 226 return html 227 228 229 def filter_toc(self, curpage, toc, level = 0): 230 found = 0 231 result = [] 232 for name, title, sub in toc: 233 if sub == None: 234 if name == curpage: 235 found = 1 236 result.append((name, title, None)) 237 else: 238 (subfound, subtoc) = self.filter_toc(curpage, sub, level + 1) 239 if subfound: 240 found = 1 241 if subfound or (name == None): 242 if level == 0 and name != None: 243 prepended = [(name, title, subtoc)] 244 prepended.extend(result) 245 result = prepended 246 else: 247 result.append((name, title, subtoc)) 246 248 else: 247 result.append((name, title, subtoc)) 249 result.append((name, title, [])) 250 return (found, result) 251 252 253 def indentation(self, col): 254 return ' ' * col 255 256 257 def display_all(self, req, name, toc, col): 258 preview = req.hdf.getValue('args.preview', "") 259 curpage = req.hdf.getValue('wiki.page_name', "") 260 html = '' 261 262 if (not preview) and req.hdf.getValue('trac.acl.WIKI_MODIFY', ''): 263 html += '%s<div class="edit"><a href="%s?edit=yes">edit</a></div>\n' % \ 264 (self.indentation(col), self.env.href.wiki(name)) 265 html += '%s<ul>\n' % self.indentation(col) 266 col += 1 267 html += self.display(curpage, toc, 0, col) 268 col -= 1 269 html += '%s</ul>\n' % self.indentation(col) 270 return html 271 272 273 def display(self, curpage, toc, depth, col): 274 html = '' 275 for name, title, sub in toc: 276 li_style = ' style="padding-left: %dem;"' % (depth + 1) 277 if sub == None: 278 if name == curpage: 279 cls = ' class="active"' 280 else: 281 cls = '' 282 html += '%s<li%s%s>%s</li>\n' % \ 283 (self.indentation(col), li_style, cls, title) 248 284 else: 249 result.append((name, title, [])) 250 return (found, result) 251 252 def indentation(col): 253 return ' ' * col 254 255 def display_all(hdf, env, name, curpage, toc, col): 256 preview = hdf.getValue('args.preview', "") 257 html = '' 258 259 if (not preview) and hdf.getValue('trac.acl.WIKI_MODIFY', ''): 260 html += '%s<div class="edit"><a href="%s?edit=yes">edit</a></div>\n' % \ 261 (indentation(col), env.href.wiki(name)) 262 html += '%s<ul>\n' % indentation(col) 263 col += 1 264 html += display(curpage, toc, 0, col) 265 col -= 1 266 html += '%s</ul>\n' % indentation(col) 267 return html 268 269 def display(curpage, toc, depth, col): 270 html = '' 271 for name, title, sub in toc: 272 li_style = ' style="padding-left: %dem;"' % (depth + 1) 273 if sub == None: 274 if name == curpage: 275 cls = ' class="active"' 276 else: 277 cls = '' 278 html += '%s<li%s%s>%s</li>\n' % \ 279 (indentation(col), li_style, cls, title) 280 else: 281 html += '%s<li%s>\n' % (indentation(col), li_style) 282 col += 1 283 if name == None or sub: 284 html += '%s<h4>%s</h4>\n' % \ 285 (indentation(col), title) 286 else: 287 html += '%s<h4>%s...</h4>\n' % \ 288 (indentation(col), title) 289 col -= 1 290 html += '%s</li>\n' % indentation(col) 291 if len(sub) > 0: 292 html += display(curpage, sub, depth + 1, col) 293 return html 294 285 html += '%s<li%s>\n' % (self.indentation(col), li_style) 286 col += 1 287 if name == None or sub: 288 html += '%s<h4>%s</h4>\n' % \ 289 (self.indentation(col), title) 290 else: 291 html += '%s<h4>%s...</h4>\n' % \ 292 (self.indentation(col), title) 293 col -= 1 294 html += '%s</li>\n' % self.indentation(col) 295 if len(sub) > 0: 296 html += self.display(curpage, sub, depth + 1, col) 297 return html 298 299 300 def get_macros(self): 301 yield 'TracNav' 302 303 304 def render_macro(self, req, name, args): 305 return self.execute(req, args) 306 307 308 def get_macro_description(self, name): 309 from inspect import getdoc, getmodule 310 return getdoc(getmodule(self)) 311 312 313 def get_htdocs_dirs(self): 314 from pkg_resources import resource_filename 315 return [('tracnav', resource_filename(__name__, 'htdocs'))] 316 317 318 def get_templates_dirs(self): 319 # we don't provide templates 320 return [] 321
Note: See TracChangeset
for help on using the changeset viewer.
