From 7b4600df3f8b8c2112a8df6c018d64f04db1ebe8 Mon Sep 17 00:00:00 2001 From: joey Date: Fri, 24 Mar 2006 01:16:32 +0000 Subject: hold onto your hats, full-fledged blogging has arrived in ikiwiki! --- IkiWiki/Render.pm | 148 ++++++++++++++++++++++++++++++++--- basewiki/blog.mdwn | 8 ++ basewiki/helponformatting.mdwn | 5 ++ basewiki/postprocessordirective.mdwn | 11 +++ doc/blog.mdwn | 8 ++ doc/features.mdwn | 21 +++-- doc/helponformatting.mdwn | 5 ++ doc/postprocessordirective.mdwn | 11 +++ doc/sandbox.mdwn | 9 +++ doc/todo.mdwn | 44 +++-------- ikiwiki | 13 ++- templates/inlinepage.tmpl | 8 ++ templates/page.tmpl | 2 + 13 files changed, 237 insertions(+), 56 deletions(-) create mode 100644 basewiki/blog.mdwn create mode 100644 basewiki/postprocessordirective.mdwn create mode 100644 doc/blog.mdwn create mode 100644 doc/postprocessordirective.mdwn create mode 100644 templates/inlinepage.tmpl diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index f397ff320..8f755e8f5 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -85,11 +85,99 @@ sub rsspage ($) { #{{{ return $page.".rss"; } #}}} +sub postprocess { #{{{ + # Takes content to postprocess followed by a list of postprocessor + # commands and subroutine references to run for the commands. + my $page=shift; + my $content=shift; + my %commands=@_; + + my $handle=sub { + my $escape=shift; + my $command=shift; + my $params=shift; + if (length $escape) { + "[[$command $params]]"; + } + elsif (exists $commands{$command}) { + my %params; + while ($params =~ /(\w+)=\"([^"]+)"(\s+|$)/g) { + $params{$1}=$2; + } + $commands{$command}->($page, %params); + } + else { + "[[bad directive $command]]"; + } + }; + + $content =~ s{(\\?)$config{wiki_processor_regexp}}{$handle->($1, $2, $3)}eg; + return $content; +} #}}} + +sub blog_list ($$) { #{{{ + my $globlist=shift; + my $maxitems=shift; + + my @list; + foreach my $page (keys %pagesources) { + if (globlist_match($page, $globlist)) { + push @list, $page; + } + } + + @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list; + return @list if @list <= $maxitems; + return @list[0..$maxitems - 1]; +} #}}} + +sub get_inline_content ($$) { #{{{ + my $parentpage=shift; + my $page=shift; + + my $file=$pagesources{$page}; + my $type=pagetype($file); + if ($type ne 'unknown') { + return htmlize($type, linkify(readfile("$config{srcdir}/$file"), $parentpage)); + } + else { + return ""; + } +} #}}} + +sub postprocess_html_inline { #{{{ + my $parentpage=shift; + my %params=@_; + + if (! exists $params{show}) { + $params{show}=10; + } + if (! exists $params{pages}) { + return ""; + } + $inlinepages{$parentpage}=$params{pages}; + + my $template=HTML::Template->new(blind_cache => 1, + filename => "$config{templatedir}/inlinepage.tmpl"); + + my $ret=""; + foreach my $page (blog_list($params{pages}, $params{show})) { + $template->param(pagelink => htmllink($parentpage, $page)); + $template->param(content => get_inline_content($parentpage, $page)); + $template->param(ctime => scalar(gmtime($pagectime{$page}))); + $ret.=$template->output; + } + + return $ret; +} #}}} + sub genpage ($$$) { #{{{ my $content=shift; my $page=shift; my $mtime=shift; + $content = postprocess($page, $content, inline => \&postprocess_html_inline); + my $title=pagetitle(basename($page)); my $template=HTML::Template->new(blind_cache => 1, @@ -134,6 +222,7 @@ sub date_822 ($) { #{{{ } #}}} sub absolute_urls ($$) { #{{{ + # sucky sub because rss sucks my $content=shift; my $url=shift; @@ -142,29 +231,56 @@ sub absolute_urls ($$) { #{{{ $content=~s/new(blind_cache => 1, filename => "$config{templatedir}/rsspage.tmpl"); + my @items; + my $isblog=0; + my $gen_blog=sub { + my $parentpage=shift; + my %params=@_; + + if (! exists $params{show}) { + $params{show}=10; + } + if (! exists $params{pages}) { + return ""; + } + $inlinepages{$parentpage}=$params{pages}; + + $isblog=1; + foreach my $page (blog_list($params{pages}, $params{show})) { + push @items, { + itemtitle => pagetitle(basename($page)), + itemurl => "$config{url}/$renderedfiles{$page}", + itempubdate => date_822($pagectime{$page}), + itemcontent => absolute_urls(get_inline_content($parentpage, $page), $url), + } if exists $renderedfiles{$page}; + } + + return ""; + }; + + $content = postprocess($page, $content, inline => $gen_blog); + # Regular page gets a feed that is updated every time the # page is changed, so the mtime is encoded in the guid. - my @items=( - { - itemtitle => pagetitle(basename($page)), - itemguid => "$url?mtime=$mtime", - itemurl => $url, - itempubdate => date_822($mtime), - itemcontent => absolute_urls($content, $url), # rss sucks - }, - ); + push @items, { + itemtitle => pagetitle(basename($page)), + itemguid => "$url?mtime=$mtime", + itemurl => $url, + itempubdate => date_822($mtime), + itemcontent => absolute_urls($content, $url), + } unless $isblog; $template->param( title => $config{wikiname}, @@ -223,7 +339,7 @@ sub render ($) { #{{{ check_overwrite("$config{destdir}/".htmlpage($page), $page); writefile("$config{destdir}/".htmlpage($page), - genpage($content, $page, mtime("$config{srcdir}/$file"))); + genpage($content, $page, mtime("$config{srcdir}/$file"))); $oldpagemtime{$page}=time; $renderedfiles{$page}=htmlpage($page); @@ -320,7 +436,7 @@ sub refresh () { #{{{ } # if any files were added or removed, check to see if each page - # needs an update due to linking to them + # needs an update due to linking to them or inlining them. # TODO: inefficient; pages may get rendered above and again here; # problem is the bestlink may have changed and we won't know until # now @@ -337,6 +453,12 @@ FILE: foreach my $file (@files) { next FILE; } } + if (exists $inlinepages{$page} && + globlist_match($p, $inlinepages{$page})) { + debug("rendering $file, which inlines $p"); + render($file); + $rendered{$file}=1; + } } } } diff --git a/basewiki/blog.mdwn b/basewiki/blog.mdwn new file mode 100644 index 000000000..d300736a8 --- /dev/null +++ b/basewiki/blog.mdwn @@ -0,0 +1,8 @@ +You can turn any page on this wiki into a weblog by inserting a +[[PostProcessorDirective]]. Like this: + +\\[[inline pages="blog/*" show="10"]] + +Any pages that match the specified [[GlobList]] (in the exaple, any +[[SubPages]] of "blog") will be part of the blog, and the newest 10 +of them will appear in the page. diff --git a/basewiki/helponformatting.mdwn b/basewiki/helponformatting.mdwn index 545148e86..4ef41d16f 100644 --- a/basewiki/helponformatting.mdwn +++ b/basewiki/helponformatting.mdwn @@ -51,4 +51,9 @@ To link to any other web page, or to an email address, you can just put the url ---- +Advanced users can use [[PostProcessorDirective]]s to do additional cool +stuff. + +---- + This style of text formatting is called [[MarkDown]]. diff --git a/basewiki/postprocessordirective.mdwn b/basewiki/postprocessordirective.mdwn new file mode 100644 index 000000000..fa8432e3f --- /dev/null +++ b/basewiki/postprocessordirective.mdwn @@ -0,0 +1,11 @@ +Postprocessor directives are similar to a [[WikiLink]] in form, except they +contain spaces and parameters. The general form is: + +\\[[directive param="value" param="value"]] + +This gets expanded after the rest of the page is processed, and can be used +to transform the page in various ways. + +Currently, these postprocessor directives are available: + +* "inline" to make a [[blog]] diff --git a/doc/blog.mdwn b/doc/blog.mdwn new file mode 100644 index 000000000..d300736a8 --- /dev/null +++ b/doc/blog.mdwn @@ -0,0 +1,8 @@ +You can turn any page on this wiki into a weblog by inserting a +[[PostProcessorDirective]]. Like this: + +\\[[inline pages="blog/*" show="10"]] + +Any pages that match the specified [[GlobList]] (in the exaple, any +[[SubPages]] of "blog") will be part of the blog, and the newest 10 +of them will appear in the page. diff --git a/doc/features.mdwn b/doc/features.mdwn index 4699f3096..4a83604ad 100644 --- a/doc/features.mdwn +++ b/doc/features.mdwn @@ -27,13 +27,6 @@ Currently implemented: and is quite smart about converting it to html. The only additional markup provided by ikiwiki aside from regular markdown is the [[WikiLink]]. -* [[RSS]] - - ikiwiki supports generating RSS (2.0) feed for individual pages. These - feeds can be subscribed to, to get an update when a page is changed. - - (Support for proper blogs is also planned.) - * support for other file types ikiwiki also supports files of any other type, including raw html, text, @@ -45,9 +38,21 @@ Currently implemented: Arbitrarily deep hierarchies of pages with fairly simple and useful [[SubPage/LinkingRUles]] +* [[blog]]s + + You can turn any page in the wiki into a [[blog]]. Pages with names + matching a specified [[GlobList]] will be displayed as a weblog within + the blog page. And an RSS feed can be generated to follow the blog. + + ikiwiki also supports generating RSS feed for individual pages that + do not contain a [[blog]]. These feeds can be used to be sent a new + version of a page when it is changed. + * 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) * [[Templates]] diff --git a/doc/helponformatting.mdwn b/doc/helponformatting.mdwn index 545148e86..4ef41d16f 100644 --- a/doc/helponformatting.mdwn +++ b/doc/helponformatting.mdwn @@ -51,4 +51,9 @@ To link to any other web page, or to an email address, you can just put the url ---- +Advanced users can use [[PostProcessorDirective]]s to do additional cool +stuff. + +---- + This style of text formatting is called [[MarkDown]]. diff --git a/doc/postprocessordirective.mdwn b/doc/postprocessordirective.mdwn new file mode 100644 index 000000000..fa8432e3f --- /dev/null +++ b/doc/postprocessordirective.mdwn @@ -0,0 +1,11 @@ +Postprocessor directives are similar to a [[WikiLink]] in form, except they +contain spaces and parameters. The general form is: + +\\[[directive param="value" param="value"]] + +This gets expanded after the rest of the page is processed, and can be used +to transform the page in various ways. + +Currently, these postprocessor directives are available: + +* "inline" to make a [[blog]] diff --git a/doc/sandbox.mdwn b/doc/sandbox.mdwn index d39f76032..37bb6bd89 100644 --- a/doc/sandbox.mdwn +++ b/doc/sandbox.mdwn @@ -36,3 +36,12 @@ Bulleted list [[WikiLink]] [[SandBox/SubPage]] -- a page under this one. + +---- + +This sandbox is also a [[blog]]! Any subpage of this page is automatically +added to the blog below. + +---- + +[[inline pages="sandbox/*" show="5"]] diff --git a/doc/todo.mdwn b/doc/todo.mdwn index 4ae62867e..f918bf156 100644 --- a/doc/todo.mdwn +++ b/doc/todo.mdwn @@ -61,38 +61,15 @@ that linked back to it could be added to the page. However, doing linkbacks also needs to tie into the main logic, to determine what pages need to be renered, so maybe that won't be a plugin. -## blogging and rss +## blogging -The wiki should emit rss feeds for pages. The simple case is a regular -page (done). The complex case is a blog composed of multiple pages. - -### multi-page blog - -This also takes care of the feature of wanting to make a wiki page -comprised of several sub-pages that can be independantly edited. Add a -token that can be embedded into a page and that specifies a [[GlobList]] of -pages. Now when any page matching the globs changes, this page must be -updated too. - -For the html rendering, just embed the most recently created N pages in the -[[GlobList]], with the title of each being a link to the individual page, -plus a link to an additional page that lists all the titles of every -matching page in creation order (archives). Plus at the bottom a small web -form that prompts for a title and allows creating a new page for a new blog -post. - -For the rss rendering, generate a proper weblog of the same pages. -Of course for permalinks use the links to the subpages. - -Note that this allows for weblogs with different sections, etc. - -Requirements: - -* Need to keep track of the globlists in the index file. -* Need to pick a good token and note that the token will need to be passed - multiple parameters. Possibly something like this: - - [[inline pages="myblog/*" show="30"]] +- Add a small form at top and bottom of a blog to allow entering + a title for a new item, that goes to a template to create the new page. +- Add a link to the end of a blog to go to the archives; this would + probably best be another cgi script, to avoid needing to generate big + static pages for little used archives. +- Should probably add params to control various rss fields like the blog + title, its author email, its copyright info, etc. ## revisit case @@ -161,6 +138,11 @@ exposing ones from the underlaydir. Will need to make sure that the mtime for the source file is zeroed when the page is removed, and that it then finds the underlay file and treats it as newer. +## wikilinks features + +- \[[John|Fred]] is a Wikipedia method for linking to the one page + while displaying it as the other, Kyle would like this. + ## Logo ikiwiki needs a logo. I'm thinking something simple like the word "ikiwiki" diff --git a/ikiwiki b/ikiwiki index 7b0a718d9..77c7744f9 100755 --- a/ikiwiki +++ b/ikiwiki @@ -9,7 +9,7 @@ use HTML::Template; use lib '.'; # For use without installation, removed by Makefile. use vars qw{%config %links %oldlinks %oldpagemtime %pagectime - %renderedfiles %pagesources}; + %renderedfiles %pagesources %inlinepages}; sub usage () { #{{{ die "usage: ikiwiki [options] source dest\n"; @@ -20,6 +20,7 @@ sub getconfig () { #{{{ %config=( wiki_file_prune_regexp => qr{((^|/).svn/|\.\.|^\.|\/\.|\.html?$)}, wiki_link_regexp => qr/\[\[([^\s\]]+)\]\]/, + wiki_processor_regexp => qr/\[\[(\w+)\s+([^\]]+)\]\]/, wiki_file_regexp => qr/(^[-A-Za-z0-9_.\&;:\/+]+$)/, verbose => 0, wikiname => "wiki", @@ -273,7 +274,7 @@ sub htmllink ($$;$$) { #{{{ $bestlink=htmlpage($bestlink); } if (! grep { $_ eq $bestlink } values %renderedfiles) { - return "?$linktext" + return "?$linktext" } $bestlink=File::Spec->abs2rel($bestlink, dirname($page)); @@ -332,6 +333,8 @@ sub loadindex () { #{{{ $oldpagemtime{$page}=$items{mtime}[0]; $oldlinks{$page}=[@{$items{link}}]; $links{$page}=[@{$items{link}}]; + $inlinepages{$page}=join(" ", @{$items{inlinepage}}) + if exists $items{inlinepage}; $renderedfiles{$page}=$items{dest}[0]; } $pagectime{$page}=$items{ctime}[0]; @@ -346,12 +349,14 @@ sub saveindex () { #{{{ open (OUT, ">$config{wikistatedir}/index") || error("cannot write to $config{wikistatedir}/index: $!"); foreach my $page (keys %oldpagemtime) { + next unless $oldpagemtime{$page}; my $line="mtime=$oldpagemtime{$page} ". "ctime=$pagectime{$page} ". "src=$pagesources{$page} ". "dest=$renderedfiles{$page}"; - if ($oldpagemtime{$page}) { - $line.=" link=$_" foreach @{$links{$page}}; + $line.=" link=$_" foreach @{$links{$page}}; + if (exists $inlinepages{$page}) { + $line.=" inlinepage=$_" foreach split " ", $inlinepages{$page}; } print OUT $line."\n"; } diff --git a/templates/inlinepage.tmpl b/templates/inlinepage.tmpl new file mode 100644 index 000000000..96e20e53f --- /dev/null +++ b/templates/inlinepage.tmpl @@ -0,0 +1,8 @@ +

+ + + +

+(posted ) +

+
diff --git a/templates/page.tmpl b/templates/page.tmpl index 5a7450af7..468361a9d 100644 --- a/templates/page.tmpl +++ b/templates/page.tmpl @@ -40,11 +40,13 @@

+ Last edited ; RSS +

-- cgit v1.2.3