aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--IkiWiki/Plugin/calendar.pm270
-rw-r--r--debian/changelog6
-rw-r--r--doc/ikiwiki-calendar.mdwn7
-rw-r--r--doc/ikiwiki/directive/calendar.mdwn21
-rw-r--r--doc/plugins/calendar.mdwn23
-rw-r--r--doc/todo/calendar_autocreate.mdwn2
-rwxr-xr-xt/img.t3
7 files changed, 298 insertions, 34 deletions
diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm
index 4df7070ac..23246757b 100644
--- a/IkiWiki/Plugin/calendar.pm
+++ b/IkiWiki/Plugin/calendar.pm
@@ -25,11 +25,17 @@ use Time::Local;
my $time=time;
my @now=localtime($time);
+my %changed;
sub import {
+ hook(type => "checkconfig", id => "calendar", call => \&checkconfig);
hook(type => "getsetup", id => "calendar", call => \&getsetup);
hook(type => "needsbuild", id => "calendar", call => \&needsbuild);
hook(type => "preprocess", id => "calendar", call => \&preprocess);
+ hook(type => "scan", id => "calendar", call => \&scan);
+ hook(type => "build_affected", id => "calendar", call => \&build_affected);
+
+ IkiWiki::loadplugin("transient");
}
sub getsetup () {
@@ -49,11 +55,41 @@ sub getsetup () {
archive_pagespec => {
type => "pagespec",
example => "page(posts/*) and !*/Discussion",
- description => "PageSpec of pages to include in the archives; used by ikiwiki-calendar command",
+ description => "PageSpec of pages to include in the archives, if option `calendar_autocreate` is true.",
link => 'ikiwiki/PageSpec',
safe => 1,
rebuild => 0,
},
+ calendar_autocreate => {
+ type => "boolean",
+ example => 1,
+ description => "autocreate new calendar pages?",
+ safe => 1,
+ rebuild => undef,
+ },
+ calendar_fill_gaps => {
+ type => "boolean",
+ example => 1,
+ default => 1,
+ description => "if set, when building calendar pages, also build pages of year and month when no pages were published (building empty calendars).",
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub checkconfig () {
+ if (! defined $config{calendar_autocreate}) {
+ $config{calendar_autocreate} = defined $config{archivebase};
+ }
+ if (! defined $config{archive_pagespec}) {
+ $config{archive_pagespec} = '*';
+ }
+ if (! defined $config{archivebase}) {
+ $config{archivebase} = 'archives';
+ }
+ if (! defined $config{calendar_fill_gaps}) {
+ $config{calendar_fill_gaps} = 1;
+ }
}
sub is_leap_year (@) {
@@ -70,6 +106,184 @@ sub month_days {
return $days_in_month;
}
+sub build_affected {
+ my %affected;
+ my ($ayear, $amonth, $valid);
+
+ foreach my $year (keys %changed) {
+ ($ayear, $valid) = nextyear($year, $config{archivebase});
+ $affected{calendarlink($ayear)} = sprintf(gettext("building calendar for %s, its previous or next year has changed"), $ayear) if ($valid);
+ ($ayear, $valid) = previousyear($year, $config{archivebase});
+ $affected{calendarlink($ayear)} = sprintf(gettext("building calendar for %s, its previous or next year has changed"), $ayear) if ($valid);
+ foreach my $month (keys $changed{$year}) {
+ ($ayear, $amonth, $valid) = nextmonth($year, $month, $config{archivebase});
+ $affected{calendarlink($ayear, sprintf("%02d", $amonth))} = sprintf(gettext("building calendar for %s/%s, its previous or next month has changed"), $amonth, $ayear) if ($valid);
+ ($ayear, $amonth, $valid) = previousmonth($year, $month, $config{archivebase});
+ $affected{calendarlink($ayear, sprintf("%02d", $amonth))} = sprintf(gettext("building calendar for %s/%s, its previous or next month has changed"), $amonth, $ayear) if ($valid);
+ }
+ }
+
+ return %affected;
+}
+
+sub autocreate {
+ my ($page, $pagefile, $year, $month) = @_;
+ my $message=sprintf(gettext("creating calendar page %s"), $page);
+ debug($message);
+
+ my $template;
+ if (defined $month) {
+ $template=template("calendarmonth.tmpl");
+ } else {
+ $template=template("calendaryear.tmpl");
+ }
+ $template->param(year => $year);
+ $template->param(month => $month) if defined $month;
+ $template->param(pagespec => $config{archive_pagespec});
+
+ my $dir = $IkiWiki::Plugin::transient::transientdir;
+
+ writefile($pagefile, $dir, $template->output);
+}
+
+sub calendarlink($;$) {
+ my ($year, $month) = @_;
+ if (defined $month) {
+ return $config{archivebase} . "/" . $year . "/" . $month;
+ } else {
+ return $config{archivebase} . "/" . $year;
+ }
+}
+
+sub gencalendarmonth{
+ my $year = shift;
+ my $month = sprintf("%02d", shift);
+
+ my $page = calendarlink($year, $month);
+ my $pagefile = newpagefile($page, $config{default_pageext});
+ add_autofile(
+ $pagefile, "calendar",
+ sub {return autocreate($page, $pagefile, $year, $month);}
+ );
+}
+
+sub gencalendaryear {
+ my $year = shift;
+ my %params = @_;
+
+ # Building year page
+ my $page = calendarlink($year);
+ my $pagefile = newpagefile($page, $config{default_pageext});
+ add_autofile(
+ $pagefile, "calendar",
+ sub {return autocreate($page, $pagefile, $year);}
+ );
+
+ if (not exists $wikistate{calendar}{minyear}) {
+ $wikistate{calendar}{minyear} = $year;
+ }
+ if (not exists $wikistate{calendar}{maxyear}) {
+ $wikistate{calendar}{maxyear} = $year;
+ }
+
+ if ($config{calendar_fill_gaps}) {
+ # Building month pages
+ foreach my $month (1 .. 12) {
+ gencalendarmonth($year, $month);
+ }
+
+ # Filling potential gaps in years (e.g. calendar goes from 2010 to 2014,
+ # and we just added year 2005. We have to add years 2006 to 2009).
+ return if $params{norecurse};
+ if ($wikistate{calendar}{minyear} > $year) {
+ foreach my $other ($year + 1 .. $wikistate{calendar}{minyear} - 1) {
+ gencalendaryear($other, norecurse => 1);
+ }
+ $wikistate{calendar}{minyear} = $year;
+ }
+ if ($wikistate{calendar}{maxyear} < $year) {
+ foreach my $other ($wikistate{calendar}{maxyear} + 1 .. $year - 1) {
+ gencalendaryear($other, norecurse => 1);
+ }
+ $wikistate{calendar}{maxyear} = $year;
+ }
+ }
+ if ($year < $wikistate{calendar}{minyear}) {
+ $wikistate{calendar}{minyear} = $year;
+ }
+ if ($year > $wikistate{calendar}{maxyear}) {
+ $wikistate{calendar}{maxyear} = $year;
+ }
+}
+
+sub previousmonth($$$) {
+ my $year = shift;
+ my $month = shift;
+ my $archivebase = shift;
+
+ if (not exists $wikistate{calendar}{minyear}) {
+ $wikistate{calendar}{minyear} = $year;
+ }
+
+ my $pmonth = $month;
+ my $pyear = $year;
+ while ((not exists $pagesources{"$archivebase/$pyear/" . sprintf("%02d", $pmonth)}) or ($pmonth == $month and $pyear == $year)) {
+ $pmonth -= 1;
+ if ($pmonth == 0) {
+ $pyear -= 1;
+ $pmonth = 12;
+ return ($pyear, $pmonth, 0) unless $pyear >= $wikistate{calendar}{minyear};
+ }
+ }
+ return ($pyear, $pmonth, 1);
+}
+
+sub nextmonth($$$) {
+ my $year = shift;
+ my $month = shift;
+ my $archivebase = shift;
+
+ if (not exists $wikistate{calendar}{maxyear}) {
+ $wikistate{calendar}{maxyear} = $year;
+ }
+
+ my $nmonth = $month;
+ my $nyear = $year;
+ while ((not exists $pagesources{"$archivebase/$nyear/" . sprintf("%02d", $nmonth)}) or ($nmonth == $month and $nyear == $year)) {
+ $nmonth += 1;
+ if ($nmonth == 13) {
+ $nyear += 1;
+ $nmonth = 1;
+ return ($nyear, $nmonth, 0) unless $nyear <= $wikistate{calendar}{maxyear};
+ }
+ }
+ return ($nyear, $nmonth, 1);
+}
+
+sub previousyear($$) {
+ my $year = shift;
+ my $archivebase = shift;
+
+ my $pyear = $year - 1;
+ while (not exists $pagesources{"$archivebase/$pyear"}) {
+ $pyear -= 1;
+ return ($pyear, 0) unless ($pyear >= $wikistate{calendar}{minyear});
+ }
+ return ($pyear, 1);
+}
+
+sub nextyear($$) {
+ my $year = shift;
+ my $archivebase = shift;
+
+ my $nyear = $year + 1;
+ while (not exists $pagesources{"$archivebase/$nyear"}) {
+ $nyear += 1;
+ return ($nyear, 0) unless ($nyear <= $wikistate{calendar}{maxyear});
+ }
+ return ($nyear, 1);
+}
+
sub format_month (@) {
my %params=@_;
@@ -92,20 +306,12 @@ sub format_month (@) {
push(@{$linkcache{"$year/$mtag/$mday"}}, $p);
}
- my $pmonth = $params{month} - 1;
- my $nmonth = $params{month} + 1;
- my $pyear = $params{year};
- my $nyear = $params{year};
-
- # Adjust for January and December
- if ($params{month} == 1) {
- $pmonth = 12;
- $pyear--;
- }
- if ($params{month} == 12) {
- $nmonth = 1;
- $nyear++;
- }
+ my $archivebase = 'archives';
+ $archivebase = $config{archivebase} if defined $config{archivebase};
+ $archivebase = $params{archivebase} if defined $params{archivebase};
+
+ my ($pyear, $pmonth, $pvalid) = previousmonth($params{year}, $params{month}, $archivebase);
+ my ($nyear, $nmonth, $nvalid) = nextmonth($params{year}, $params{month}, $archivebase);
# Add padding.
$pmonth=sprintf("%02d", $pmonth);
@@ -129,10 +335,6 @@ sub format_month (@) {
my $pmonthname=strftime_utf8("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900)));
my $nmonthname=strftime_utf8("%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 $params{year}",'','');
if (exists $pagesources{"$archivebase/$params{year}/$params{month}"}) {
@@ -274,7 +476,7 @@ EOF
sub format_year (@) {
my %params=@_;
-
+
my @post_months;
foreach my $p (pagespec_match_list($params{page},
"creation_year($params{year}) and ($params{pages})",
@@ -290,18 +492,18 @@ sub format_year (@) {
}
my $calendar="\n";
+
+ my $archivebase = 'archives';
+ $archivebase = $config{archivebase} if defined $config{archivebase};
+ $archivebase = $params{archivebase} if defined $params{archivebase};
- my $pyear = $params{year} - 1;
- my $nyear = $params{year} + 1;
+ my ($pyear, $pvalid) = previousyear($params{year}, $archivebase);
+ my ($nyear, $nvalid) = nextyear($params{year}, $archivebase);
my $thisyear = $now[5]+1900;
my $future_month = 0;
$future_month = $now[4]+1 if $params{year} == $thisyear;
- 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)=("$params{year}",'','');
if (exists $pagesources{"$archivebase/$params{year}"}) {
@@ -431,6 +633,7 @@ sub preprocess (@) {
}
$params{month} = sprintf("%02d", $params{month});
+ $changed{$params{year}}{$params{month}} = 1;
if ($params{type} eq 'month' && $params{year} == $thisyear
&& $params{month} == $thismonth) {
@@ -508,7 +711,22 @@ sub needsbuild (@) {
}
}
}
+
return $needsbuild;
}
+sub scan (@) {
+ my %params=@_;
+ my $page=$params{page};
+
+ return unless $config{calendar_autocreate};
+
+ # Check if year pages have to be generated
+ if (pagespec_match($page, $config{archive_pagespec})) {
+ my @ctime = localtime($IkiWiki::pagectime{$page});
+ gencalendaryear($ctime[5]+1900);
+ gencalendarmonth($ctime[5]+1900, $ctime[4]+1);
+ }
+}
+
1
diff --git a/debian/changelog b/debian/changelog
index 014066e32..1cf3dce8b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,6 @@
ikiwiki (3.20141017) UNRELEASED; urgency=medium
+ [ Joey Hess ]
* Added ikiwiki-comment program.
* Add missing build-depends on libcgi-formbuilder-perl, needed for
t/relativity.t
@@ -7,6 +8,11 @@ ikiwiki (3.20141017) UNRELEASED; urgency=medium
* Set Debian package maintainer to Simon McVittie as I'm retiring from
Debian.
+ [ Simon McVittie ]
+ * calendar: add calendar_autocreate option, with which "ikiwiki --refresh"
+ can mostly supersede the ikiwiki-calendar command.
+ Thanks, Louis Paternault
+
-- Joey Hess <joeyh@debian.org> Mon, 20 Oct 2014 12:04:49 -0400
ikiwiki (3.20141016) unstable; urgency=medium
diff --git a/doc/ikiwiki-calendar.mdwn b/doc/ikiwiki-calendar.mdwn
index d311a1859..fd3244694 100644
--- a/doc/ikiwiki-calendar.mdwn
+++ b/doc/ikiwiki-calendar.mdwn
@@ -46,6 +46,13 @@ An example crontab:
This command uses two [[templates]] to generate
the pages, `calendarmonth.tmpl` and `calendaryear.tmpl`.
+# [[plugins/calendar]] setup option
+
+Most of the goals of this command can be replaced by setting up
+`calendar_autocreate` setup option (of plugin [[plugins/calendar]]), and
+running `ikiwiki -setup you.setup`. The only thing that `ikiwiki-calendar` can
+do and that `ikiwiki` cannot is forcing page generation (using `-f` switch).
+
# AUTHOR
Joey Hess <joey@ikiwiki.info>
diff --git a/doc/ikiwiki/directive/calendar.mdwn b/doc/ikiwiki/directive/calendar.mdwn
index cb40f884e..4c2b99ccb 100644
--- a/doc/ikiwiki/directive/calendar.mdwn
+++ b/doc/ikiwiki/directive/calendar.mdwn
@@ -25,14 +25,23 @@ in the sidebar, you'll also need to create these archive pages. They
typically use this directive to display a calendar, and also use [[inline]]
to display or list pages created in the given time frame.
-The `ikiwiki-calendar` command can be used to automatically generate the
-archive pages. It also refreshes the wiki, updating the calendars to
-highlight the current day. This command is typically run at midnight from
-cron.
+## Generating archive pages
+
+If [[!iki plugins/calendar desc=option]] `calendar_autocreate` is not set, the
+[[!iki ikiwiki-calendar]] command can be used to automatically generate the archive
+pages. It also refreshes the wiki, updating the calendars to highlight the
+current day. This command is typically run at midnight from cron.
An example crontab:
- 0 0 * * * ikiwiki-calendar ~/ikiwiki.setup "posts/* and !*/Discussion"
+ 0 0 * * * ikiwiki-calendar ~/ikiwiki.setup "posts/* and !*/Discussion"
+
+
+With [[!iki plugins/calendar desc="setup option"]] `calendar_autocreate`,
+all this work is done by `ikiwiki` itself. Thus, the crontab command can be
+replaced by:
+
+ 0 0 * * * ikiwiki --setup ~/ikiwiki.setup --refresh
## usage
@@ -45,7 +54,7 @@ An example crontab:
for the whole wiki by setting `archivebase` in ikiwiki's setup file.
Calendars link to pages under here, with names like "2010/04" and
"2010". These pages can be automatically created using the
- `ikiwiki-calendar` program.
+ `calendar_autocreate` [[!iki plugins/calendar desc="setup option"]].
* `year` - The year for which the calendar is requested. Defaults to the
current year. Can also use -1 to refer to last year, and so on.
* `month` - The numeric month for which the calendar is requested, in the
diff --git a/doc/plugins/calendar.mdwn b/doc/plugins/calendar.mdwn
index 76e718a3b..8d18ed081 100644
--- a/doc/plugins/calendar.mdwn
+++ b/doc/plugins/calendar.mdwn
@@ -5,7 +5,28 @@ This plugin provides a [[ikiwiki/directive/calendar]] [[ikiwiki/directive]].
The directive displays a calendar, similar to the typical calendars shown on
some blogs.
-The [[ikiwiki-calendar]] command is used to keep the calendar up-to-date.
+The [[ikiwiki-calendar]] command is used to force generating year and month
+pages from templates (overriding the existing ones).
+
+## Setup options
+
+* `archivebase` - Default value for [[ikiwiki/directive/calendar]] directive
+ option of the same name.
+* `archive_pagespec` - [[ikiwiki/PageSpec]] of pages to include in the
+ archives, if option `calendar_autocreate` is on. It defaults to `*`.
+* `calendar_autocreate` - Control whether new archive pages are created as
+ needed. It defaults to being done only if option `archivebase` is set.
+* `calendar_fill_gaps` - If set (and `calendar_autocreate` is set as well),
+ build calendar pages of empty years and months (but does not build pages older
+ than the older page, and younger than the younger page of the pagespec). If
+ not, those empty calendar pages will be skipped. *Please note:*
+ * The archive pages will not be automatically updated if this option changes.
+ It is up to the user to delete relevant pages, and rebuild the wiki.
+ * When `calendar_fill_gaps` is set, and a post is deleted, making the
+ corresponding year/month empty, the corresponding page is left, and shows
+ an empty calendar. This is on purpose, not to break any external link
+ pointing to this particular page. If you do not like it, delete the
+ relevant pages, and rebuild the wiki.
## CSS
diff --git a/doc/todo/calendar_autocreate.mdwn b/doc/todo/calendar_autocreate.mdwn
index 371079d68..c1f9c454e 100644
--- a/doc/todo/calendar_autocreate.mdwn
+++ b/doc/todo/calendar_autocreate.mdwn
@@ -1,5 +1,7 @@
Here is a patch that makes [[ikiwiki-calendar]] almost useless.
+> [[merged|done]], thanks! --[[smcv]]
+
It adds some options, the main one being `calendar_autocreate`, which is
similar to the `tag_autocreate` option of the [[tag|plugins/tag]]: it create
archive pages when needed.
diff --git a/t/img.t b/t/img.t
index 8c10d9b74..2ea3abb24 100755
--- a/t/img.t
+++ b/t/img.t
@@ -26,7 +26,8 @@ ok(! system("rm -rf t/tmp; mkdir -p t/tmp/in"));
ok(! system("cp t/img/redsquare.png t/tmp/in/redsquare.png"));
if ($SVGS_WORK) {
- writefile("emptysquare.svg", "t/tmp/in", '<svg width="30" height="30"/>');
+ writefile("emptysquare.svg", "t/tmp/in",
+ '<svg width="30" height="30"><rect x="0" y="0" width="30" height="30" fill="blue"/></svg>');
}
# using different image sizes for different pages, so the pagenumber selection can be tested easily