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

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