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,
} #}}}
sub absolute_urls ($$) { #{{{
+ # sucky sub because rss sucks
my $content=shift;
my $url=shift;
$content=~s/<a\s+href="(?!http:\/\/)([^"]+)"/<a href="$url$1"/ig;
$content=~s/<img\s+src="(?!http:\/\/)([^"]+)"/<img src="$url$1"/ig;
return $content;
-} #}}}
+} #}}}zo
sub genrss ($$$) { #{{{
my $content=shift;
my $page=shift;
my $mtime=shift;
-
+
my $url="$config{url}/".htmlpage($page);
my $template=HTML::Template->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},
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);
}
# 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
next FILE;
}
}
+ if (exists $inlinepages{$page} &&
+ globlist_match($p, $inlinepages{$page})) {
+ debug("rendering $file, which inlines $p");
+ render($file);
+ $rendered{$file}=1;
+ }
}
}
}
--- /dev/null
+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.
----
+Advanced users can use [[PostProcessorDirective]]s to do additional cool
+stuff.
+
+----
+
This style of text formatting is called [[MarkDown]].
--- /dev/null
+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]]
--- /dev/null
+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.
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,
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]]
----
+Advanced users can use [[PostProcessorDirective]]s to do additional cool
+stuff.
+
+----
+
This style of text formatting is called [[MarkDown]].
--- /dev/null
+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]]
[[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"]]
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
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"
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";
%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",
$bestlink=htmlpage($bestlink);
}
if (! grep { $_ eq $bestlink } values %renderedfiles) {
- return "<a href=\"$config{cgiurl}?do=create&page=$link&from=$page\">?</a>$linktext"
+ return "<span><a href=\"$config{cgiurl}?do=create&page=$link&from=$page\">?</a>$linktext</span>"
}
$bestlink=File::Spec->abs2rel($bestlink, dirname($page));
$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];
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";
}
--- /dev/null
+<h2><TMPL_VAR PAGELINK></h2>
+
+<TMPL_VAR CONTENT>
+
+<p>
+<i>(posted <TMPL_VAR CTIME>)</i>
+</p>
+<hr>
</TMPL_IF>
<p>
+<i>
<!-- from <TMPL_VAR NAME=WIKINAME> -->
Last edited <TMPL_VAR NAME=MTIME>
<TMPL_IF NAME="RSSURL">
; <a type="application/rss+xml" href="<TMPL_VAR NAME=RSSURL>">RSS</a>
</TMPL_IF>
+</i>
</p>
</body>