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

Revision 2990, 8.3 KB checked in by hauma, 8 years ago (diff)

Bugfix: Format processed boxes like regular preformatted text boxes.

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