Users/News/NewPropelWebsite: TOC.py

File TOC.py, 4.2 kB (added by david, 3 years ago)
Line 
1 # vim: expandtab tabstop=4
2 from StringIO import StringIO
3 import re
4 import string
5 from trac.util import escape
6
7 rules_re = re.compile(r"""(?P<heading>^\s*(?P<hdepth>=+)\s(?P<header>.*)\s(?P=hdepth)\s*$)""")
8 anchor_re = re.compile('[^\w\d]+')
9
10 def parse_toc(env, out, page, body, max_depth = 999, min_depth = 1):
11     current_depth = min_depth
12     in_pre = False
13     first_li = True
14     seen_anchors = []
15     has_hits = False
16
17     for line in body.splitlines():
18         line = escape(line)
19
20         # Skip over wiki-escaped code, e.g. code examples (Steven N.
21         # Severinghaus <sns@severinghaus.org>)
22         if in_pre:
23             if line == '}}}':
24                 in_pre = False
25             else:
26                 continue
27         if line == '{{{':
28             in_pre = True
29             continue
30
31         match = rules_re.match(line)
32         if match:
33             header = match.group('header')
34             new_depth = len(match.group('hdepth'))
35             if new_depth < min_depth:
36                 continue
37             elif new_depth < current_depth:
38                 while new_depth < current_depth:
39                     current_depth -= 1
40                     if current_depth < max_depth:
41                         out.write("</ul>")
42                 indent = current_depth - 1
43                 out.write("<li style='padding-left: %sem;'>" % indent)
44                 has_hits = True
45             elif new_depth >= current_depth:
46                 i = current_depth
47                 while new_depth > i or first_li  :
48                     i += 1
49                     first_li = False
50                     if current_depth <= max_depth:
51                         out.write("<ul>")
52                 current_depth = new_depth
53                 indent = current_depth - 1
54                 out.write("<li style='padding-left: %sem;'>" % indent)
55                 has_hits = True
56             default_anchor = anchor = anchor_re.sub("", header)
57             anchor_n = 1
58             while anchor in seen_anchors:
59                 anchor = default_anchor + str(anchor_n)
60                 anchor_n += 1
61             seen_anchors.append(anchor)
62             link = page + "#" + anchor
63             if current_depth <= max_depth:
64                 out.write('<a href="%s">%s</a></li>\n' % (env.href.wiki(link), header))
65     while current_depth >= min_depth and not first_li:
66         if current_depth <= max_depth:
67             out.write("</ul>\n")
68         current_depth -= 1
69     return has_hits
70
71 def execute(hdf, args, env):
72     db = env.get_db_cnx()
73     if not args:
74         args = ''
75     pre_pages = re.split('\s*,\s*', args)
76     # Options
77     inline = False
78     heading = 'TOC for this Page'
79     pages = []
80     root = ''
81     params = { }
82     # Global options
83     for page in pre_pages:
84         if page == 'inline':
85             inline = True
86         elif page == 'noheading':
87             heading = None
88         elif page[:8] == 'heading=':
89             heading = page[8:]
90         elif page == '':
91             continue
92         elif page[:6] == 'depth=':
93             params['max_depth'] = int(page[6:])
94         elif page[:5] == 'root=':
95             root = page[5:]
96         else:
97             pages.append(page)
98     # Has the user supplied a list of pages?
99     if not pages:
100         pages.append(hdf.getValue("args.page", "WikiStart"))
101         root = ''
102         params['min_depth'] = 2     # Skip page title
103     out = StringIO()
104     if not inline:
105         out.write("<div class='wiki-toc trac-nav'>\n")
106     if heading:
107         out.write("<h3>%s</h3>\n" % heading)
108     has_hits = False
109     for page in pages:
110         # Override arguments
111         if page[:6] == 'depth=':
112             params['max_depth'] = int(page[6:])
113         elif page[:5] == 'root=':
114             root = page[5:]
115         else:
116             page = root + page
117             cursor = db.cursor()
118             cursor.execute("SELECT text FROM wiki WHERE name='%s' ORDER BY version desc LIMIT 1" % page)
119             row = cursor.fetchone()
120             if row:
121                 has_hits = parse_toc(env, out, page, row[0], **params)
122             else:
123                 out.write('<div class="system-message"><strong>Error: Page %s does not exist</strong></div>' % page)
124     if not inline:
125         out.write("</div>\n")
126     if has_hits:
127         return out.getvalue()
128     else:
129         return ''