From: Holger Schurig Date: Wed, 23 Jun 2010 13:55:17 +0000 (+0200) Subject: toc.py: now we can generate a table-of-contents X-Git-Url: https://oss.titaniummirror.com/gitweb?p=webber.git;a=commitdiff_plain;h=60f96e570d30a5d9de3db805ad8c8ce6a833f087 toc.py: now we can generate a table-of-contents --- diff --git a/in/functions.md b/in/functions.md index 05e0d8d..ba54aa1 100644 --- a/in/functions.md +++ b/in/functions.md @@ -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 == diff --git a/in/hooks.md b/in/hooks.md index fd888dd..c30a258 100644 --- a/in/hooks.md +++ b/in/hooks.md @@ -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 diff --git a/in/plugins/rss_feed.md b/in/plugins/rss_feed.md index 046db84..e0f9cf7 100644 --- a/in/plugins/rss_feed.md +++ b/in/plugins/rss_feed.md @@ -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: diff --git a/in/plugins/toc.md b/in/plugins/toc.md new file mode 100644 index 0000000..44d8410 --- /dev/null +++ b/in/plugins/toc.md @@ -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: + +

Calling macros

+

Example

+

Defining macros

+ +the table-of-contents will be like this: + + + +While doing this, it also modifies the HTML file contents to look like this: + +

Calling macros 

+

Example 

+

Defining macros 

+ +== 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; + } diff --git a/in/webber.conf b/in/webber.conf index 3013998..e9e3789 100644 --- a/in/webber.conf +++ b/in/webber.conf @@ -14,6 +14,7 @@ plugins: [ "read_markdown", "template_mako", "google_sitemap", + "toc", ] exclude_dir: [ ] diff --git a/plugins/link.py b/plugins/link.py index d8c4214..b0d673b 100644 --- a/plugins/link.py +++ b/plugins/link.py @@ -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 index 0000000..ffd6c25 --- /dev/null +++ b/plugins/toc.py @@ -0,0 +1,88 @@ +# -*- coding: iso-8859-1 -*- +from webber import * +import htmlentitydefs, re + + +reHeader = re.compile(r'(.*)', 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 '%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('
    ') + for (label, lvl, txt) in toc: + while lvl > level: + res.append("%s
      " % (" "*level)) + level += 1 + while lvl < level: + level -= 1 + res.append("%s
    " % (" "*level)) + res.append('%s
  • %s
  • ' % (" " * level, label, txt)) + while level: + level -= 1 + res.append("%s
" % (" "*level)) + return "\n".join(res) diff --git a/webber.py b/webber.py index c90cdb9..6be571e 100644 --- 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