]> sipb.mit.edu Git - ikiwiki.git/commitdiff
* Add toc (table of contents) plugin.
authorjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>
Mon, 28 Aug 2006 07:40:20 +0000 (07:40 +0000)
committerjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>
Mon, 28 Aug 2006 07:40:20 +0000 (07:40 +0000)
IkiWiki/Plugin/skeleton.pm
IkiWiki/Plugin/toc.pm [new file with mode: 0644]
Makefile.PL
debian/changelog
doc/features.mdwn
doc/ikiwiki.setup
doc/plugins/toc.mdwn [new file with mode: 0644]
doc/security.mdwn
doc/todo/pageindexes.mdwn
t/html.t

index 1201d055c46cff36a6004bc9f6f115b3994c3a58..4683b00ba707a51809001dd3baa79f6068a1bf3c 100644 (file)
@@ -21,6 +21,8 @@ sub import { #{{{
                call => \&htmlize);
        IkiWiki::hook(type => "sanitize", id => "skeleton", 
                call => \&sanitize);
+       IkiWiki::hook(type => "format", id => "skeleton", 
+               call => \&format);
        IkiWiki::hook(type => "pagetemplate", id => "skeleton", 
                call => \&pagetemplate);
        IkiWiki::hook(type => "delete", id => "skeleton", 
@@ -71,6 +73,14 @@ sub sanitize ($) { #{{{
        return $content;
 } # }}}
 
+sub format ($) { #{{{
+       my $content=shift;
+       
+       IkiWiki::debug("skeleton plugin running as a formatter");
+
+       return $content;
+} # }}}
+
 sub pagetemplate (@) { #{{{
        my %params=@_;
        my $page=$params{page};
diff --git a/IkiWiki/Plugin/toc.pm b/IkiWiki/Plugin/toc.pm
new file mode 100644 (file)
index 0000000..c36ce28
--- /dev/null
@@ -0,0 +1,116 @@
+#!/usr/bin/perl
+# Table Of Contents generator
+package IkiWiki::Plugin::toc;
+
+use warnings;
+use strict;
+use IkiWiki;
+use HTML::Parser;
+
+sub import { #{{{
+       IkiWiki::hook(type => "preprocess", id => "toc",
+               call => \&preprocess);
+       IkiWiki::hook(type => "format", id => "toc",
+               call => \&format);
+} # }}}
+
+my @tocs;
+
+sub preprocess (@) { #{{{
+       my %params=@_;
+
+       $params{levels}=1 unless exists $params{levels};
+
+       # It's too early to generate the toc here, so just record the
+       # info.
+       push @tocs, \%params;
+
+       return "\n[[toc $#tocs]]\n";
+} # }}}
+
+sub format ($) { #{{{
+       my $content=shift;
+       
+       return $content unless @tocs && $content=~/\[\[toc (\d+)\]\]/ && $#tocs >= $1;
+       my $id=$1;
+       my %params=%{$tocs[$id]};
+
+       my $p=HTML::Parser->new(api_version => 3);
+       my $page="";
+       my $index="";
+       my %anchors;
+       my $curlevel;
+       my $startlevel=0;
+       my $liststarted=0;
+       my $indent=sub { "\t" x $curlevel };
+       $p->handler(start => sub {
+               my $tagname=shift;
+               my $text=shift;
+               if ($tagname =~ /^h(\d+)$/i) {
+                       my $level=$1;
+                       my $anchor="index".++$anchors{$level}."h$level";
+                       $page.="$text<a name=\"$anchor\" />";
+       
+                       # Take the first header level seen as the topmost level,
+                       # even if there are higher levels seen later on.
+                       if (! $startlevel) {
+                               $startlevel=$level;
+                               $curlevel=$startlevel-1;
+                       }
+                       elsif ($level < $startlevel) {
+                               $level=$startlevel;
+                       }
+                       
+                       return if $level - $startlevel >= $params{levels};
+       
+                       if ($level > $curlevel) {
+                               while ($level > $curlevel + 1) {
+                                       $index.=&$indent."<ol>\n";
+                                       $curlevel++;
+                                       $index.=&$indent."<li class=\"L$curlevel\">\n";
+                               }
+                               $index.=&$indent."<ol>\n";
+                               $curlevel=$level;
+                               $liststarted=1;
+                       }
+                       elsif ($level < $curlevel) {
+                               while ($level < $curlevel) {
+                                       $index.=&$indent."</li>\n" if $curlevel;
+                                       $curlevel--;
+                                       $index.=&$indent."</ol>\n";
+                               }
+                               $liststarted=0;
+                       }
+       
+                       $p->handler(text => sub {
+                               $page.=join("", @_);
+                               $index.=&$indent."</li>\n" unless $liststarted;
+                               $liststarted=0;
+                               $index.=&$indent."<li class=\"L$curlevel\">".
+                                       "<a href=\"#$anchor\">".
+                                       join("", @_).
+                                       "</a>\n";
+                               $p->handler(text => undef);
+                       }, "dtext");
+               }
+               else {
+                       $page.=$text;
+               }
+       }, "tagname, text");
+       $p->handler(default => sub { $page.=join("", @_) }, "text");
+       $p->parse($content);
+       $p->eof;
+
+       while ($startlevel && $curlevel >= $startlevel) {
+               $index.=&$indent."</li>\n" if $curlevel;
+               $curlevel--;
+               $index.=&$indent."</ol>\n";
+       }
+
+       # Ignore cruft around the toc marker, probably <p> tags added by
+       # markdown which shouldn't appear in a list anyway.
+       $page=~s/\n.*\[\[toc $id\]\].*\n/$index/;
+       return $page;
+}
+
+1
index 7f715eb87f4eaf4598be3304a38816f8cc171991..d2266ad8e0aa60fdfc22037f092cb944f61fa9a9 100755 (executable)
@@ -24,7 +24,7 @@ extra_build:
                --plugin=orphans --plugin=haiku --plugin=meta \
                --plugin=tag --plugin=polygen --plugin=pagestats \
                --plugin=fortune --plugin=aggregate --plugin=map \
-               --plugin=template
+               --plugin=template --plugin=toc
        ./mdwn2man ikiwiki 1 doc/usage.mdwn > ikiwiki.man
        ./mdwn2man ikiwiki-mass-rebuild 8 doc/ikiwiki-mass-rebuild.mdwn > ikiwiki-mass-rebuild.man
                
index 2d1fd37778d538aedb48f768c5f0564224b442ab..ccff36c9a3fd9f52c4f5e926aacdf8f18e4edb78 100644 (file)
@@ -40,8 +40,9 @@ ikiwiki (1.22) UNRELEASED; urgency=low
   * Factor out the cgi header printing code into a new function.
   * Fix preferences page on anonok wikis; still need to sign in to get
     to the preferences page.
+  * Add toc (table of contents) plugin.
 
- -- Joey Hess <joeyh@debian.org>  Sun, 27 Aug 2006 16:17:21 -0400
+ -- Joey Hess <joeyh@debian.org>  Mon, 28 Aug 2006 02:31:56 -0400
 
 ikiwiki (1.21) unstable; urgency=low
 
index 92773f3c98dafb03137148953223eb251f7f0b89..b909b864abb36c4368645995eeec69842f2f96a0 100644 (file)
-Some of ikiwiki's features:
+An overview of some of ikiwiki's features:
+[[toc ]]
 
-* Uses a real RCS
+## Uses a real RCS
 
-  Rather than implement its own system for storing page histories etc,
-  ikiwiki uses a real RCS. This isn't because we're lazy, it's because a
-  real RCS is a good thing to have, and there are advantages to using one
-  that are not possible with a standard wiki.
+Rather than implement its own system for storing page histories etc,
+ikiwiki uses a real RCS. This isn't because we're lazy, it's because a
+real RCS is a good thing to have, and there are advantages to using one
+that are not possible with a standard wiki.
 
-  Instead of editing pages in a stupid web form, you can use vim and commit
-  changes via svn. Or work disconnected using svk and push your changes out
-  when you come online. Or use git to work in a distributed fashion all the
-  time. (It's also possible to [[plugins/write]] a plugin to support other
-  systems.)
+Instead of editing pages in a stupid web form, you can use vim and commit
+changes via svn. Or work disconnected using svk and push your changes out
+when you come online. Or use git to work in a distributed fashion all the
+time. (It's also possible to [[plugins/write]] a plugin to support other
+systems.)
 
-  ikiwiki can be run from a [[post-commit]] hook to update your wiki
-  immediately whenever you commit.
+ikiwiki can be run from a [[post-commit]] hook to update your wiki
+immediately whenever you commit.
 
-  Note that ikiwiki does not require a RCS to function. If you want to
-  run a simple wiki without page history, it can do that too.
+Note that ikiwiki does not require a RCS to function. If you want to
+run a simple wiki without page history, it can do that too.
 
-* Supports many markup languages
+## Supports many markup languages
 
-  By default, pages in the wiki are written using the [[MarkDown]] format.
-  Any page with a filename ending in ".mdwn" is converted from markdown to html
-  by ikiwiki. Markdown understands text formatted as it would be in an email,
-  and is quite smart about converting it to html. The only additional markup
-  provided by ikiwiki on top of regular markdown is the [[WikiLink]] and 
-  [[PreprocessorDirective]].
+By default, pages in the wiki are written using the [[MarkDown]] format.
+Any page with a filename ending in ".mdwn" is converted from markdown to html
+by ikiwiki. Markdown understands text formatted as it would be in an email,
+and is quite smart about converting it to html. The only additional markup
+provided by ikiwiki on top of regular markdown is the [[WikiLink]] and 
+[[PreprocessorDirective]].
 
-  If you prefer to use some other markup language, ikiwiki allows others to
-  easily be added by [[plugins]]. For example it also supports traditional
-  [[plugins/WikiText]] formatted pages, pages written as pure
-  [[plugins/HTML]], or pages written in [[reStructuredText|plugins/rst]].
+If you prefer to use some other markup language, ikiwiki allows others to
+easily be added by [[plugins]]. For example it also supports traditional
+[[plugins/WikiText]] formatted pages, pages written as pure
+[[plugins/HTML]], or pages written in [[reStructuredText|plugins/rst]].
 
-* support for other file types
+## support for other file types
 
-  ikiwiki also supports files of any other type, including plain text,
-  images, etc. These are not converted to wiki pages, they are just copied
-  unchanged by ikiwiki as it builds your wiki. So you can check in an image,
-  program, or other special file and link to it from your wiki pages.
+ikiwiki also supports files of any other type, including plain text,
+images, etc. These are not converted to wiki pages, they are just copied
+unchanged by ikiwiki as it builds your wiki. So you can check in an image,
+program, or other special file and link to it from your wiki pages.
 
-* Fast compiler
+## Fast compiler
 
-  ikiwiki is fast and smart about updating a wiki, it only builds pages
-  that have changed (and tracks things like creation of new pages and links
-  that can indirectly cause a page to need a rebuild)
+ikiwiki is fast and smart about updating a wiki, it only builds pages
+that have changed (and tracks things like creation of new pages and links
+that can indirectly cause a page to need a rebuild)
 
-* [[blogging|blog]]
+## [[blogging|blog]]
 
-  You can turn any page in the wiki into a [[blog]]. Pages matching a
-  specified [[PageSpec]] will be displayed as a weblog within the blog
-  page. And an RSS feed can be generated to follow the blog.
+You can turn any page in the wiki into a [[blog]]. Pages matching a
+specified [[PageSpec]] will be displayed as a weblog within the blog
+page. And an RSS feed can be generated to follow the blog.
 
-  Ikiwiki's own [[TODO]], [[news]], and [[plugins]] pages are good examples
-  of some of the flexible ways that this can be used.
+Ikiwiki's own [[TODO]], [[news]], and [[plugins]] pages are good examples
+of some of the flexible ways that this can be used.
 
-  Ikiwiki can also [[plugins/aggregate]] external blogs, feeding them into
-  the wiki. This can be used to create a Planet type site that aggregates
-  interesting feeds.
+Ikiwiki can also [[plugins/aggregate]] external blogs, feeding them into
+the wiki. This can be used to create a Planet type site that aggregates
+interesting feeds.
 
-* [[tags]]
+## [[tags]]
 
-  You can tag pages and use these tags in various ways. Tags will show
-  up in the ways you'd expect, like at the bottom of pages, in blogs, and
-  in rss feeds.
+You can tag pages and use these tags in various ways. Tags will show
+up in the ways you'd expect, like at the bottom of pages, in blogs, and
+in rss feeds.
 
-* valid html and css
+## valid html and css
 
-  ikiwiki aims to produce 
-  [valid XHTML 1.0](http://validator.w3.org/check?url=referer).
-  ikiwiki generates html using [[templates]], and uses css, so you can 
-  change the look and layout of all pages in any way you would like.
+ikiwiki aims to produce 
+[valid XHTML 1.0](http://validator.w3.org/check?url=referer).
+ikiwiki generates html using [[templates]], and uses css, so you can 
+change the look and layout of all pages in any way you would like.
 
-* [[SubPages|SubPage]]
+## [[SubPages|SubPage]]
 
-  Arbitrarily deep hierarchies of pages with fairly simple and useful
-  [[SubPage/LinkingRules]]
+Arbitrarily deep hierarchies of pages with fairly simple and useful
+[[SubPage/LinkingRules]]
 
-* [[BackLinks]]
+## [[BackLinks]]
 
-  Automatically included on pages. Rather faster than eg MoinMoin and
-  always there to help with navigation.
+Automatically included on pages. Rather faster than eg MoinMoin and
+always there to help with navigation.
 
-* [[PageHistory]]
+## [[PageHistory]]
 
-  Well, sorta. Rather than implementing YA history browser, it can link to
-  [[ViewCVS]] or the like to browse the history of a wiki page.
+Well, sorta. Rather than implementing YA history browser, it can link to
+[[ViewCVS]] or the like to browse the history of a wiki page.
 
-* [[RecentChanges]], editing pages in a web browser
+## [[RecentChanges]], editing pages in a web browser
 
-  Nearly the definition of a wiki, although perhaps ikiwiki challenges how
-  much of that web gunk a wiki really needs. These features are optional
-  and can be enabled by enabling [[CGI]].
+Nearly the definition of a wiki, although perhaps ikiwiki challenges how
+much of that web gunk a wiki really needs. These features are optional
+and can be enabled by enabling [[CGI]].
 
-* User registration
+## User registration
 
-  Can optionally be configured to allow only registered users to post
-  pages; online user registration form, etc.
+Can optionally be configured to allow only registered users to post
+pages; online user registration form, etc.
 
-* Discussion pages
+## Discussion pages
 
-  Thanks to subpages, every page can easily and automatically have a
-  /Discussion subpage. By default, these links are included in the
-  [[templates]] for each page.
+Thanks to subpages, every page can easily and automatically have a
+/Discussion subpage. By default, these links are included in the
+[[templates]] for each page.
 
-* Smart merging and conflict resolution in your web browser
+## Smart merging and conflict resolution in your web browser
 
-  Since it uses a real RCS, ikiwiki takes advantage of its smart merging to
-  avoid any conflicts when two people edit different parts of the same page
-  at the same time. No annoying warnings about other editors, or locking,
-  etc, instead the other person's changes will be automatically merged with
-  yours when you commit.
+Since it uses a real RCS, ikiwiki takes advantage of its smart merging to
+avoid any conflicts when two people edit different parts of the same page
+at the same time. No annoying warnings about other editors, or locking,
+etc, instead the other person's changes will be automatically merged with
+yours when you commit.
 
-  In the rare cases where automatic merging fails due to the same part of a
-  page being concurrently edited, regular commit conflict markers are
-  shown in the file to resolve the conflict, so if you're already familiar
-  with that there's no new commit marker syntax to learn.
+In the rare cases where automatic merging fails due to the same part of a
+page being concurrently edited, regular commit conflict markers are
+shown in the file to resolve the conflict, so if you're already familiar
+with that there's no new commit marker syntax to learn.
 
-* page locking
+## page locking
 
-  Wiki admins can lock pages so that only other admins can edit them.
+Wiki admins can lock pages so that only other admins can edit them.
 
-* Full text search
+## Full text search
 
-  ikiwiki can use the [[HyperEstraier]] search engine to add powerful
-  full text search capabilities to your wiki.
+ikiwiki can use the [[HyperEstraier]] search engine to add powerful
+full text search capabilities to your wiki.
 
-* Commit mails
+## Commit mails
 
-  ikiwiki can be configured to send you commit mails with diffs of changes
-  to selected pages.
+ikiwiki can be configured to send you commit mails with diffs of changes
+to selected pages.
 
-* [[Plugins]]
+## [[Plugins]]
 
-  Plugins can be used to add additional features to ikiwiki. The interface
-  is quite flexible, allowing plugins to implement additional markup
-  languages, register [[PreProcessorDirective]]s, hook into [[CGI]] mode,
-  and more. Most of ikiwiki's features are actually provided by plugins.
-  Ikiwiki's backend RCS support is also pluggable, so support for new
-  revision control systems can be added to ikiwiki. 
+Plugins can be used to add additional features to ikiwiki. The interface
+is quite flexible, allowing plugins to implement additional markup
+languages, register [[PreProcessorDirective]]s, hook into [[CGI]] mode,
+and more. Most of ikiwiki's features are actually provided by plugins.
+Ikiwiki's backend RCS support is also pluggable, so support for new
+revision control systems can be added to ikiwiki. 
 
-* [[todo/utf8]]
+## [[todo/utf8]]
 
-  After rather a lot of fiddling, we think that ikiwiki correctly and fully
-  supports utf8 everywhere.
+After rather a lot of fiddling, we think that ikiwiki correctly and fully
+supports utf8 everywhere.
 
-* [[w3mmode]]
+## [[w3mmode]]
 
-  Can be set up so that w3m can be used to browse a wiki and edit pages
-  without using a web server.
-
-----
-
-It also has some [[TODO]] items and [[Bugs]].
+Can be set up so that w3m can be used to browse a wiki and edit pages
+without using a web server.
index 9a4b61ec407a3e2d8b05b639f8503c36e4ce813d..ee5e394bec01f4b3e72a66f82878573afca44d69 100644 (file)
@@ -83,7 +83,7 @@ use IkiWiki::Setup::Standard {
        # To add plugins, list them here.
        #add_plugins => [qw{meta tag pagecount brokenlinks search smiley
        #                   wikitext camelcase pagestats htmltidy fortune
-       #                   sidebar map rst}],
+       #                   sidebar map rst toc}],
        # If you want to disable any of the default plugins, list them here.
        #disable_plugins => [qw{inline htmlscrubber}],
 }
diff --git a/doc/plugins/toc.mdwn b/doc/plugins/toc.mdwn
new file mode 100644 (file)
index 0000000..57bd622
--- /dev/null
@@ -0,0 +1,13 @@
+[[template id=plugin name=toc included=1 author="Joey Hess"]]
+[[tag type/chrome]]
+
+Add a table of contents be to a page:
+
+       \[[toc ]]
+
+The table of contents will be automatically generated based on the
+headers of the page. By default only the largest headers present on the
+page will be shown; to control how many levels of headers are shown, use
+the `levels` parameter:
+
+       \[[toc levels=2]]
index 5cc35b33866d31892b5c16f3ad932fa8770e27ce..fea0eb727d655fe2c7452174b08e3d718e7aae40 100644 (file)
@@ -6,6 +6,8 @@ security issues with this program than with cat(1). If, however, you let
 others edit pages in your wiki, then some possible security issues do need
 to be kept in mind.
 
+[[toc levels=2]]
+
 ----
 
 # Probable holes
index 0b567332ec96a9f0fea2e4b398f432e092dbb4f3..c2de20a341a86c0ad6b1e41cbf2e3a79a7b3f9a4 100644 (file)
@@ -1,3 +1,5 @@
 Might be nice to support automatically generating an index based on headers
 in a page, for long pages. This could be done as a sanitize hook that
 parsed the html, with a preprocessordirective that controlled it.
+
+[[todo/done]]
index 01f14d0c0fbf0dfee414b56ebe8e9d78c2f8a519..fc6888dca7de7832767d6f16eb9aa036a4ee5752 100755 (executable)
--- a/t/html.t
+++ b/t/html.t
@@ -6,7 +6,7 @@ use Test::More;
 my @pages;
 
 BEGIN {
-       @pages=qw(index todo features news plugins/map);
+       @pages=qw(index todo features news plugins/map security);
        if (! -x "/usr/bin/validate") {
                plan skip_all => "/usr/bin/validate html validator not present";
        }