* Add a calendar plugin, contributed by Manoj Srivastava.

* Reformat calendar plugin to ikiwiki conventions.
* The calendar plugin made *every* page depend on every other page,
  which seemed a wee tiny little bit overkill. Fixed the dependency
  calculations (I hope.)
* Removed manual ctime statting code, and just have the calendar plugin use
  %pagectime.
master
joey 2007-10-23 00:02:53 +00:00
parent 341a6c13c4
commit a27f4a47ba
6 changed files with 467 additions and 2 deletions

View File

@ -0,0 +1,368 @@
#! /usr/bin/perl
# Copyright (c) 2006, 2007 Manoj Srivastava <srivasta@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
require 5.002;
package IkiWiki::Plugin::calendar;
use warnings;
use strict;
use IkiWiki 2.00;
use Time::Local;
my %cache;
my %linkcache;
my @now=localtime();
sub import { #{{{
hook(type => "preprocess", id => "calendar", call => \&preprocess);
} #}}}
sub is_leap_year (@) { #{{
my %params=@_;
return ($params{year} % 4 == 0 && (($params{year} % 100 != 0) || $params{year} % 400 == 0));
} #}}}
sub month_days { #{{{
my %params=@_;
my $days_in_month = (31,28,31,30,31,30,31,31,30,31,30,31)[$params{month}-1];
if ($params{month} == 2 && is_leap_year(%params)) {
$days_in_month++;
}
return $days_in_month;
} #}}}
sub format_month (@) { #{{{
my %params=@_;
my $pagespec = $params{pages};
my $year = $params{year};
my $month = $params{month};
my $pmonth = $params{pmonth};
my $nmonth = $params{nmonth};
my $pyear = $params{pyear};
my $nyear = $params{nyear};
my @list;
my $calendar="\n";
# When did this month start?
my @monthstart = localtime(timelocal(0,0,0,1,$month-1,$year-1900));
my $future_dom = 0;
my $today = 0;
if ($year == $now[5]+1900 && $month == $now[4]+1) {
$future_dom = $now[3]+1;
$today = $now[3];
}
# Find out month names for this, next, and previous months
my $monthname=POSIX::strftime("%B", @monthstart);
my $pmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900)));
my $nmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900)));
my $archivebase = 'archives';
$archivebase = $config{archivebase} if defined $config{archivebase};
$archivebase = $params{archivebase} if defined $params{archivebase};
# Calculate URL's for monthly archives.
my ($url, $purl, $nurl)=("$monthname",'','');
if (exists $cache{$pagespec}{"$year/$month"}) {
$url = htmllink($params{page}, $params{destpage},
"$archivebase/$year/".sprintf("%02d", $month),
linktext => " $monthname ");
}
add_depends($params{page}, "$archivebase/$year/".sprintf("%02d", $month));
if (exists $cache{$pagespec}{"$pyear/$pmonth"}) {
$purl = htmllink($params{page}, $params{destpage},
"$archivebase/$pyear/" . sprintf("%02d", $pmonth),
linktext => " $pmonthname ");
}
add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth));
if (exists $cache{$pagespec}{"$nyear/$nmonth"}) {
$nurl = htmllink($params{page}, $params{destpage},
"$archivebase/$nyear/" . sprintf("%02d", $nmonth),
linktext => " $nmonthname ");
}
add_depends($params{page}, "$archivebase/$nyear/".sprintf("%02d", $nmonth));
# Start producing the month calendar
$calendar=<<EOF;
<table class="month-calendar">
<caption class="month-calendar-head">
$purl
$url
$nurl
</caption>
<tr>
EOF
# Suppose we want to start the week with day $week_start_day
# If $monthstart[6] == 1
my $week_start_day = $params{week_start_day};
my $start_day = 1 + (7 - $monthstart[6] + $week_start_day) % 7;
my %downame;
my %dowabbr;
for my $dow ($week_start_day..$week_start_day+6) {
my @day=localtime(timelocal(0,0,0,$start_day++,$month-1,$year-1900));
my $downame = POSIX::strftime("%A", @day);
my $dowabbr = POSIX::strftime("%a", @day);
$downame{$dow % 7}=$downame;
$dowabbr{$dow % 7}=$dowabbr;
$calendar.= qq{\t\t<th class="month-calendar-day-head $downame">$dowabbr</th>\n};
}
$calendar.=<<EOF;
</tr>
EOF
my $wday;
# we start with a week_start_day, and skip until we get to the first
for ($wday=$week_start_day; $wday != $monthstart[6]; $wday++, $wday %= 7) {
$calendar.=qq{\t<tr>\n} if $wday == $week_start_day;
$calendar.=qq{\t\t<td class="month-calendar-day-noday $downame{$wday}">&nbsp;</td>\n};
}
# At this point, either the first is a week_start_day, in which case
# nothing has been printed, or else we are in the middle of a row.
for (my $day = 1; $day <= month_days(year => $year, month => $month);
$day++, $wday++, $wday %= 7) {
# At tihs point, on a week_start_day, we close out a row,
# and start a new one -- unless it is week_start_day on the
# first, where we do not close a row -- since none was started.
if ($wday == $week_start_day) {
$calendar.=qq{\t</tr>\n} unless $day == 1;
$calendar.=qq{\t<tr>\n};
}
my $tag;
my $mtag = sprintf("%02d", $month);
if (defined $cache{$pagespec}{"$year/$mtag/$day"}) {
if ($day == $today) {
$tag='month-calendar-day-this-day';
}
else {
$tag='month-calendar-day-link';
}
$calendar.=qq{\t\t<td class="$tag $downame{$wday}">};
$calendar.=htmllink($params{page}, $params{destpage},
pagename($linkcache{"$year/$mtag/$day"}),
"linktext" => "$day");
push @list, pagename($linkcache{"$year/$mtag/$day"});
$calendar.=qq{</td>\n};
}
else {
if ($day == $today) {
$tag='month-calendar-day-this-day';
}
elsif ($day == $future_dom) {
$tag='month-calendar-day-future';
}
else {
$tag='month-calendar-day-nolink';
}
$calendar.=qq{\t\t<td class="$tag $downame{$wday}">$day</td>\n};
}
}
# finish off the week
for (; $wday != $week_start_day; $wday++, $wday %= 7) {
$calendar.=qq{\t\t<td class="month-calendar-day-noday $downame{$wday}">&nbsp;</td>\n};
}
$calendar.=<<EOF;
</tr>
</table>
EOF
# Add dependencies to update the calendar whenever pages
# matching the pagespec are added or removed.
add_depends($params{page}, $params{pages});
# Explicitly add all currently linked pages as dependencies, so
# that if they are removed, the calendar will be sure to be updated.
add_depends($params{page}, join(" or ", @list));
return $calendar;
}
sub format_year (@) {
my %params=@_;
my $pagespec = $params{pages};
my $year = $params{year};
my $month = $params{month};
my $pmonth = $params{pmonth};
my $nmonth = $params{nmonth};
my $pyear = $params{pyear};
my $nyear = $params{nyear};
my $calendar="\n";
my $future_month = 0;
$future_month = $now[4]+1 if ($year == $now[5]+1900);
my $archivebase = 'archives';
$archivebase = $config{archivebase} if defined $config{archivebase};
$archivebase = $params{archivebase} if defined $params{archivebase};
# calculate URL's for previous and next years
my ($url, $purl, $nurl)=("$year",'','');
if (exists $cache{$pagespec}{"$year"}) {
$url = htmllink($params{page}, $params{destpage},
"$archivebase/$year",
linktext => "$year");
}
add_depends($params{page}, "$archivebase/$year");
if (exists $cache{$pagespec}{"$pyear"}) {
$purl = htmllink($params{page}, $params{destpage},
"$archivebase/$pyear",
linktext => "\&larr;");
}
add_depends($params{page}, "$archivebase/$pyear");
if (exists $cache{$pagespec}{"$nyear"}) {
$nurl = htmllink($params{page}, $params{destpage},
"$archivebase/$nyear",
linktext => "\&rarr;");
}
add_depends($params{page}, "$archivebase/$nyear");
# Start producing the year calendar
$calendar=<<EOF;
<table class="year-calendar">
<caption class="year-calendar-head">
$purl
$url
$nurl
</caption>
<tr>
<th class="year-calendar-subhead" colspan="$params{months_per_row}">Months</th>
</tr>
EOF
for ($month = 1; $month <= 12; $month++) {
my @day=localtime(timelocal(0,0,0,15,$month-1,$year-1900));
my $murl;
my $monthname = POSIX::strftime("%B", @day);
my $monthabbr = POSIX::strftime("%b", @day);
$calendar.=qq{\t<tr>\n} if ($month % $params{months_per_row} == 1);
my $tag;
my $mtag=sprintf("%02d", $month);
if ($month == $params{month}) {
if ($cache{$pagespec}{"$year/$mtag"}) {
$tag = 'this_month_link';
}
else {
$tag = 'this_month_nolink';
}
}
elsif ($cache{$pagespec}{"$year/$mtag"}) {
$tag = 'month_link';
}
elsif ($future_month && $month >= $future_month) {
$tag = 'month_future';
}
else {
$tag = 'month_nolink';
}
if ($cache{$pagespec}{"$year/$mtag"}) {
$murl = htmllink($params{page}, $params{destpage},
"$archivebase/$year/$mtag",
linktext => "$monthabbr");
$calendar.=qq{\t<td class="$tag">};
$calendar.=$murl;
$calendar.=qq{\t</td>\n};
}
else {
$calendar.=qq{\t<td class="$tag">$monthabbr</td>\n};
}
add_depends($params{page}, "$archivebase/$year/$mtag");
$calendar.=qq{\t</tr>\n} if ($month % $params{months_per_row} == 0);
}
$calendar.=<<EOF;
</table>
EOF
return $calendar;
}
sub preprocess (@) {
my %params=@_;
$params{pages} = "*" unless defined $params{pages};
$params{type} = "month" unless defined $params{type};
$params{year} = 1900 + $now[5] unless defined $params{year};
$params{month} = sprintf("%02d", $params{month}) if defined $params{month};
$params{month} = 1 + $now[4] unless defined $params{month};
$params{week_start_day} = 0 unless defined $params{week_start_day};
$params{months_per_row} = 3 unless defined $params{months_per_row};
# Calculate month names for next month, and previous months
my $pmonth = $params{month} - 1;
my $nmonth = $params{month} + 1;
my $pyear = $params{year} - 1;
my $nyear = $params{year} + 1;
# Adjust for January and December
if ($params{month} == 1) {
$pmonth = 12;
$pyear--;
}
if ($params{month} == 12) {
$nmonth = 1;
$nyear++;
}
$params{pmonth}=$pmonth;
$params{nmonth}=$nmonth;
$params{pyear} =$pyear;
$params{nyear} =$nyear;
my $calendar="\n";
my $pagespec=$params{pages};
my $page =$params{page};
if (! defined $cache{$pagespec}) {
foreach my $p (keys %pagesources) {
next unless pagespec_match($p, $pagespec);
my $mtime = $IkiWiki::pagectime{$p};
my $src = $pagesources{$p};
my @date = localtime($mtime);
my $mday = $date[3];
my $month = $date[4] + 1;
my $year = $date[5] + 1900;
my $mtag = sprintf("%02d", $month);
# Only one posting per day is being linked to.
$linkcache{"$year/$mtag/$mday"} = "$src";
$cache{$pagespec}{"$year"}++;
$cache{$pagespec}{"$year/$mtag"}++;
$cache{$pagespec}{"$year/$mtag/$mday"}++;
}
}
if ($params{type} =~ /month/i) {
$calendar=format_month(%params);
}
elsif ($params{type} =~ /year/i) {
$calendar=format_year(%params);
}
return "\n<div class=\"calendar\">$calendar</div><!-- calendar -->\n";
}
1

9
debian/changelog vendored
View File

@ -3,8 +3,15 @@ ikiwiki (2.11) UNRELEASED; urgency=low
* Correct a pair of logic errors that triggered if svnpath was empty.
* If gitorigin_branch is set to the empty string, don't push or pull.
Useful for laptop clones of remote wikis.
* Add a calendar plugin, contributed by Manoj Srivastava.
* Reformat calendar plugin to ikiwiki conventions.
* The calendar plugin made *every* page depend on every other page,
which seemed a wee tiny little bit overkill. Fixed the dependency
calculations (I hope.)
* Removed manual ctime statting code, and just have the calendar plugin use
%pagectime.
-- Joey Hess <joeyh@debian.org> Sun, 21 Oct 2007 20:28:16 -0400
-- Joey Hess <joeyh@debian.org> Mon, 22 Oct 2007 18:24:00 -0400
ikiwiki (2.10) unstable; urgency=low

4
debian/copyright vendored
View File

@ -78,6 +78,10 @@ Files: plugins/rst
Copyright: © martin f. krafft <madduck@madduck.net>
License: GPL-2
Files: calendar.pm
Copyright: (c) 2006, 2007 Manoj Srivastava <srivasta@debian.org>
License: GPL-2+
Files: doc/logo/*
Copyright: © 2006 Recai Oktaş <roktas@debian.org>
License: GPL-2+

View File

@ -0,0 +1,76 @@
[[template id=plugin name=calendar author="[[ManojSrivastava]]"]]
[[tag type/chrome]]
This plugin displays a calendar, similar to the typical calendars shown on
some blogs.
# examples
\[[calendar ]]
\[[calendar type="month" pages="blog/* and !*/Discussion"]]
\[[calendar type="year" year="2005" pages="blog/* and !*/Discussion"]]
This plugin is inspired by the calendar plugin for Blosxom, but
derives no code from it. This plugin is essentially a fancy front end
to archives of previous pages, usually used for blogs. It can produce
a calendar for a given month, or a list of months for a given year.
The tricky part of this is that while calendar defaults to showing the
current day and month, ikiwiki is a wiki compiler, which only rebuilds
pages if they have changed. So to keep the calendar up-to-date, wikis that
include it need to be periodically rebuilt, typically by cron at midnight.
The month format calendar simply links to any page posted on each
day of the month. The year format calendar links to archive pages, with
names like `archives/2007` (for all of 2007) and `archives/2007/01`
(for January, 2007). For this to work, you'll need to create these archive
pages. They typically use [[inline]] to display or list pages created in
the given time frame.
## usage
* `type` - Used to specify the type of calendar wanted. Can be one of
"month" or "year". The default is a month view calendar.
* `pages` - Specifies the [[PageSpec]] of pages to link to from the
month calendar. Defaults to "*".
* `archivebase` - Configures the base of the archives hierarchy. The
default is "archives". Note that this default can also be overridden
for the whole wiki by setting `archivebase` in ikiwiki's setup file.
* `year` - The year for which the calendar is requested. Defaults to the
current year.
* `month` - The numeric month for which the calendar is requested, in the
range 1..12. Used only for the month view calendar, and defaults to the
current month.
* `week_start_day` - A number, in the range 0..6, which represents the day
of the week that the month calendar starts with. 0 is Sunday, 1 is Monday,
and so on. Defaults to 0, which is Sunday.
* `months_per_row` - In the annual calendar, number of months to place in
each row. Defaults to 3.
## CSS
The output is liberally sprinkled with classes, for fine grained CSS
customization.
* `month-calendar` - The month calendar as a whole.
* `month-calendar-head` - The head of the month calendar (ie,"March").
* `month-calendar-day-head` - A column head in the month calendar (ie, a
day-of-week abbreviation).
* `month-calendar-day-noday`, `month-calendar-day-link`,
`month-calendar-day-nolink`, `month-calendar-day-future`,
`month-calendar-day-this-day` - The day squares on the month calendar,
for days that are not in the month (before or after the month itself), that
don't have links, that do have links, that are in the future, or are that
are the current day, respectively.
* `Sunday`, `Monday`, `Tuesday`, ... - Each day square is also given a class
matching its (localised) day of week, this can be used to highlight
weekends.
* `year-calendar` - The year calendar as a whole.
* `year-calendar-head` - The head of the year calendar (ie, "2007").
* `year-calendar-subhead` - For example, "Months".
* `year-calendar-month-link`, `year-calendar-month-nolink`,
`year-calendar-month-future`, `year-calendar-this-month` - The month
squares on the year calendar, for months with stories,
without, in the future, and currently selected, respectively.

View File

@ -119,4 +119,6 @@ And that's all I've heard so far. Hoping I didn't miss another patch?
>> I think I have solved the ""Need to look at all pages that match the spec"" issue; but the nightly rebuild to handle the current day changing still remain. I use cron. It is now, however, richly documented :)
--ManojSrivastava
--ManojSrivastava
> Finally reviewed and applied this. [[done]]! --[[Joey]]

View File

@ -58,3 +58,11 @@ If I do this, I might as well also:
* Change the link= link= stuff to just links=link+link etc.
* Change the delimiter from space to comma; commas are rare in index files,
so less ugly escaped delimiters to deal with.
---
The [[plugins/calendar]] plugin could use plugin data storage to record
which pages have a calendar for the current time. Then ensure they are
rebuilt at least once a day. Currently, it needs a cron job to rebuild
the *whole* wiki every day; with this enhancement, the cron job would only
rebuild the few pages that really need it.