<div dir="ltr">Martin, I'm not sure if this [59812] is appropriate because it is not stabilized yet [59816] and overall, it is a new feature although it is just in documentation.<div><br></div><div><a href="https://trac.osgeo.org/grass/changeset/59812">https://trac.osgeo.org/grass/changeset/59812</a><br>

</div><div><a href="https://trac.osgeo.org/grass/changeset/59816">https://trac.osgeo.org/grass/changeset/59816</a><br></div><div><br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sat, Apr 19, 2014 at 2:38 PM,  <span dir="ltr"><<a href="mailto:svn_grass@osgeo.org" target="_blank">svn_grass@osgeo.org</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Author: martinl<br>
Date: 2014-04-19 11:38:08 -0700 (Sat, 19 Apr 2014)<br>
New Revision: 59812<br>
<br>
Modified:<br>
   grass/branches/releasebranch_7_0/man/build_html.py<br>
   grass/branches/releasebranch_7_0/man/grassdocs.css<br>
   grass/branches/releasebranch_7_0/tools/mkhtml.py<br>
Log:<br>
Backport TOC manual generation from trunk<br>
<br>
<br>
Modified: grass/branches/releasebranch_7_0/man/build_html.py<br>
===================================================================<br>
--- grass/branches/releasebranch_7_0/man/build_html.py  2014-04-19 18:33:48 UTC (rev 59811)<br>
+++ grass/branches/releasebranch_7_0/man/build_html.py  2014-04-19 18:38:08 UTC (rev 59812)<br>
@@ -48,7 +48,7 @@<br>
 header2_tmpl = string.Template(\<br>
 r""" <link rel="stylesheet" href="grassdocs.css" type="text/css"><br>
 </head><br>
-<body bgcolor="#FFFFFF"><br>
+<body style="width: 99%"><br>
<br>
 <!-- this file is generated by man/build_html.py --><br>
<br>
@@ -249,7 +249,7 @@<br>
 r"""<br>
 <link rel="stylesheet" href="grassdocs.css" type="text/css"><br>
 </head><br>
-<body bgcolor="white"><br>
+<body style="width: 99%"><br>
<br>
 <img src="grass_logo.png" alt="GRASS logo"><hr align=center size=6 noshade><br>
 <h2>Topics</h2><br>
@@ -261,7 +261,7 @@<br>
 r"""<br>
 <link rel="stylesheet" href="grassdocs.css" type="text/css"><br>
 </head><br>
-<body bgcolor="white"><br>
+<body style="width: 99%"><br>
<br>
 <img src="grass_logo.png" alt="GRASS logo"><hr align=center size=6 noshade><br>
 <h2>Keywords - Index of GRASS GIS modules</h2><br>
<br>
Modified: grass/branches/releasebranch_7_0/man/grassdocs.css<br>
===================================================================<br>
--- grass/branches/releasebranch_7_0/man/grassdocs.css  2014-04-19 18:33:48 UTC (rev 59811)<br>
+++ grass/branches/releasebranch_7_0/man/grassdocs.css  2014-04-19 18:38:08 UTC (rev 59812)<br>
@@ -14,6 +14,7 @@<br>
     background: white;<br>
     color: black;<br>
     font-family: arial,sans-serif;<br>
+    width: 80%;<br>
 }<br>
<br>
 h1{<br>
@@ -49,7 +50,7 @@<br>
 }<br>
<br>
 div.code{<br>
-    width: 95%;<br>
+    width: 100%;<br>
     color : black;<br>
     background-color: rgb(90%, 90%, 90%);<br>
     padding-left: 1em;<br>
@@ -86,3 +87,32 @@<br>
 td {<br>
     padding: 5px;<br>
 }<br>
+<br>
+div.toc{<br>
+    background-color: transparent;<br>
+    position: fixed;<br>
+    border: solid 1px rgb(25%, 60%, 25%);<br>
+    top: 5px;<br>
+    right: 5px;<br>
+    width: 17%;<br>
+    line-height: 120%;<br>
+    font-weight: bold;<br>
+    font-size: small;<br>
+    font-family: arial,sans-serif;<br>
+}<br>
+<br>
+li.toc {<br>
+   margin-left: -15px;<br>
+   padding: 3px 3px; 3px; 3px;<br>
+   color: rgb(25%, 60%, 25%);<br>
+}<br>
+<br>
+ul.toc {<br>
+   margin-top: 3px;<br>
+   margin-bottom: 3px;<br>
+}<br>
+<br>
+a.toc {<br>
+    color: rgb(25%, 60%, 25%);<br>
+    text-decoration: none;<br>
+}<br>
<br>
Modified: grass/branches/releasebranch_7_0/tools/mkhtml.py<br>
===================================================================<br>
--- grass/branches/releasebranch_7_0/tools/mkhtml.py    2014-04-19 18:33:48 UTC (rev 59811)<br>
+++ grass/branches/releasebranch_7_0/tools/mkhtml.py    2014-04-19 18:38:08 UTC (rev 59812)<br>
@@ -2,12 +2,12 @@<br>
<br>
 ############################################################################<br>
 #<br>
-# MODULE:       mkhtml.py<br>
+# MODULE:       Builds manual pages<br>
 # AUTHOR(S):    Markus Neteler<br>
 #               Glynn Clements<br>
 #               Martin Landa <landa.martin <a href="http://gmail.com" target="_blank">gmail.com</a>><br>
 # PURPOSE:      Create HTML manual page snippets<br>
-# COPYRIGHT:    (C) 2007, 2009, 2011-2012 by Glynn Clements<br>
+# COPYRIGHT:    (C) 2007-2014 by Glynn Clements<br>
 #                and the GRASS Development Team<br>
 #<br>
 #               This program is free software under the GNU General<br>
@@ -21,6 +21,7 @@<br>
 import string<br>
 import re<br>
 from datetime import datetime<br>
+from HTMLParser import HTMLParser<br>
<br>
 pgm = sys.argv[1]<br>
<br>
@@ -61,6 +62,7 @@<br>
 </html><br>
 """)<br>
<br>
+<br>
 def read_file(name):<br>
     try:<br>
         f = open(name, 'rb')<br>
@@ -70,11 +72,101 @@<br>
     except IOError:<br>
         return ""<br>
<br>
+<br>
+def create_toc(src_data):<br>
+    class MyHTMLParser(HTMLParser):<br>
+        def __init__(self):<br>
+            self.reset()<br>
+            self.idx = 1<br>
+            self.tag_curr = ''<br>
+            self.tag_last = ''<br>
+            self.process_text = False<br>
+            self.data = []<br>
+            self.tags_allowed = ('h1', 'h2', 'h3')<br>
+            self.tags_ignored = ('img')<br>
+            self.text = ''<br>
+<br>
+        def handle_starttag(self, tag, attrs):<br>
+            if tag in self.tags_allowed:<br>
+                self.process_text = True<br>
+            self.tag_last = self.tag_curr<br>
+            self.tag_curr = tag<br>
+<br>
+        def handle_endtag(self, tag):<br>
+            if tag in self.tags_allowed:<br>
+                self.data.append((tag, '%s_%d' % (tag, self.idx),<br>
+                                  self.text))<br>
+                self.idx += 1<br>
+                self.process_text = False<br>
+                self.text = ''<br>
+<br>
+            self.tag_curr = self.tag_last<br>
+<br>
+        def handle_data(self, data):<br>
+            if not self.process_text:<br>
+                return<br>
+            if self.tag_curr in self.tags_allowed or self.tag_curr in self.tags_ignored:<br>
+                self.text += data<br>
+            else:<br>
+                self.text += '<%s>%s</%s>' % (self.tag_curr, data, self.tag_curr)<br>
+<br>
+    # instantiate the parser and fed it some HTML<br>
+    parser = MyHTMLParser()<br>
+    parser.feed(src_data)<br>
+<br>
+    return parser.data<br>
+<br>
+<br>
+def write_toc(data):<br>
+    if not data:<br>
+        return<br>
+<br>
+    fd = sys.stdout<br>
+    fd.write('<div class="toc">\n')<br>
+    fd.write('<ul class="toc">\n')<br>
+    first = True<br>
+    in_h3 = False<br>
+    indent = 4<br>
+    for tag, href, text in data:<br>
+        if tag == 'h3' and not in_h3:<br>
+            fd.write('\n%s<ul class="toc">\n' % (' ' * indent))<br>
+            indent += 4<br>
+            in_h3 = True<br>
+        elif not first:<br>
+            fd.write('</li>\n')<br>
+<br>
+        if tag == 'h2' and in_h3:<br>
+            indent -= 4<br>
+            fd.write('%s</ul></li>\n' % (' ' * indent))<br>
+            in_h3 = False<br>
+<br>
+        fd.write('%s<li class="toc"><a href="#%s" class="toc">%s</a>' % \<br>
+                     (' ' * indent, href, text))<br>
+        first = False<br>
+<br>
+    fd.write('</li>\n</ul>\n')<br>
+    fd.write('</div>\n')<br>
+<br>
+def update_toc(data):<br>
+    ret_data = []<br>
+    pat = re.compile(r'(<(h\d)>)(.+)(</h\d>)')<br>
+    idx = 1<br>
+    for line in data.splitlines():<br>
+        if pat.search(line):<br>
+            xline = pat.split(line)<br>
+            line = xline[1] + '<a name="%s_%d">' % (xline[2], idx) + xline[3] + '</a>' + xline[4]<br>
+            idx += 1<br>
+        ret_data.append(line)<br>
+<br>
+    return '\n'.join(ret_data)<br>
+<br>
+# process header<br>
 src_data = read_file(src_file)<br>
 name = re.search('(<!-- meta page name:)(.*)(-->)', src_data, re.IGNORECASE)<br>
 if name:<br>
     pgm = name.group(2).strip().split('-', 1)[0].strip()<br>
-desc = re.search('(<!-- meta page description:)(.*)(-->)', src_data, re.IGNORECASE)<br>
+desc = re.search('(<!-- meta page description:)(.*)(-->)', src_data,<br>
+                 re.IGNORECASE)<br>
 if desc:<br>
     pgm = desc.group(2).strip()<br>
     header_tmpl = string.Template(header_base + header_nopgm)<br>
@@ -84,14 +176,18 @@<br>
 if not re.search('<html>', src_data, re.IGNORECASE):<br>
     tmp_data = read_file(tmp_file)<br>
     if not re.search('<html>', tmp_data, re.IGNORECASE):<br>
-        sys.stdout.write(header_tmpl.substitute(PGM = pgm))<br>
+        sys.stdout.write(header_tmpl.substitute(PGM=pgm))<br>
     if tmp_data:<br>
         for line in tmp_data.splitlines(True):<br>
             if not re.search('</body>|</html>', line, re.IGNORECASE):<br>
                 sys.stdout.write(line)<br>
<br>
-sys.stdout.write(src_data)<br>
+# create TOC<br>
+write_toc(create_toc(src_data))<br>
<br>
+# process body<br>
+sys.stdout.write(update_toc(src_data))<br>
+<br>
 # if </html> is found, suppose a complete html is provided.<br>
 # otherwise, generate module class reference:<br>
 if re.search('</html>', src_data, re.IGNORECASE):<br>
@@ -112,6 +208,7 @@<br>
     'v' : 'vector'<br>
     }<br>
<br>
+# process footer<br>
 index = re.search('(<!-- meta page index:)(.*)(-->)', src_data, re.IGNORECASE)<br>
 if index:<br>
     index_name_cap = index_name = index.group(2).strip()<br>
@@ -120,13 +217,16 @@<br>
     index_name = index_names.get(mod_class, '')<br>
     index_name_cap = index_name.title()<br>
<br>
-grass_version = os.getenv("VERSION_NUMBER", "unknown")<br>
+grass_version = os.getenv("VERSION_NUMBER", "unknown")<br>
 year = os.getenv("VERSION_DATE")<br>
 if not year:<br>
     year = str(datetime.now().year)<br>
<br>
 if index_name:<br>
-    sys.stdout.write(footer_index.substitute(INDEXNAME = index_name, INDEXNAMECAP = index_name_cap,<br>
-                                             YEAR = year, GRASS_VERSION = grass_version))<br>
+    sys.stdout.write(footer_index.substitute(INDEXNAME=index_name,<br>
+                                             INDEXNAMECAP=index_name_cap,<br>
+                                             YEAR=year,<br>
+                                             GRASS_VERSION=grass_version))<br>
 else:<br>
-    sys.stdout.write(footer_noindex.substitute(YEAR = year, GRASS_VERSION = grass_version))<br>
+    sys.stdout.write(footer_noindex.substitute(YEAR=year,<br>
+                                               GRASS_VERSION=grass_version))<br>
<br>
_______________________________________________<br>
grass-commit mailing list<br>
<a href="mailto:grass-commit@lists.osgeo.org">grass-commit@lists.osgeo.org</a><br>
<a href="http://lists.osgeo.org/mailman/listinfo/grass-commit" target="_blank">http://lists.osgeo.org/mailman/listinfo/grass-commit</a><br>
</blockquote></div><br></div></div>