Users/News/NewPropelWebsite: TracNav.py

File TracNav.py, 8.5 kB (added by david, 3 years ago)
Line 
1 # -*- coding: iso8859-1 -*-
2 """
3 = TracNav: The navigation bar for Trac =
4
5 This macro implements a fully customizable navigation bar for the Trac
6 wiki engine. The contents of the navigation bar is a wiki page itself
7 and can be edited like any other wiki page through the web
8 interface. The navigation bar supports hierarchical ordering of
9 topics. The design of TracNav mimics the design of the TracGuideToc
10 that was originally supplied with Trac. The drawback of TracGuideToc
11 is that it is not customizable without editing its source code and
12 that it does not support hierarchical ordering.
13
14
15 == Installation ==
16
17 To install TracNav, you must place the file {{{TracNav.py}}} somewhere
18 in your {{{wiki-macros/}}} directory of your Trac
19 installation. Additionally, you have to append the following lines to
20 the file {{{htdocs/css/wiki.css}}} that can also be found in your Trac
21 directoryhierarchy.
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
37 The lines above define the styles for displaying the navigation
38 bar. These styles build upon the styles for !TracGuideToc that come
39 with your Trac distribution. If you just install the macro but miss to
40 extend the style file, TracNav will work but look somewhat strange.
41
42
43 == Usage ==
44
45 To use TracNav, you have to create an index page for your site and
46 call the TracNav macro on each page, where the navigation bar should
47 be displayed. The index page is a regular wiki page. The page with the
48 table of contents must include an unordered list of links that should
49 be displayed in the navigation bar.
50
51 To display the navigation bar on a page, you must call the TracNav
52 macro on that page an pass the name of your table of contents as
53 argument.
54
55
56 == Author and license ==
57
58 Copyright 2005 Bernhard Haumacher (haui at haumacher.de)
59
60 {{{
61 This program is free software; you can redistribute it and/or modify
62 it under the terms of the GNU General Public License as published by
63 the Free Software Foundation; either version 2 of the License, or
64 (at your option) any later version.
65
66 This program is distributed in the hope that it will be useful,
67 but WITHOUT ANY WARRANTY; without even the implied warranty of
68 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
69 GNU General Public License for more details.
70
71 You should have received a copy of the GNU General Public License
72 along with this program; if not, write to the Free Software
73 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
74 }}}
75
76 == Additional information and a life example ==
77
78 Please visit: http://svn.ipd.uka.de/trac/javaparty/wiki/TracNav
79 """
80
81 import re
82 import sys
83
84 listRule = re.compile(r"""^(?P<indent> *)\* +(?:(?P<wikilink>\[wiki:(?P<link>(&#34;([^&#34;]*)&#34;|'([^']*)')|([^ \]]+)) +(?P<label>[^\]]*)\])|(?P<text>.*))""", re.M)
85
86 def 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
103 def 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, False)]))
132         elif indent == lastIndent:
133             list.append((link, label, None, False))
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, False)
140
141             (lastIndent, list) = stack[len(stack) - 1]
142             list.append((link, label, None, False))
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, False)
151
152     (_, list) = stack.pop()
153     return list
154
155
156 def 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
180 def filter(curpage, toc, level):
181     found = 0
182     result = []
183     for name, title, sub, hidden in toc:
184         if sub == None:
185             if name == curpage:
186                 found = 1
187             result.append((name, title, None, hidden))
188         else:
189             if name == curpage:
190                 found = 1
191             (subfound, subtoc) = filter(curpage, sub, level + 1)
192             if subfound or (name == None):
193                 found = 1
194 #                if level == 0 and name != None:
195 #                    prepended = [(name, title, subtoc, hidden)]
196 #                    prepended.extend(result)
197 #                    result = prepended
198 #                else:
199 #                    result.append((name, title, subtoc, hidden))
200                 result.append((name, title, subtoc, hidden))
201             else:
202                 if level == 0 and name != curpage:
203                     hidden = True
204                 result.append((name, title, subtoc, hidden))
205            
206     return (found, result)
207
208 def indentation(col):
209     return ' ' * col
210
211 def displayAll(hdf, env, name, curpage, toc, col):
212     preview = hdf.getValue('args.preview', "")
213     html = ''
214     html += '%s<div id="PropelSiteNavigation" class="wiki-toc trac-nav">\n' % indentation(col)
215     col += 1
216     if (not preview) and hdf.getValue('trac.acl.WIKI_MODIFY', ''):
217         html += '%s<div class="edit"><a href="%s?edit=yes">edit</a></div>\n' % (indentation(col), env.href.wiki(name))
218     html += '%s<h3>Website Navigation</h3>\n' % indentation(col)
219     col += 1
220     html += display(env, curpage, toc, 0, col)
221     col -= 1
222     col -= 1
223     html += '%s</div>\n' % indentation(col)
224     return html
225
226 def display(env, curpage, toc, depth, col):
227     html = ''
228     html+= '<ul>\n';
229     for name, title, sub, hidden in toc:
230         if name == curpage:
231             cls = ' class="active"'
232         else:
233             cls = ''
234         if sub == None:
235             html += '%s<li%s>' % (indentation(col), cls)
236             if name == None:
237                 html += title
238             else:
239                 html += '<a href="%s">%s</a>' % (env.href.wiki(name), title)
240             html += '</li>\n'
241         else:
242             if hidden:
243                 hide = ' class="hidden"'
244             else:
245                 hide = ''
246             html += '%s<li%s%s>' % (indentation(col), hide, cls)
247             col += 1
248             #if name == None or len(sub) > 0:
249             if name == None:
250                 html += '%s%s\n' % (indentation(col), title)
251             else:
252                 html += '%s<a href="%s">%s...</a>\n' % (indentation(col), env.href.wiki(name), title)
253             col -= 1
254             if len(sub) > 0:
255                 html += display(env, curpage, sub, depth + 1, col)
256             html += '%s</li>\n' % indentation(col)
257     html+= '</ul>\n'
258     return html
259