source: trac/trunk/wiki-macros/TracNav.py @ 3053

Revision 3053, 8.1 KB checked in by moschny, 8 years ago (diff)

Move pattern matching into a generator.

Line 
1# -*- coding: utf-8 -*-
2"""
3= TracNav: The navigation bar for Trac =
4
5This macro implements a fully customizable navigation bar for the Trac
6wiki engine. The contents of the navigation bar is a wiki page itself
7and can be edited like any other wiki page through the web
8interface. The navigation bar supports hierarchical ordering of
9topics. The design of TracNav mimics the design of the TracGuideToc
10that was originally supplied with Trac. The drawback of TracGuideToc
11is that it is not customizable without editing its source code and
12that it does not support hierarchical ordering.
13
14
15== Installation ==
16
17To install TracNav, place the file `TracNav.py` in the `wiki-macros`
18subdirectory and the accompanying `tracnav.css` file in the
19`templates` subdirectory of your Trac project. Add this line
20{{{
21@import url(<?cs var:chrome.href ?>/site/tracnav.css);
22}}}
23to the `templates/site_css.cs` file of your Trac project.
24
25The `tracnav.css` file defines the styles for displaying the
26navigation bar. These styles build upon the styles for !TracGuideToc
27that come with your Trac distribution. If you just install the macro
28but miss to install the style file, TracNav will work but look
29somewhat strange.
30
31
32== Usage ==
33
34To use TracNav, create an index page for your site and call the
35TracNav macro on each page, where the navigation bar should be
36displayed. The index page is a regular wiki page. The page with the
37table of contents must include an unordered list of links that should
38be displayed in the navigation bar.
39
40To display the navigation bar on a page, you must call the TracNav
41macro on that page an pass the name of your table of contents as
42argument.
43
44
45== Author and license ==
46
47Copyright 2005 Bernhard Haumacher (haui at haumacher.de)
48
49{{{
50This program is free software; you can redistribute it and/or modify
51it under the terms of the GNU General Public License as published by
52the Free Software Foundation; either version 2 of the License, or
53(at your option) any later version.
54
55This program is distributed in the hope that it will be useful,
56but WITHOUT ANY WARRANTY; without even the implied warranty of
57MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
58GNU General Public License for more details.
59
60You should have received a copy of the GNU General Public License
61along with this program; if not, write to the Free Software
62Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
63}}}
64
65== Additional information and a life example ==
66
67Please visit: http://svn.ipd.uka.de/trac/javaparty/wiki/TracNav
68"""
69
70import re
71import sys
72from trac.wiki.api import WikiSystem
73from trac.wiki.model import WikiPage
74
75listRule = re.compile(r"""^(?P<indent> *)\* +(?:(?P<wikilink>\[wiki:(?P<link>(&#34;([^&#34;]*)&#34;|'([^']*)')|([^ \]]+)) +(?P<label>[^\]]*)\])|(?P<text>.*))""", re.M)
76
77def getToc(hdf, env, curpage, name):
78    tocText = "* Table of contents"
79
80    preview = hdf.getValue('args.preview', "")
81    if preview and (name == curpage):
82        tocText = hdf.getValue('wiki.page_source', tocText);
83    else:
84        if WikiSystem(env).has_page(name):
85            tocText = WikiPage(env, name).text
86
87    # env.log.debug(tocText)
88    return tocText
89
90
91def getTocEntry(tocText):
92    nextPos = 0
93    while 1:
94        match = listRule.search(tocText, nextPos)
95        if not match:
96            # env.log.debug("No more matches")
97            return
98
99        indent = len(match.group('indent'))
100        if match.group('wikilink'):
101            link = match.group('link')
102            label = match.group('label')
103        else:
104            link = None
105            label = match.group('text')
106
107        # if link == None:
108        #     env.log.debug(label + " ---")
109        # else:
110        #     env.log.debug(label + ": " + link)
111   
112        yield indent, link, label
113        nextPos = match.end()
114
115
116def parseToc(tocText):
117    stack = []
118    for indent, link, label in getTocEntry(tocText):
119
120        if len(stack) == 0:
121            stack.append((indent, []))
122
123        (lastIndent, list) = stack[len(stack) - 1]
124
125        if indent > lastIndent:
126            stack.append((indent, [(link, label, None)]))
127        elif indent == lastIndent:
128            list.append((link, label, None))
129        else:
130            while indent < lastIndent:
131                (_, list) = stack.pop()
132                (lastIndent, topList) = stack[len(stack) - 1]
133                (topLink, topLabel, _) = topList[len(topList) - 1]
134                topList[len(topList) - 1] = (topLink, topLabel, list)
135
136            (lastIndent, list) = stack[len(stack) - 1]
137            list.append((link, label, None))
138               
139    while len(stack) > 1:
140        (_, list) = stack.pop()
141        (_, topList) = stack[len(stack) - 1]
142        (topLink, topLabel, _) = topList[len(topList) - 1]
143        topList[len(topList) - 1] = (topLink, topLabel, list)
144
145    (_, list) = stack.pop()
146    return list
147
148
149def execute(hdf, args, env):
150    preview = hdf.getValue('args.preview', "")
151    curpage = hdf.getValue('wiki.page_name', "")
152    name = args
153    if not name:
154        name = 'TOC'
155
156    db = env.get_db_cnx()
157    toc = parseToc(getToc(hdf, env, curpage, name))
158    if not toc:
159        msg = ''
160        msg += '<div class="system-message"><strong>Error: Table of contents does not exist.'
161        if (not preview) and (hdf.getValue('trac.acl.WIKI_MODIFY', '')):
162            msg += ' Click here to <a href="%s?edit=yes">edit</a>.' % env.href.wiki(name)
163        msg += '</strong></div>\n'
164        return msg
165
166    (found, filtered) = filter(curpage, toc, 0)
167    if found:
168        return displayAll(hdf, env, name, curpage, filtered, 0)
169    else:
170        return displayAll(hdf, env, name, curpage, toc, 0)
171
172
173def filter(curpage, toc, level):
174    found = 0
175    result = []
176    for name, title, sub in toc:
177        if sub == None:
178            if name == curpage:
179                found = 1
180            result.append((name, title, None))
181        else:
182            (subfound, subtoc) = filter(curpage, sub, level + 1)
183            if subfound:
184                found = 1
185            if subfound or (name == None):
186                if level == 0 and name != None:
187                    prepended = [(name, title, subtoc)]
188                    prepended.extend(result)
189                    result = prepended
190                else:
191                    result.append((name, title, subtoc))
192            else:
193                result.append((name, title, []))
194    return (found, result)
195
196def indentation(col):
197    return ' ' * col
198
199def displayAll(hdf, env, name, curpage, toc, col):
200    preview = hdf.getValue('args.preview', "")
201    html = ''
202    html += '%s<div class="wiki-toc trac-nav">\n' % indentation(col)
203    col += 1
204
205    html += '%s<h2><a href="http://svn.ipd.uka.de/trac/javaparty/wiki/TracNav">TracNav</a> menu</h2>' % indentation(col)
206
207    if (not preview) and hdf.getValue('trac.acl.WIKI_MODIFY', ''):
208        html += '%s<div class="edit"><a href="%s?edit=yes">edit</a></div>\n' % (indentation(col), env.href.wiki(name))
209    html += '%s<ul>\n' % indentation(col)
210    col += 1
211    html += display(env, curpage, toc, 0, col)
212    col -= 1
213    html += '%s</ul>\n' % indentation(col)
214    col -= 1
215    html += '%s</div>\n' % indentation(col)
216    return html
217
218def display(env, curpage, toc, depth, col):
219    html = ''
220    for name, title, sub in toc:
221        liStyle = ' style="padding-left: %dem;"' % (depth + 1)
222        if sub == None:
223            if name == curpage:
224                cls = ' class="active"'
225            else:
226                cls = ''
227            html += '%s<li%s%s>' % (indentation(col), liStyle, cls)
228            if name == None:
229                html += title
230            else:
231                html += '<a href="%s">%s</a>' % (env.href.wiki(name), title)
232            html += '</li>\n'
233        else:
234            html += '%s<li%s>\n' % (indentation(col), liStyle)
235            col += 1
236            if name == None or len(sub) > 0:
237                html += '%s<h4>%s</h4>\n' % (indentation(col), title)
238            else:
239                html += '%s<h4><a href="%s">%s</a>...</h4>\n' % (indentation(col), env.href.wiki(name), title)
240            col -= 1
241            html += '%s</li>\n' % indentation(col)
242            if len(sub) > 0:
243                html += display(env, curpage, sub, depth + 1, col)
244    return html
245
Note: See TracBrowser for help on using the repository browser.