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

Revision 2935, 7.7 KB checked in by hauma, 8 years ago (diff)
  • Bugfix: TracNav no longer depends on the correct indentation (indent == 1) of the first list item on the TOC page.
Line 
1# -*- coding: iso8859-1 -*-
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, you must place the file {{{TracNav.py}}} somewhere
18in your {{{wiki-macros/}}} directory of your Trac
19installation. Additionally, you have to append the following lines to
20the file {{{htdocs/css/wiki.css}}} that can also be found in your Trac
21directoryhierarchy.
22
23{{{
24/* Styles for TracNav */
25.wiki-toc.trac-nav h4 { margin: 0; padding: 0; }
26.wiki-toc.trac-nav .edit { border:0; position:absolute; top:0; right:5px; }
27.wiki-toc.trac-nav .edit a { color:blue; border-color:blue; }
28}}}
29
30The lines above define the styles for displaying the navigation
31bar. These styles build upon the styles for !TracGuideToc that come
32with your Trac distribution. If you just install the macro but miss to
33extend the style file, TracNav will work but look somewhat strange.
34
35
36== Usage ==
37
38To use TracNav, you have to create an index page for your site and
39call the TracNav macro on each page, where the navigation bar should
40be displayed. The index page is a regular wiki page. The page with the
41table of contents must include an unordered list of links that should
42be displayed in the navigation bar.
43
44To display the navigation bar on a page, you must call the TracNav
45macro on that page an pass the name of your table of contents as
46argument.
47
48
49== Author and license ==
50
51Copyright 2005 Bernhard Haumacher (haui at haumacher.de)
52
53{{{
54This program is free software; you can redistribute it and/or modify
55it under the terms of the GNU General Public License as published by
56the Free Software Foundation; either version 2 of the License, or
57(at your option) any later version.
58
59This program is distributed in the hope that it will be useful,
60but WITHOUT ANY WARRANTY; without even the implied warranty of
61MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
62GNU General Public License for more details.
63
64You should have received a copy of the GNU General Public License
65along with this program; if not, write to the Free Software
66Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
67}}}
68
69== Additional information and a life example ==
70
71Please visit: http://svn.ipd.uka.de/trac/javaparty/wiki/TracNav
72"""
73
74import re
75import sys
76
77listRule = re.compile(r"""^(?P<indent> *)\* +(?:(?P<wikilink>\[wiki:(?P<link>(&#34;([^&#34;]*)&#34;|'([^']*)')|([^ \]]+)) +(?P<label>[^\]]*)\])|(?P<text>.*))""", re.M)
78
79def getToc(env, db, name):
80    cursor = db.cursor()
81    cursor.execute('SELECT text FROM wiki WHERE name=%s ORDER BY version DESC LIMIT 1', name)
82    row = cursor.fetchone()
83    if not row:
84        return None
85
86    tocText = row[0]
87
88    # env.log.debug(tocText)
89
90    stack = []
91    nextPos = 0
92    while 1:
93        match = listRule.search(tocText, nextPos)
94        if not match:
95            # env.log.debug("No more matches")
96            break
97
98        indent = len(match.group('indent'))
99        if match.group('wikilink'):
100            link = match.group('link')
101            label = match.group('label')
102        else:
103            link = None
104            label = match.group('text')
105
106        # if link == None:
107        #     env.log.debug(label + " ---")
108        # else:
109        #     env.log.debug(label + ": " + link)
110
111        if len(stack) == 0:
112            stack.append((indent, []))
113
114        (lastIndent, list) = stack[len(stack) - 1]
115
116        if indent > lastIndent:
117            stack.append((indent, [(link, label, None)]))
118        elif indent == lastIndent:
119            list.append((link, label, None))
120        else:
121            while indent < lastIndent:
122                (_, list) = stack.pop()
123                (lastIndent, topList) = stack[len(stack) - 1]
124                (topLink, topLabel, _) = topList[len(topList) - 1]
125                topList[len(topList) - 1] = (topLink, topLabel, list)
126
127            (lastIndent, list) = stack[len(stack) - 1]
128            list.append((link, label, None))
129               
130        nextPos = match.end()
131
132    while len(stack) > 1:
133        (_, list) = stack.pop()
134        (_, topList) = stack[len(stack) - 1]
135        (topLink, topLabel, _) = topList[len(topList) - 1]
136        topList[len(topList) - 1] = (topLink, topLabel, list)
137
138    (_, list) = stack.pop()
139    return list
140
141
142def execute(hdf, args, env):
143    curpage =  '%s' % hdf.getValue('args.page', '')
144    name = args
145    if not name:
146        name = 'TOC'
147
148    db = env.get_db_cnx()
149    toc = getToc(env, db, name)
150    if not toc:
151        msg = ''
152        msg += '<div class="system-message"><strong>Error: Table of contents does not exist.'
153        if (hdf.getValue('trac.acl.WIKI_MODIFY', '')):
154            msg += ' Click here to <a href="%s?edit=yes">edit</a>.' % env.href.wiki(name)
155        msg += '</strong></div>\n'
156        return msg
157
158    (found, filtered) = filter(curpage, toc, 0)
159    if found:
160        return displayAll(hdf, env, name, curpage, filtered, 0)
161    else:
162        return displayAll(hdf, env, name, curpage, toc, 0)
163
164
165def filter(curpage, toc, level):
166    found = 0
167    result = []
168    for name, title, sub in toc:
169        if sub == None:
170            if name == curpage:
171                found = 1
172            result.append((name, title, None))
173        else:
174            (subfound, subtoc) = filter(curpage, sub, level + 1)
175            if subfound or (name == None):
176                found = 1
177                if level == 0 and name != None:
178                    prepended = [(name, title, subtoc)]
179                    prepended.extend(result)
180                    result = prepended
181                else:
182                    result.append((name, title, subtoc))
183            else:
184                result.append((name, title, []))
185    return (found, result)
186
187def indentation(col):
188    return ' ' * col
189
190def displayAll(hdf, env, name, curpage, toc, col):
191    html = ''
192    html += '%s<div class="wiki-toc trac-nav">\n' % indentation(col)
193    col += 1
194    if hdf.getValue('trac.acl.WIKI_MODIFY', ''):
195        html += '%s<div class="edit"><a href="%s?edit=yes">edit</a></div>\n' % (indentation(col), env.href.wiki(name))
196    html += '%s<ul>\n' % indentation(col)
197    col += 1
198    html += display(env, curpage, toc, 0, col)
199    col -= 1
200    html += '%s</ul>\n' % indentation(col)
201    col -= 1
202    html += '%s</div>\n' % indentation(col)
203    return html
204
205def display(env, curpage, toc, depth, col):
206    html = ''
207    for name, title, sub in toc:
208        liStyle = ' style="padding-left: %dem;"' % (depth + 1)
209        if sub == None:
210            if name == curpage:
211                cls = ' class="active"'
212            else:
213                cls = ''
214            html += '%s<li%s%s>' % (indentation(col), liStyle, cls)
215            if name == None:
216                html += title
217            else:
218                html += '<a href="%s">%s</a>' % (env.href.wiki(name), title)
219            html += '</li>\n'
220        else:
221            html += '%s<li%s>\n' % (indentation(col), liStyle)
222            col += 1
223            if name == None or len(sub) > 0:
224                html += '%s<h4>%s</h4>\n' % (indentation(col), title)
225            else:
226                html += '%s<h4><a href="%s">%s...</a></h4>\n' % (indentation(col), env.href.wiki(name), title)
227            col -= 1
228            html += '%s</li>\n' % indentation(col)
229            if len(sub) > 0:
230                html += display(env, curpage, sub, depth + 1, col)
231    return html
232
Note: See TracBrowser for help on using the repository browser.