web commit by ManojSrivastava
[ikiwiki.git] / doc / todo / calendar_--_archive_browsing_via_a_calendar_frontend.mdwn
1 I am serving notice that I am starting work on a calendar plugin inspired by Blosxom's calendar plugin. The current plan is to create a plugin that looks through all the source files matching a certain pagespec, and optionally spit out a month view for the specified month (default to current), or spit out a year view for a given year (defaulting to the current year), of a list  of year with posts in them. The output would be a table, with the same CSS directives that the Blosxom plugin used to use (so that I can just reuse my css file).  The links would be created to a $config{archivedir}/$year or $config{archivedir}/$year-$month file, which can just have 
2
3      \[[inline pages="blog/* and !*/Discussion and creation_year($year) and creation_month($month)" rss="no" atom="no" show="0"]]
4
5 or some thing to generate a archive of postings. 
6
7 Roland Mas suggested a separate cron job to generate these archive indices automatically, but that is another thread.
8
9 ManojSrivastava
10
11 This plugin is inspired by the calendar plugin for Blosxom, but derivesno 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. To invoke the calendar, just use the preprocessor directive:
12
13      \[[calendar ]]
14
15 or
16
17       \[[calendar type="month" pages="blog/* and !*/Discussion"]]
18
19 or
20
21        \[[calendar type="year"  year="2005" pages="blog/* and !*/Discussion"]]
22
23
24 The year and month entities in the out put have links to archive index pages, which are supposed to exist already. The idea is to create an archives hierarchy, rooted in the subdirectory specified in the site-wide customization variable, archivebase. archivebase defaults to "archives".  Links are created to pages "$archivebase/$year" and "$archivebase/$year/$month". The idea is to create annual and monthly indices, for example, by using something like this sample from my archives/2006/01.mdwn 
25
26           \[[meta title="Archives for 2006/01"]]
27           \[[inline rootpage="blog" atom="no" rss="no" show="0" pages="blog/* and !*/Discussion and creation_year(2006) and creation_month(01)" ]]
28
29 I'll send in the patch via email.
30
31 ManojSrivastava
32
33 ------
34
35 Since this is a little bit er, stalled, I'll post here the stuff Manoj
36 mailed me, and my response to it. --[[Joey]]
37
38
39
40 [[tag patch]]
41
42 <pre>
43 #! /usr/bin/perl
44 #                              -*- Mode: Cperl -*- 
45 # calendar.pm --- 
46 # Author           : Manoj Srivastava ( srivasta@glaurung.internal.golden-gryphon.com ) 
47 # Created On       : Fri Dec  8 16:05:48 2006
48 # Created On Node  : glaurung.internal.golden-gryphon.com
49 # Last Modified By : Manoj Srivastava
50 # Last Modified On : Sun Dec 10 01:53:22 2006
51 # Last Machine Used: glaurung.internal.golden-gryphon.com
52 # Update Count     : 139
53 # Status           : Unknown, Use with caution!
54 # HISTORY          : 
55 # Description      : 
56
57 # arch-tag: 2aa737c7-3d62-4918-aaeb-fd85b4b1384c
58 #
59 # Copyright (c) 2006 Manoj Srivastava <srivasta@debian.org>
60 #
61 # This program is free software; you can redistribute it and/or modify
62 # it under the terms of the GNU General Public License as published by
63 # the Free Software Foundation; either version 2 of the License, or
64 # (at your option) any later version.
65 #
66 # This program is distributed in the hope that it will be useful,
67 # but WITHOUT ANY WARRANTY; without even the implied warranty of
68 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
69 # GNU General Public License for more details.
70 #
71 # You should have received a copy of the GNU General Public License
72 # along with this program; if not, write to the Free Software
73 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
74 #
75
76 require 5.002;
77 package IkiWiki::Plugin::calendar;
78
79 use warnings;
80 use strict;
81 use IkiWiki '1.00';
82 use Time::Local;
83
84 our $VERSION = "0.1";
85 my $file = __FILE__;
86
87 my %calpages;
88 my %cache;
89 my %linkcache;
90
91 my $index=1;
92 my @now=localtime();
93
94 =head1 NAME
95
96 calendar - Add links for the current month's, current year's, and older archived postings
97
98 =cut
99
100 =head1 SYNOPSIS
101
102 To invoke the calendar, just use the preprocessor directive (options
103 and variations are detailed below):
104
105   [[calendar ]]
106
107 or
108
109   [[calendar type="month" pages="blog/* and !*/Discussion"]]
110
111 or
112
113   [[calendar type="year"  year="2005" pages="blog/* and !*/Discussion"]]
114
115 =cut
116
117
118 =head1 DESCRIPTION
119
120 This plugin is inspired by the calendar plugin for Blosxom, but
121 derives no code from it. This plugin is essentially a fancy front end
122 to archives of previous pages, usually used for blogs. It can produce
123 a calendar for a given month, or a list of months for a given year. 
124
125 The year and month entities in the out put have links to archive index
126 pages, which are supposed to exist already. The idea is to create an
127 archives hierarchy, rooted in the subdirectory specified in the
128 site wide customization variable, I<archivebase>. I<archivebase>
129 defaults to C<archives>.  Links are created to pages
130 C<$archivebase/$year> and C<$archivebase/$year/$month>. If one creates
131 annual and monthly indices, for example, by using something like this
132 sample from my I<archives/2006/01.mdwn> (warning: line split for
133 readability):
134
135    \[[meta title="Archives for 2006/01"]]
136    \[[inline rootpage="blog" atom="no" rss="no" show="0"
137      pages="blog/* and !*/Discussion and creation_year(2006)
138             and creation_month(01)"
139    ]]
140
141 =cut
142
143 =head1 OPTIONS
144
145 =over
146
147 =item B<type>
148
149 Used to specify the type of calendar wanted. Can be one of C<month> or
150 C<year>. The default is a month view calendar.
151
152 =item B<pages>
153
154 Specifies the C<pagespec> used to get pages to match for
155 linking. Usually this should be something like C<blog/* and !*/Discussion>.
156 Defaults to C<*>.
157
158 =item B<year>
159
160 The year for which the calendar is requested. Defaults to the current year.
161
162 =item B<month>
163
164 The numeric month for which the calendar is requested, in the range
165 1..12. Used only for the month view calendar, and defaults to the
166 current month.
167
168 =item B<week_start_day>
169
170 A number, in the range 0..6, which represents the day of the week that
171 the month calendar starts with. 0 is Sunday, 1 is Monday, and so
172 on. Defaults to 0, which is Sunday.
173
174 =item B<months_per_row>
175
176 In the annual calendar, number of months to place in each row. Defaults to 3.
177
178 =back
179
180 =cut
181
182 =head1 Classes for CSS control
183
184 The output is liberally sprinkled with classes, for fine grained CSS
185 customization.
186
187 =over
188
189 =item C<month-calendar> 
190
191 The month calendar as a whole
192
193 =item C<month-calendar-head>
194
195 The head of the month calendar (ie,"March"), localized to the environment.
196
197 =item C<month-calendar-day-head>
198
199 A column head in the month calendar (ie, a day-of-week abbreviation),
200 localized.
201
202 =item C<month-calendar-day-noday>, C<month-calendar-day-link>,
203   C<month-calendar-day-nolink>, C<month-calendar-day-future>,
204   C<month-calendar-day-this-day> 
205
206 The day squares on the month calendar, for days that don't exist
207 (before or after the month itself), that don't have stories, that do
208 have stories, that are in the future, or are that currently selected,
209 respectively (today).
210
211 =item Day-of-week-name
212
213 Each day square is also given a class matching its day of week, this
214 can be used to high light weekends. This is also localized.
215
216 =item C<year-calendar>
217
218 The year calendar as a whole
219
220 =item C<year-calendar-head>
221
222 The head of the year calendar (ie, "2006")
223
224 =item C<year-calendar-subhead>
225
226 For example, "Months"
227
228 =item C<year-calendar-month-link>, C<year-calendar-month-nolink>,
229   C<year-calendar-month-future>, C<year-calendar-this-month>
230
231 The month squares on the year calendar, for months with stories,
232 without, in the future, and currently selected, respectively.
233
234 =back
235
236 =cut
237
238
239 sub import {
240   hook(type => "preprocess", id => "calendar", call => \&preprocess);
241   hook(type => "format", id => "calendar", call => \&format);
242 }
243
244 sub preprocess (@) {
245   my %params=@_;
246   $params{pages} = "*"            unless defined $params{pages};
247   $params{type}  = "month"        unless defined $params{type};
248   $params{year}  = 1900 + $now[5] unless defined $params{year};
249   $params{month} = sprintf("%02d", $params{month}) if defined  $params{month};
250   $params{month} = 1    + $now[4] unless defined $params{month};
251   $params{week_start_day} = 0     unless defined $params{week_start_day};
252   $params{months_per_row} = 3     unless defined $params{months_per_row};
253
254   # Store parameters (could be multiple calls per page)
255   $calpages{$params{destpage}}{$index} = \%params;
256
257   return "\n<div class=\"calendar\">" . $index++ . "</div><!-- calendar -->\n";
258 }
259
260 sub is_leap_year (@) {
261   my %params=@_;
262   return ($params{year} % 4 == 0 && (($params{year} % 100 != 0) || $params{year} % 400 ==0)) ;
263 }
264
265
266 sub month_days {
267   my %params=@_;
268   my $days_in_month = (31,28,31,30,31,30,31,31,30,31,30,31)[$params{month}-1];
269   if ($params{month} == 2 && is_leap_year(%params)) {
270     $days_in_month++;
271   }
272   return $days_in_month;
273 }
274
275
276 sub format_month (@) {
277   my %params=@_;
278   my $pagespec = $params{pages};
279   my $year     = $params{year};
280   my $month    = $params{month};
281
282   my $calendar="\n";
283
284   # When did this month start?
285   my @monthstart = localtime(timelocal(0,0,0,1,$month-1,$year-1900));
286
287   my $future_dom = 0;
288   my $today      = 0;
289   $future_dom = $now[3]+1 if ($year == $now[5]+1900 && $month == $now[4]+1);
290   $today      = $now[3]   if ($year == $now[5]+1900 && $month == $now[4]+1);
291
292   # Calculate month names for next month, and previous months
293   my $pmonth = $month - 1;
294   my $nmonth = $month + 1;
295   my $pyear  = $year;
296   my $nyear  = $year;
297
298   # Adjust for January and December
299   if ($month == 1)  { $pmonth = 12; $pyear--;  }
300   if ($month == 12) { $nmonth = 1;  $nyear++;  }
301
302   # Find out month names for this, next, and previous months
303   my $monthname=POSIX::strftime("%B", @monthstart);
304   my $pmonthname=
305     POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900)));
306   my $nmonthname=
307     POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900)));
308
309   # Calculate URL's for monthly archives, and article counts
310   my $archivebase = 'archives';
311   $archivebase = $config{archivebase} if defined $config{archivebase};
312
313   my ($url, $purl, $nurl)=("$monthname",'','');
314   my ($count, $pcount, $ncount) = (0,0,0);
315
316   if (exists $cache{$pagespec}{"$year/$month"}) {
317     $url = htmllink($params{page}, $params{destpage}, 
318                     "$archivebase/$year/" . sprintf("%02d", $month),
319                     0,0," $monthname ");
320   }
321
322   if (exists $cache{$pagespec}{"$pyear/$pmonth"}) {
323     $purl = htmllink($params{page}, $params{destpage}, 
324                      "$archivebase/$pyear/" . sprintf("%02d", $pmonth),
325                      0,0," $pmonthname ");
326   }
327   if (exists $cache{$pagespec}{"$nyear/$nmonth"}) {
328     $nurl = htmllink($params{page}, $params{destpage}, 
329                      "$archivebase/$nyear/" . sprintf("%02d", $nmonth),
330                      0,0," $nmonthname ");
331   }
332
333   # Start producing the month calendar
334   $calendar=<<EOF;
335 <table class="month-calendar">
336    <caption class="month-calendar-head">
337       $purl
338       $url
339       $nurl
340    </caption>
341    <tr>
342 EOF
343   # Suppose we want to start the week with day $week_start_day
344   # If $monthstart[6] == 1
345   my $week_start_day = $params{week_start_day};
346
347   my $start_day = 1 + (7 - $monthstart[6] + $week_start_day) % 7;
348   my %downame;
349   my %dowabbr;
350   for my $dow ($week_start_day..$week_start_day+6) {
351     my @day=localtime(timelocal(0,0,0,$start_day++,$month-1,$year-1900));
352     my $downame = POSIX::strftime("%A", @day);
353     my $dowabbr = POSIX::strftime("%a", @day);
354     $downame{$dow % 7}=$downame;
355     $dowabbr{$dow % 7}=$dowabbr;
356     $calendar.=
357       qq{     <th class="month-calendar-day-head $downame">$dowabbr</th>\n};
358   }
359
360   $calendar.=<<EOF;
361    </tr>
362 EOF
363
364   my $wday;
365   # we start with a week_start_day, and skip until we get to the first
366   for ($wday=$week_start_day; $wday != $monthstart[6]; $wday++, $wday %= 7) {
367     $calendar.=qq{   <tr>\n} if $wday == $week_start_day;
368     $calendar.=
369       qq{     <td class="month-calendar-day-noday $downame{$wday}">&nbsp;</td>\n};
370   }
371
372   # At this point, either the first is a week_start_day, in which case nothing
373   # has been printed, or else we are in the middle of a row.
374   for (my $day = 1; $day <= month_days(year => $year, month => $month); 
375        $day++, $wday++, $wday %= 7) {
376     # At tihs point, on a week_start_day, we close out a row, and start a new
377     # one -- unless it is week_start_day on the first, where we do not close a
378     # row -- since none was started.
379     if ($wday == $week_start_day) {
380       $calendar.=qq{   </tr>\n} unless $day == 1;
381       $calendar.=qq{   <tr>\n};
382     }
383     my $tag;
384     my $mtag = sprintf("%02d", $month);
385     if (defined $cache{$pagespec}{"$year/$mtag/$day"}) {
386       if ($day == $today)         { $tag='month-calendar-day-this-day'; }
387       else                        { $tag='month-calendar-day-link';     }
388       $calendar.=qq{     <td class="$tag $downame{$wday}">};
389       $calendar.=
390         htmllink($params{page}, $params{destpage}, 
391                  pagename($linkcache{"$year/$mtag/$day"}),
392                  0,0,"$day");
393       $calendar.=qq{</td>\n};
394     }
395     else {
396       if ($day == $today)         { $tag='month-calendar-day-this-day'; }
397       elsif ($day == $future_dom) { $tag='month-calendar-day-future';   }
398       else                        { $tag='month-calendar-day-nolink';   }
399       $calendar.=qq{     <td class="$tag $downame{$wday}">$day</td>\n};
400     }
401   }
402   # finish off the week
403   for (; $wday != $week_start_day; $wday++, $wday %= 7) {
404     $calendar.=qq{     <td class="month-calendar-day-noday $downame{$wday}">&nbsp;</td>\n};
405   }
406   $calendar.=<<EOF;
407    </tr>
408 </table>
409 EOF
410
411   return $calendar;
412 }
413
414 sub format_year (@) {
415   my %params=@_;
416   my $pagespec = $params{pages};
417   my $year     = $params{year};
418   my $month    = $params{month};
419   my $calendar="\n";
420   my $pyear  = $year - 1;
421   my $nyear  = $year + 1;
422   my $future_month = 0;
423   $future_month = $now[4]+1 if ($year == $now[5]+1900);
424
425   #  calculate URL's for previous and next years
426   my $archivebase = 'archives';
427   $archivebase = $config{archivebase} if defined $config{archivebase};
428   my ($url, $purl, $nurl)=("$year",'','');
429   if (exists $cache{$pagespec}{"$year"}) {
430     $url = htmllink($params{page}, $params{destpage}, 
431                     "$archivebase/$year",
432                     0,0,"$year");
433   }
434
435   if (exists $cache{$pagespec}{"$pyear"}) {
436     $purl = htmllink($params{page}, $params{destpage}, 
437                      "$archivebase/$pyear",
438                      0,0,"\&larr;");
439   }
440   if (exists $cache{$pagespec}{"$nyear"}) {
441     $nurl = htmllink($params{page}, $params{destpage}, 
442                      "$archivebase/$nyear",
443                      0,0,"\&rarr;");
444   }
445   # Start producing the year calendar
446   $calendar=<<EOF;
447 <table class="year-calendar">
448   <caption class="year-calendar-head">
449    $purl
450    $url
451    $nurl
452   </caption>
453   <tr>
454     <th class="year-calendar-subhead" colspan="$params{months_per_row}">Months</th>
455   </tr>
456 EOF
457
458   for ($month = 1; $month <= 12; $month++) {
459     my @day=localtime(timelocal(0,0,0,15,$month-1,$year-1900));
460     my $murl;
461     my $monthname = POSIX::strftime("%B", @day);
462     my $monthabbr = POSIX::strftime("%b", @day);
463     $calendar.=qq{   <tr>\n}  if ($month % $params{months_per_row} == 1);
464     my $tag;
465     my $mtag=sprintf("%02d", $month);
466     if ($month == $params{month}) {
467       if ($cache{$pagespec}{"$year/$mtag"})        {$tag = 'this_month_link'}
468       else                                         {$tag = 'this_month_nolink'}
469     }
470     elsif ($cache{$pagespec}{"$year/$mtag"})       {$tag = 'month_link'} 
471     elsif ($future_month && $month >=$future_month){$tag = 'month_future'} 
472     else                                           {$tag = 'month_nolink'}
473     if ($cache{$pagespec}{"$year/$mtag"}) {
474       $murl =  htmllink($params{page}, $params{destpage}, 
475                         "$archivebase/$year/$mtag",
476                         0,0,"$monthabbr");
477       $calendar.=qq{     <td class="$tag">};
478       $calendar.=$murl;
479       $calendar.=qq{</td>\n};
480     }
481     else {
482       $calendar.=qq{     <td class="$tag">$monthabbr</td>\n};
483     }
484     $calendar.=qq{   </tr>\n} if ($month % $params{months_per_row} == 0);
485   }
486   $calendar.=<<EOF;
487 </table>
488 EOF
489
490   return $calendar;
491 }
492
493
494 sub format (@) {
495   my %params=@_;
496   my $content=$params{content};
497   return $content unless exists $calpages{$params{page}};
498
499   # Restore parameters for each invocation
500   foreach my $index (keys %{$calpages{$params{page}}}) {
501     my $calendar="\n";
502     my %saved = %{$calpages{$params{page}}{$index}};
503     my $pagespec=$saved{pages};
504
505     if (! defined $cache{$pagespec}) {
506       for my $page (sort keys %pagesources) {
507         next unless pagespec_match($page,$pagespec);
508         my $mtime;
509         my $src = $pagesources{$page};
510         if (! exists $IkiWiki::pagectime{$page}) {
511           $mtime=(stat(srcfile($src)))[9];
512         }
513         else {
514           $mtime=$IkiWiki::pagectime{$page}
515         }
516         my @date  = localtime($mtime);
517         my $mday  = $date[3];
518         my $month = $date[4] + 1;
519         my $year  = $date[5] + 1900;
520         my $mtag  = sprintf("%02d", $month);
521         $linkcache{"$year/$mtag/$mday"} = "$src";
522         $cache{$pagespec}{"$year"}++;
523         $cache{$pagespec}{"$year/$mtag"}++;
524         $cache{$pagespec}{"$year/$mtag/$mday"}++;
525       }
526     }
527     # So, we have cached data for the current pagespec at this point
528     if ($saved{type} =~ /month/i) {
529       $calendar=format_month(%saved);
530     }
531     elsif ($saved{type} =~ /year/i) {
532       $calendar=format_year(%saved);
533     }
534     $content =~ s/(<div class=\"calendar\">\s*.?\s*$index\b)/<div class=\"calendar\">$calendar/ms;
535   }
536   return $content;
537 }
538
539
540
541 =head1 CAVEATS
542
543 In the month calendar, for days in which there is more than one
544 posting, the link created randomly selects one of them. Since there is
545 no easy way in B<IkiWiki> to automatically generate index pages, and
546 pregenerating daily index pages seems too much of an overhead, we have
547 to live with this.  All postings can still be viewed in the monthly or
548 annual indices, of course. This can be an issue for very prolific
549 scriveners.
550
551 =cut
552
553 =head1 BUGS
554
555 None Known so far.
556
557 =head1 BUGS
558
559 Since B<IkiWiki> eval's the configuration file, the values have to all
560 on a single physical line. This is the reason we need to use strings
561 and eval, instead of just passing in real anonymous sub references,
562 since the eval pass converts the coderef into a string of the form
563 "(CODE 12de345657)" which can't be dereferenced.
564
565 =cut
566
567 =head1 AUTHOR
568
569 Manoj Srivastava <srivasta@debian.org>
570
571 =head1 COPYRIGHT AND LICENSE
572
573 This script is a part of the Devotee package, and is 
574
575 Copyright (c) 2002 Manoj Srivastava <srivasta@debian.org>
576
577 This program is free software; you can redistribute it and/or modify
578 it under the terms of the GNU General Public License as published by
579 the Free Software Foundation; either version 2 of the License, or
580 (at your option) any later version.
581
582 This program is distributed in the hope that it will be useful,
583 but WITHOUT ANY WARRANTY; without even the implied warranty of
584 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
585 GNU General Public License for more details.
586
587 You should have received a copy of the GNU General Public License
588 along with this program; if not, write to the Free Software
589 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
590
591 =cut
592
593 1;
594
595 __END__
596 </pre>
597
598 ------
599
600 I've been looking over the calendar plugin. Some items:
601
602 * Why did you need to use a two-stage generation with a format hook?
603   That approach should only be needed if adding something to a page that
604   would be removed by the htmlscrubber, and as far as I can tell, the
605   calendars don't involve anything that would be a problem. It seems
606   that emitting the whole calendar in the preprocess hook would simplify
607   things and you'd not need to save state about calendars.
608
609 > I am scared of the html scrubber, and have never turned it on,
610 >        and did not look too deeply into what would be scrubbed out --ManojSrivastava
611 >> Unless you're using javascript, a few annoyances link <blink>, or inline
612 >> css, it's unlikly to object to any html you might write. The list of
613 >> allowed tags and attributes is easy to find near the top of the plugin.
614
615 > In case the option that gets the ctime of the pages from the
616 > SCM itself, %IkiWiki::pagectime  is not populated that early,
617 > is it? So I waited until the last possible moment to look at
618 > the time information.
619 >
620 >> Actually, since my big rewrite of the rendering path a few months ago,
621 >> ikiwiki scans and populates almost all page information before starting
622 >> to render any page. This includes %pagectime, and even %links. So you
623 >> shouldn't need to worry about running it late.
624
625 * The way that it defaults to the current year and current month
626   is a little bit tricky, because of course the wiki might not get
627   updated in a particular time period, and even if it is updated, only
628   iff a page containing a calendar is rebuilt for some other reason will
629   the calendar get updated, and change what year or month it shows. This
630   is essentially the same problem described in
631   [[todo/tagging_with_a_publication_date]],
632   although I don't think it will affect the calendar plugin very badly.
633   Still, the docs probably need to be clear about this.
634
635 > I use it on the sidebar; and the blog pages are almost always
636 > rebuilt, which is where the calendar is  looked at most often. Oh,
637 > and I also cheat, I have ikiwiki  --setup foo as a @daily cronjob, so
638 > my wiki is always built daily from scratch.
639
640 > I think it should be mentioned, yes.
641
642 * There seems to be something a bit wrong with the year-to-year
643   navigation in the calendar, based on the example in your blog. If I'm
644   on the page for 2006, there's an arrow pointing left which takes me to
645   2005. If I'm on 2005, the arrow points left, but goes to 2006, not
646   2004.
647
648 > I need to look into this.
649
650 * AIUI, the archivebase setting makes a directory rooted at the top of
651   the wiki, so you can have only one set of archives per wiki, in
652   /archives/. It would be good if it were possible to have multiple
653   archived for different blogs in the same wiki at multiple locations.
654   Though since the archives contain calendars, the archive location
655   can't just be relative to the page with the calendar. But perhaps
656   archivebase could be a configurable parameter that can be specified in
657   the directive for the calendar? (It would be fine to keep the global
658   location as a default.)
659
660 > OK, this is simple enough to implement. I'll do that (well,
661 > perhaps not before Xmas, I have a family dinner to cook) and send in
662 > another patch.
663
664
665 ----
666
667 And that's all I've heard so far. Hoping I didn't miss another patch?
668
669 --[[Joey]]
670
671 No, you did not.  But I am back to hacking on this, and I think I have discovered a major problem with my approach. One of the problems with the current plugin is that the goal of a calendar is to create a calendar, either a month or year based on,  that provides links to blogs for all the days in (for the month calendar), and all the months (in a year calendar) in which there have been blog postings. For the monthly calendar, it needs to know the  previous and next months where there is a posting, and  for the year calendar, it needs to know  which of the previous (next) years had entries.
672
673 Now, this means that it needs to know about at _all_ pages that meet the pagespec, and stash that information, before it begins generating the calandar in question, in order to calculate how to create the symlinks. And, of course, all pages that have calendars on them might need to change anytime a page that meets the pagespec is added; and again at midnight, when the current day changes.
674
675 keys %IkiWiki::pagectime  followed by pagespec_match would probably do the trick -- 
676
677         @Interesting = grep (pagespec_match($_,$pagespec), keys %IkiWiki::pagectime);
678
679 When is the %IkiWiki::pagectime hash created? Can it be used in the preprocess hook?
680
681 --[[ManojSrivastava]]