Add the new variables to the Configuration/constant variables section:
use vars qw(@RcDays @HtmlPairs @HtmlSingle $TempDir ... ... $InterWikiMoniker $SiteDescription $RssImageUrl $RssPublisher $RssContributor $RssRights);
In the Configuration section, set the variables:
$InterWikiMoniker = "EmacsWiki"; # InterWiki prefix for this wiki. (for RSS) $SiteDescription = "This is the Emacs and XEmacs know-how repository."; # Description of this wiki. (for RSS) $RssImageUrl = "http://www.emacswiki.org/emacs_rss.png"; # URL to image to associate with your RSS feed $RssPublisher = "Alex Schroeder"; $RssContributor = "The EmacsWiki community"; $RssRights = "Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation.";
As in the WikiPatches/ModWiki patch, DoRc now accepts a reference to a subroutine.
In BrowsePage, add the new parameter to the call to DoRc:
if (($id eq $RCName) || (T($RCName) eq $id) || (T($id) eq $RCName)) { print $fullHtml; &DoRc(\&GetRcHtml); print "<hr>\n" if (!&GetParam('embed', $EmbedWiki)); print &GetFooterText($id, $goodRevision); return; }
The changes to DoRc and GetRcHtml in the old script are pretty extensive and confusing so here is just a replacement chunk. Replace the old DoRc and GetRcHtml with the following code. Personally I find the code really hairy, but that is how it was done in the WikiPatches/ModWiki patch, and I did not feel like reinventing yet another wheel.
Here is how to read the patch:
$GetRC
according to @_ (the new parameter)
$showHTML
if $GetRC
is the HTML function
if( $showHTML )
GetRc
. This takes three parameters: A block to execute for every day, a block to execute for every line, and the lines themselves.
GetRcHtml
such that it now calls GetRc
with the necessary code passed in the two blocks.
GetRcRss
subroutine that also uses GetRc
.
DoRss
subroutine.
Note that in order to use PRE tags to escape this source code, I had
to change some existing </pre>
tags to
</pre" . ">
-- you can undo this, of course.
By default, the RSS returned is limited to first 15 items. This limit is recommended in the standard. If you want more items, pass the rsslimit parameter along with the upper limit you want, or use `all' to indicate that you want the maximum. Here is a reminder of the more usefull options you can use: `days=12' is the number of days, `from' is the start time, `showedits=1' includes minor edits, `showedits=2' shows only minor edits, `all=1' shows all changes, not only the latest change for every page, and `newtop=0' shows the latest changes at the end of the list. Watch out: If you use `newtop=0', you should probably use `rsslimit=all', too.
Validation:
sub DoRc { my ($GetRC) = @_; my ($fileData, $rcline, $i, $daysago, $lastTs, $ts, $idOnly); my (@fullrc, $status, $oldFileData, $firstTs, $errorText); my $starttime = 0; my $showbar = 0; my $showHTML = $GetRC eq \&GetRcHtml; # Special (normative) case if (&GetParam("from", 0)) { $starttime = &GetParam("from", 0); if( $showHTML ) { print "<h2>" . Ts('Updates since %s', &TimeToText($starttime)) . "</h2>\n"; } } else { $daysago = &GetParam("days", 0); $daysago = &GetParam("rcdays", 0) if ($daysago == 0); if ($daysago) { $starttime = $Now - ((24*60*60)*$daysago); if( $showHTML ) { print "<h2>" . Ts('Updates in the last %s day' . (($daysago != 1)?"s":""), $daysago) . "</h2>\n"; } # Note: must have two translations (for "day" and "days") # Following comment line is for translation helper script # Ts('Updates in the last %s days', ''); } } if ($starttime == 0) { $starttime = $Now - ((24*60*60)*$RcDefault); if( $showHTML ) { print "<h2>" . Ts('Updates in the last %s day' . (($RcDefault != 1)?"s":""), $RcDefault) . "</h2>\n"; } # Translation of above line is identical to previous version } # Read rclog data (and oldrclog data if needed) ($status, $fileData) = &ReadFile($RcFile); $errorText = ""; if (!$status) { # Save error text if needed. $errorText = '<p><strong>' . Ts('Could not open %s log file', $RCName) . ":</strong> $RcFile<p>" . T('Error was') . ":\n<pre>$!</pre" . ">\n" . '<p>' . T('Note: This error is normal if no changes have been made.') . "\n"; } @fullrc = split(/\n/, $fileData); $firstTs = 0; if (@fullrc > 0) { # Only false if no lines in file ($firstTs) = split(/$FS3/, $fullrc[0]); } if (($firstTs == 0) || ($starttime <= $firstTs)) { ($status, $oldFileData) = &ReadFile($RcOldFile); if ($status) { @fullrc = split(/\n/, $oldFileData . $fileData); } else { if ($errorText ne "") { # could not open either rclog file print $errorText; print "<p><strong>" . Ts('Could not open old %s log file', $RCName) . ":</strong> $RcOldFile<p>" . T('Error was') . ":\n<pre>$!</pre" . ">\n"; return; } } } $lastTs = 0; if (@fullrc > 0) { # Only false if no lines in file ($lastTs) = split(/$FS3/, $fullrc[$#fullrc]); } $lastTs++ if (($Now - $lastTs) > 5); # Skip last unless very recent $idOnly = &GetParam("rcidonly", ""); if ($idOnly && $showHTML) { print '<b>(' . Ts('for %s only', &ScriptLink($idOnly, $idOnly)) . ')</b><br>'; } if( $showHTML ) { foreach $i (@RcDays) { print " | " if $showbar; $showbar = 1; print &ScriptLink("action=rc&days=$i", Ts('%s day' . (($i != 1)?'s':''), $i)); # Note: must have two translations (for "day" and "days") # Following comment line is for translation helper script # Ts('%s days', ''); } print "<br>" . &ScriptLink("action=rc&from=$lastTs", T('List new changes starting from')); print " " . &TimeToText($lastTs) . "<br>\n"; } # Later consider a binary search? $i = 0; while ($i < @fullrc) { # Optimization: skip old entries quickly ($ts) = split(/$FS3/, $fullrc[$i]); if ($ts >= $starttime) { $i -= 1000 if ($i > 0); last; } $i += 1000; } $i -= 1000 if (($i > 0) && ($i >= @fullrc)); for (; $i < @fullrc ; $i++) { ($ts) = split(/$FS3/, $fullrc[$i]); last if ($ts >= $starttime); } if ($i == @fullrc && $showHTML) { print '<br><strong>' . Ts('No updates since %s', &TimeToText($starttime)) . "</strong><br>\n"; } else { splice(@fullrc, 0, $i); # Remove items before index $i # Later consider an end-time limit (items older than X) print &$GetRC(@fullrc); } print '<p>' . Ts('Page generated %s', &TimeToText($Now)), "<br>\n" if $showHTML; } sub GetRc { my $printDailyTear = shift; my $printRCLine = shift; my @outrc = @_; my ($rcline, $date, $newtop, $author); my ($showedit, $link, $all, $idOnly); my ($ts, $pagename, $summary, $isEdit, $host, $kind, $extraTemp); my %extra = (); my %changetime = (); my %pagecount = (); # Slice minor edits $showedit = &GetParam("rcshowedit", $ShowEdits); $showedit = &GetParam("showedit", $showedit); if ($showedit != 1) { my @temprc = (); foreach $rcline (@outrc) { ($ts, $pagename, $summary, $isEdit, $host) = split(/$FS3/, $rcline); if ($showedit == 0) { # 0 = No edits push(@temprc, $rcline) if (!$isEdit); } else { # 2 = Only edits push(@temprc, $rcline) if ($isEdit); } } @outrc = @temprc; } # Later consider folding into loop above? # Later add lines to assoc. pagename array (for new RC display) foreach $rcline (@outrc) { ($ts, $pagename) = split(/$FS3/, $rcline); $pagecount{$pagename}++; $changetime{$pagename} = $ts; } $date = ""; $all = &GetParam("rcall", 0); $all = &GetParam("all", $all); $newtop = &GetParam("rcnewtop", $RecentTop); $newtop = &GetParam("newtop", $newtop); $idOnly = &GetParam("rcidonly", ""); @outrc = reverse @outrc if ($newtop); foreach $rcline (@outrc) { ($ts, $pagename, $summary, $isEdit, $host, $kind, $extraTemp) = split(/$FS3/, $rcline); # Later: need to change $all for new-RC? next if ((!$all) && ($ts < $changetime{$pagename})); next if (($idOnly ne "") && ($idOnly ne $pagename)); %extra = split(/$FS2/, $extraTemp, -1); if ($date ne &CalcDay($ts)) { $date = &CalcDay($ts); &$printDailyTear($date); } &$printRCLine( $pagename, $ts, $host, $extra{'name'}, $extra{'id'}, $summary, $isEdit, $pagecount{$pagename}, $extra{'revision'} ); } } sub GetRcHtml { my ($html, $inlist, $all, $rcchangehist); my ($tEdit, $tChanges, $tDiff); # Optimize param fetches out of main loop $all = &GetParam("rcall", 0); $all = &GetParam("all", $all); $rcchangehist = &GetParam("rcchangehist", 1); # Optimize translations out of main loop $tEdit = T('(edit)'); $tDiff = T('(diff)'); $tChanges = T('changes'); GetRc # printDailyTear sub { my $date = shift; if ($inlist) { $html .= "</UL>\n"; $inlist = 0; } $html .= "<p><strong>" . $date . "</strong><p>\n"; if (!$inlist) { $html .= "<UL>\n"; $inlist = 1; } }, # printRCLine sub { my( $pagename, $timestamp, $host, $userName, $userID, $summary, $isEdit, $pagecount, $revision ) = @_; my( $author, $sum, $edit, $count, $link ); $host = &QuoteHtml($host); if (defined($userName) && defined($userID)) { $author = &GetAuthorLink($host, $userName, $userID); } else { $author = &GetAuthorLink($host, "", 0); } $sum = ""; if (($summary ne "") && ($summary ne "*")) { $summary = &QuoteHtml($summary); $sum = "<strong>[$summary]</strong> "; } $edit = ""; $edit = "<em>$tEdit</em> " if ($isEdit); $count = ""; if ((!$all) && ($pagecount > 1)) { $count = "($pagecount "; if ($rcchangehist) { $count .= &GetHistoryLink($pagename, $tChanges); } else { $count .= $tChanges; } $count .= ") "; } $link = ""; if ($UseDiff && &GetParam("diffrclink", 1)) { $link .= &ScriptLinkDiff(4, $pagename, $tDiff, "") . " "; } $link .= &GetPageLink($pagename); $html .= "<li>$link "; # Later do new-RC looping here. $html .= &CalcTime($timestamp) . " $count$edit" . " $sum"; $html .= ". . . . . $author\n"; # Make dots optional? }, @_; $html .= "</UL>\n" if ($inlist); return $html; } sub GetRcRss { my ($QuotedFullUrl, $ChannelAbout, $diffPrefix, $historyPrefix); # Normally get URL from script, but allow override. $FullUrl = $q->url(-full=>1) if ($FullUrl eq ""); $QuotedFullUrl = &QuoteHtml($FullUrl); $diffPrefix = $QuotedFullUrl . &QuoteHtml("?action=browse\&diff=4\&id="); $historyPrefix = $QuotedFullUrl . &QuoteHtml("?action=history\&id="); $SiteDescription = &QuoteHtml($SiteDescription); my $timestamp = time + $TimeZoneOffset; my ($sec, $min, $hour, $mday, $mon, $year) = localtime($timestamp); $year += 1900; my $date = sprintf( "%4d-%02d-%02dT%02d:%02d:%02d+%02d:00", $year, $mon+1, $mday, $hour, $min, $sec, $TimeZoneOffset/(60*60) ); require XML::RSS; my $rss = new XML::RSS (version => '1.0', encoding => $HttpCharset); $rss->add_module( prefix => 'wiki', uri => 'http://purl.org/rss/1.0/modules/wiki/' ); $rss->channel( title => &QuoteHtml($SiteName), link => $QuotedFullUrl . &QuoteHtml("?$RCName"), description => $SiteDescription, dc => { publisher => $RssPublisher, contributor => $RssContributor, date => $date, rights => $RssRights, }, wiki => { interwiki => $InterWikiMoniker, }, ); $rss->image( title => &QuoteHtml($SiteName), url => $RssImageUrl, link => $QuotedFullUrl, ); # Now call GetRc with some blocks of code as parameters: GetRc # printDailyTear sub {}, # printRCLine sub { my( $pagename, $timestamp, $host, $userName, $userID, $summary, $isEdit, $pagecount, $revision ) = @_; my( $description, $author, $status, $importance, $date ); $timestamp += $TimeZoneOffset; my ($sec, $min, $hour, $mday, $mon, $year) = localtime($timestamp); $year += 1900; $date = sprintf( "%4d-%02d-%02dT%02d:%02d:%02d+%02d:00", $year, $mon+1, $mday, $hour, $min, $sec, $TimeZoneOffset/(60*60) ); if (($summary ne "") && ($summary ne "*")) { $description = &QuoteHtml($summary); } if( $userName ) { $author = &QuoteHtml($userName); } else { $author = $host; } $status = (1 == $revision) ? 'new' : 'updated'; $importance = $isEdit ? 'minor' : 'major'; $rss->add_item( title => &QuoteHtml($pagename), link => $QuotedFullUrl . '?action=browse' . '&id=' . $pagename . '&revision=' . $revision, description => $description, dc => { date => $date, contributor => $author, }, wiki => { status => $status, importance => $importance, diff => $diffPrefix . $pagename, version => $revision, history => $historyPrefix . $pagename, }, ); }, # RC Lines @_; # Only take the first 15 entries my $limit = &GetParam("rsslimit", 14); if ($limit != 'all') { @{$rss->{'items'}} = @{$rss->{'items'}}[0..$limit]; } return $rss->as_string; } sub DoRss { print "Content-type: text/plain\n\n"; &DoRc(\&GetRcRss); }
This last subroutine, DoRss
is what we need to call when
we want the RSS output. In DoOtherRequest, therefore, we add the
following fragment, anywhere amongst the various actions:
} elsif ($action eq "rss") { &DoRss();
print "Content-type: application/xml\n\n";
"[This document] summarizes the best current practice for using various Internet media types for serving various XHTML Family documents. In summary, 'application/xhtml+xml' SHOULD be used for XHTML Family documents, and the use of 'text/html' SHOULD be limited to HTML-compatible XHTML 1.0 documents. 'application/xml' and 'text/xml' MAY also be used, but whenever appropriate, 'application/xhtml+xml' SHOULD be used rather than those generic XML media types."