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

Revision 2934, 7.6 KB checked in by hauma, 8 years ago (diff)
  • Adjusted the look and feel of the active line in the TracNav navigation bar. Now, the whole line is highlighted no matter of the level of indentation. Unfortunately, this requires to generate a flat unordered list in HTML with direct style directives for indentation.
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 = [(1, [])]
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        (lastIndent, list) = stack[len(stack) - 1]
112
113        if indent > lastIndent:
114            stack.append((indent, [(link, label, None)]))
115        elif indent == lastIndent:
116            list.append((link, label, None))
117        else:
118            while indent < lastIndent:
119                (_, list) = stack.pop()
120                (lastIndent, topList) = stack[len(stack) - 1]
121                (topLink, topLabel, _) = topList[len(topList) - 1]
122                topList[len(topList) - 1] = (topLink, topLabel, list)
123
124            (lastIndent, list) = stack[len(stack) - 1]
125            list.append((link, label, None))
126               
127        nextPos = match.end()
128
129    while len(stack) > 1:
130        (_, list) = stack.pop()
131        (_, topList) = stack[len(stack) - 1]
132        (topLink, topLabel, _) = topList[len(topList) - 1]
133        topList[len(topList) - 1] = (topLink, topLabel, list)
134
135    (_, list) = stack.pop()
136    return list
137
138
139def execute(hdf, args, env):
140    curpage =  '%s' % hdf.getValue('args.page', '')
141    name = args
142    if not name:
143        name = 'TOC'
144
145    db = env.get_db_cnx()
146    toc = getToc(env, db, name)
147    if not toc:
148        msg = ''
149        msg += '<div class="system-message"><strong>Error: Table of contents does not exist.'
150        if (hdf.getValue('trac.acl.WIKI_MODIFY', '')):
151            msg += ' Click here to <a href="%s?edit=yes">edit</a>.' % env.href.wiki(name)
152        msg += '</strong></div>\n'
153        return msg
154
155    (found, filtered) = filter(curpage, toc, 0)
156    if found:
157        return displayAll(hdf, env, name, curpage, filtered, 0)
158    else:
159        return displayAll(hdf, env, name, curpage, toc, 0)
160
161
162def filter(curpage, toc, level):
163    found = 0
164    result = []
165    for name, title, sub in toc:
166        if sub == None:
167            if name == curpage:
168                found = 1
169            result.append((name, title, None))
170        else:
171            (subfound, subtoc) = filter(curpage, sub, level + 1)
172            if subfound or (name == None):
173                found = 1
174                if level == 0 and name != None:
175                    prepended = [(name, title, subtoc)]
176                    prepended.extend(result)
177                    result = prepended
178                else:
179                    result.append((name, title, subtoc))
180            else:
181                result.append((name, title, []))
182    return (found, result)
183
184def indentation(col):
185    return ' ' * col
186
187def displayAll(hdf, env, name, curpage, toc, col):
188    html = ''
189    html += '%s<div class="wiki-toc trac-nav">\n' % indentation(col)
190    col += 1
191    if hdf.getValue('trac.acl.WIKI_MODIFY', ''):
192        html += '%s<div class="edit"><a href="%s?edit=yes">edit</a></div>\n' % (indentation(col), env.href.wiki(name))
193    html += '%s<ul>\n' % indentation(col)
194    col += 1
195    html += display(env, curpage, toc, 0, col)
196    col -= 1
197    html += '%s</ul>\n' % indentation(col)
198    col -= 1
199    html += '%s</div>\n' % indentation(col)
200    return html
201
202def display(env, curpage, toc, depth, col):
203    html = ''
204    for name, title, sub in toc:
205        liStyle = ' style="padding-left: %dem;"' % (depth + 1)
206        if sub == None:
207            if name == curpage:
208                cls = ' class="active"'
209            else:
210                cls = ''
211            html += '%s<li%s%s>' % (indentation(col), liStyle, cls)
212            if name == None:
213                html += title
214            else:
215                html += '<a href="%s">%s</a>' % (env.href.wiki(name), title)
216            html += '</li>\n'
217        else:
218            html += '%s<li%s>\n' % (indentation(col), liStyle)
219            col += 1
220            if name == None or len(sub) > 0:
221                html += '%s<h4>%s</h4>\n' % (indentation(col), title)
222            else:
223                html += '%s<h4><a href="%s">%s...</a></h4>\n' % (indentation(col), env.href.wiki(name), title)
224            col -= 1
225            html += '%s</li>\n' % indentation(col)
226            if len(sub) > 0:
227                html += display(env, curpage, sub, depth + 1, col)
228    return html
229
Note: See TracBrowser for help on using the repository browser.