]> oss.titaniummirror.com Git - webber.git/commitdiff
toc.py: now we can generate a table-of-contents
authorHolger Schurig <holgerschurig@gmail.com>
Wed, 23 Jun 2010 13:55:17 +0000 (15:55 +0200)
committerHolger Schurig <holgerschurig@gmail.com>
Wed, 23 Jun 2010 13:55:17 +0000 (15:55 +0200)
in/functions.md
in/hooks.md
in/plugins/rss_feed.md
in/plugins/toc.md [new file with mode: 0644]
in/webber.conf
plugins/link.py
plugins/toc.py [new file with mode: 0644]
webber.py

index 05e0d8deb10133f2e99b601447f20c1d2368a7f8..ba54aa1c1e37dc0a03ea12abd6eb6e692bcc9100 100644 (file)
@@ -76,6 +76,11 @@ specify "`True`" for "`show_orphans`".
 
 Defined in [[hierarchy.py|hierarchy]], where you find an example.
 
+== get_toc() ==
+
+Returns an unsorted list with the hierarchy of the table-of-contents.
+
+Defined in [[toc.py|toc]], where you find an example.
 
 == func ==
 
index fd888dd078efb65de495e7f0a43882e06198b77b..c30a2588f61d9bf23e62cced630191843bb995cd 100644 (file)
@@ -145,8 +145,12 @@ The first hook that returns HTML, no other hooks will be called.
 
 == linkify ==
 
-This hook should contain any link to html. Implemented by the plugin
-[[link]].
+Functions that are called by this hook receive a pre-rendered HTML page.
+They can now modify this HTML further, e.g. py converting links to HTML.
+
+They can directly modify params.file.contents and don't need to return anything.
+
+Implemented by the plugin [[link]] and [[toc]].
 
 * "`params.direc`" contains a "`class Directory`" object
 * "`params.file`" has a "`class File`" object
index 046db8448ead9bdc97a8ee6eb3d3955462e1b02e..e0f9cf7c9f7a13d2441dd81f1d1a8ac1cd766997 100644 (file)
@@ -56,7 +56,7 @@ regardless of it's age.
 
 = Support in the template =
 
-You [[templates]] should mention your rss feed. One possible solution
+Your [[template|Mako template]] should mention your rss feed. One possible solution
 is this:
 
        <head>
diff --git a/in/plugins/toc.md b/in/plugins/toc.md
new file mode 100644 (file)
index 0000000..44d8410
--- /dev/null
@@ -0,0 +1,69 @@
+title: Generate table of contents
+linktitle: toc.py
+parent: Plugins
+ctime: 2010-06-23
+
+This plugin analyzes the HTML header statements (h1, h2, h3 ...) and
+generates a table of contents based on this information.
+
+= Configuration =
+
+== toc_min_lines ==
+
+A page needs with less lines than specified won't get a table-of-contents.
+
+You can use this if you paste the table-of-contents to some screen
+corner, and don't want the clutter the display if the HTML page is
+very short anyway.
+
+If not specified, this defaults to 30.
+
+
+= Usage example =
+
+with this HTML:
+
+       <h2>Calling macros</h2>
+       <h3>Example</h3>
+       <h3>Defining macros</h2>
+
+the table-of-contents will be like this:
+
+       <ul id="toc">
+         <li><a href="#calling_macros">Calling macros</a></li>
+          <ul>
+           <li><a href="#example">Example</a></li>
+         </ul>
+         <li><a href="#defining_macros">Defining macros</a></li>
+       </ul>
+
+While doing this, it also modifies the HTML file contents to look like this:
+
+       <h2>Calling macros<a name="calling_macros">&nbsp;</a></h2>
+       <h3>Example<a name="example">&nbsp;</a></h3>
+       <h2>Defining macros<a name="defining_macros">&nbsp;</a></h2>
+
+== Accessing the TOC ==
+
+Use "`${get_toc()}`" in your [[template|template_mako]] to access
+the generated HTML.
+
+
+== Example CSS ==
+
+Finally, you use some CSS to format the table-of-contents to your
+liking, e.g. with this:
+
+       #toc, #toc ul {
+               list-style-type: none;
+               overflow: hidden;
+               padding: 0;
+               margin: 0;
+       }
+       #toc {
+               font-size: 90%;
+       }
+       #toc li {
+               width: 100%;
+               text-align: right;
+       }
index 3013998632ccb80a0dfebeda388a83b44b6cea2b..e9e3789d8f93bf06127f21f75493f25679f33050 100644 (file)
@@ -14,6 +14,7 @@ plugins: [
        "read_markdown",
        "template_mako",
        "google_sitemap",
+       "toc",
        ]
 exclude_dir: [
        ]
index d8c42149434ed60f5c1bb71c026a01307ce35755..b0d673b306991beb4fcb17bec4940aaa8b105a07 100644 (file)
@@ -72,12 +72,7 @@ def test_sub():
                res = reLink.sub(do_link, s)
                print "", res
 
-#test_link()
-#test_sub()
-
-
-
 
 @set_hook("linkify")
 def linkify(params):
-       return reLink.sub(do_link, params.file.contents)
+       params.file.contents = reLink.sub(do_link, params.file.contents)
diff --git a/plugins/toc.py b/plugins/toc.py
new file mode 100644 (file)
index 0000000..ffd6c25
--- /dev/null
@@ -0,0 +1,88 @@
+# -*- coding: iso-8859-1 -*-
+from webber import *
+import htmlentitydefs, re
+
+
+reHeader = re.compile(r'<h(\d)(.*)>(.*)</h\1>', re.IGNORECASE | re.MULTILINE)
+toc = []
+labels = {}
+
+
+toc_min_lines = 30
+
+
+@set_hook("checkconfig")
+def checkconfig(params):
+       if cfg.has_key("toc_min_lines"):
+               global toc_min_lines
+               toc_min_lines = int(cfg.toc_min_times)
+
+
+def slugify(text, separator):
+    """Based on http://snipplr.com/view/26266/create-slugs-in-python/"""
+
+    ret = ""
+    for c in text.lower():
+        try:
+            ret += htmlentitydefs.codepoint2name[ord(c)]
+        except:
+            ret += c
+    ret = re.sub("([a-zA-Z])(uml|acute|grave|circ|tilde|cedil)", r"\1", ret)
+    ret = re.sub("\W", " ", ret)
+    ret = re.sub(" +", separator, ret)
+    return ret.strip()
+
+
+def repl(m):
+    global toc
+    label = slugify(m.group(3), "_")
+    if labels.has_key(label):
+        n = 0
+        while True:
+            l = "%s_%d" % (label, n)
+            if not labels.has_key(l):
+                label = l
+                break
+            n += 1
+
+    toc.append( (label, int(m.group(1))-1, m.group(3)) )
+    return '<h%s%s>%s<a name="%s">&nbsp;</a></h%s>' % (
+        m.group(1),
+        m.group(2),
+        m.group(3),
+        label,
+        m.group(1))
+
+
+@set_hook("linkify")
+def linkify(params):
+    global toc
+    global labels
+    toc = []
+    labels = {}
+
+    # Very small pages don't need a table-of-contents
+    if params.file.contents.count("\n") < toc_min_lines:
+        return
+
+    params.file.contents = reHeader.sub(repl, params.file.contents)
+
+
+
+@set_function("get_toc")
+def get_toc():
+    level = 1
+    res = []
+    res.append('<ul id="toc">')
+    for (label, lvl, txt) in toc:
+        while lvl > level:
+            res.append("%s<ul>" % ("  "*level))
+            level += 1
+        while lvl < level:
+            level -= 1
+            res.append("%s</ul>" % ("  "*level))
+        res.append('%s<li><a href="#%s">%s</a></li>' % ("  " * level, label, txt))
+    while level:
+        level -= 1
+        res.append("%s</ul>" % ("  "*level))
+    return "\n".join(res)
index c90cdb97b3805c35b03a1983ef6d51124b2e09c7..6be571e0ff09ea19d88e0e9e2ef6625b442eaf16 100644 (file)
--- a/webber.py
+++ b/webber.py
@@ -674,14 +674,13 @@ def render_files():
                        continue
                direc = directories[file.direc]
 
-               contents = run_hooks("linkify",
+               run_hooks("linkify",
                        direc=direc,
                        file=file,
-                       return_holder=False)
+                       return_holder=True)
                #print "contents after 'linkify':", contents
-               if not contents:
+               if not file.contents:
                        continue
-               file.contents = contents
 
                # TODO: einige Fragmente sollen u.U. in eine andere
                # Webseite eingebaut werden und sollten daher nicht in