aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--IkiWiki/Render.pm78
-rw-r--r--doc/features.mdwn7
-rw-r--r--doc/ikiwiki.setup2
-rw-r--r--doc/usage.mdwn6
-rwxr-xr-xikiwiki7
-rw-r--r--templates/page.tmpl5
-rw-r--r--templates/rsspage.tmpl21
7 files changed, 120 insertions, 6 deletions
diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm
index df24fd568..646e254a5 100644
--- a/IkiWiki/Render.pm
+++ b/IkiWiki/Render.pm
@@ -79,7 +79,13 @@ sub parentlinks ($) { #{{{
return @ret;
} #}}}
-sub finalize ($$$) { #{{{
+sub rsspage ($) { #{{{
+ my $page=shift;
+
+ return $page.".rss";
+} #}}}
+
+sub genpage ($$$) { #{{{
my $content=shift;
my $page=shift;
my $mtime=shift;
@@ -102,6 +108,10 @@ sub finalize ($$$) { #{{{
$u=~s/\[\[file\]\]/$pagesources{$page}/g;
$template->param(historyurl => $u);
}
+
+ if ($config{rss}) {
+ $template->param(rssurl => rsspage($page));
+ }
$template->param(
title => $title,
@@ -116,6 +126,59 @@ sub finalize ($$$) { #{{{
return $template->output;
} #}}}
+sub date_822 ($) { #{{{
+ my $time=shift;
+
+ eval q{use POSIX};
+ return POSIX::strftime("%a, %d %b %Y %H:%M:%S %z", localtime($time));
+} #}}}
+
+sub absolute_urls ($$) { #{{{
+ my $content=shift;
+ my $url=shift;
+
+ $url=~s/[^\/]+$//;
+
+ $content=~s{<a\s+href="([^"]+)"}{
+ "<a href=\"$url$1\""
+ }ieg;
+ $content=~s{<img\s+src="([^"]+)"}{
+ "<img src=\"$url$1\""
+ }ieg;
+ return $content;
+} #}}}
+
+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");
+
+ # 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
+ },
+ );
+
+ $template->param(
+ title => pagetitle(basename($page)),
+ pageurl => $url,
+ items => \@items,
+ );
+
+ return $template->output;
+} #}}}
+
sub check_overwrite ($$) { #{{{
# Important security check. Make sure to call this before saving
# any files to the source directory.
@@ -161,13 +224,20 @@ sub render ($) { #{{{
$content=linkify($content, $page);
$content=htmlize($type, $content);
- $content=finalize($content, $page,
- mtime("$config{srcdir}/$file"));
check_overwrite("$config{destdir}/".htmlpage($page), $page);
- writefile("$config{destdir}/".htmlpage($page), $content);
+ writefile("$config{destdir}/".htmlpage($page),
+ genpage($content, $page, mtime("$config{srcdir}/$file")));
$oldpagemtime{$page}=time;
$renderedfiles{$page}=htmlpage($page);
+
+ # TODO: should really add this to renderedfiles and call
+ # check_overwrite, as above, but currently renderedfiles
+ # only supports listing one file per page.
+ if ($config{rss}) {
+ writefile("$config{destdir}/".rsspage($page),
+ genrss($content, $page, mtime("$config{srcdir}/$file")));
+ }
}
else {
$links{$file}=[];
diff --git a/doc/features.mdwn b/doc/features.mdwn
index c20da504d..4699f3096 100644
--- a/doc/features.mdwn
+++ b/doc/features.mdwn
@@ -27,6 +27,13 @@ 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,
diff --git a/doc/ikiwiki.setup b/doc/ikiwiki.setup
index 374093a5e..b81983080 100644
--- a/doc/ikiwiki.setup
+++ b/doc/ikiwiki.setup
@@ -44,4 +44,6 @@ use IkiWiki::Setup::Standard {
# Can anonymous web users edit pages?
#anonok => 1,
+ # Generate rss feeds for pages?
+ #rss => 1,
}
diff --git a/doc/usage.mdwn b/doc/usage.mdwn
index b9744438b..02d01f49c 100644
--- a/doc/usage.mdwn
+++ b/doc/usage.mdwn
@@ -64,6 +64,12 @@ flags such as --verbose can be negated with --no-verbose.
By default, anonymous users cannot edit the wiki.
+* --rss, --norss
+
+ If rss is set, along with every html page rendered by ikiwiki, an rss
+ page will also be rendered, to allow users to subscribe to a rss feed of
+ changes to that page.
+
* --cgi
Enable [[CGI]] mode. In cgi mode ikiwiki runs as a cgi script, and supports editing pages, signing in, registration, and displaying [[RecentChanges]].
diff --git a/ikiwiki b/ikiwiki
index 3540f8667..5c708919a 100755
--- a/ikiwiki
+++ b/ikiwiki
@@ -30,6 +30,7 @@ sub getconfig () { #{{{
historyurl => '',
diffurl => '',
anonok => 0,
+ rss => 0,
rebuild => 0,
wrapper => undef,
wrappermode => undef,
@@ -49,6 +50,7 @@ sub getconfig () { #{{{
"wrappermode=i" => \$config{wrappermode},
"svn!" => \$config{svn},
"anonok!" => \$config{anonok},
+ "rss!" => \$config{rss},
"cgi!" => \$config{cgi},
"url=s" => \$config{url},
"cgiurl=s" => \$config{cgiurl},
@@ -85,7 +87,10 @@ sub getconfig () { #{{{
sub checkconfig () { #{{{
if ($config{cgi} && ! length $config{url}) {
- error("Must specify url to wiki with --url when using --cgi");
+ error("Must specify url to wiki with --url when using --cgi\n");
+ }
+ if ($config{rss} && ! length $config{url}) {
+ error("Must specify url to wiki with --url when using --rss\n");
}
$config{wikistatedir}="$config{srcdir}/.ikiwiki"
diff --git a/templates/page.tmpl b/templates/page.tmpl
index 1e484056e..5a7450af7 100644
--- a/templates/page.tmpl
+++ b/templates/page.tmpl
@@ -41,7 +41,10 @@
<p>
<!-- from <TMPL_VAR NAME=WIKINAME> -->
-last edited <TMPL_VAR NAME=MTIME>
+Last edited <TMPL_VAR NAME=MTIME>
+<TMPL_IF NAME="RSSURL">
+; <a type="application/rss+xml" href="<TMPL_VAR NAME=RSSURL>">RSS</a>
+</TMPL_IF>
</p>
</body>
diff --git a/templates/rsspage.tmpl b/templates/rsspage.tmpl
new file mode 100644
index 000000000..cbfeb5471
--- /dev/null
+++ b/templates/rsspage.tmpl
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<rss version="2.0">
+ <channel>
+ <title><TMPL_VAR TITLE ESCAPE=HTML></title>
+ <link><TMPL_VAR PAGEURL></link>
+ <description><TMPL_VAR TITLE ESCAPE=HTML></description>
+ <TMPL_LOOP NAME="ITEMS">
+ <item>
+ <title><TMPL_VAR ITEMTITLE ESCAPE=HTML></title>
+ <TMPL_IF NAME="ITEMGUID">
+ <guid isPermaLink="false"><TMPL_VAR ITEMGUID></guid>
+ <TMPL_ELSE>
+ <guid><TMPL_VAR ITEMURL></guid>
+ </TMPL_IF>
+ <link><TMPL_VAR ITEMURL></link>
+ <pubDate><TMPL_VAR ITEMPUBDATE></pubDate>
+ <description><![CDATA[<TMPL_VAR ITEMCONTENT>]]></description>
+ </item>
+ </TMPL_LOOP>
+ </channel>
+</rss>