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

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