* meta: Add pagespec functions to match against title, author, authorurl,

license, and copyright. This can be used to create custom RecentChanges.
* meta: To support the pagespec functions, metadata about pages has to be
  retained as pagestate.
* Fix encoding bug when pagestate values contained spaces.
master
Joey Hess 2008-01-29 17:16:51 -05:00
parent fbfbda614d
commit 64a8c828b8
10 changed files with 136 additions and 71 deletions

View File

@ -973,7 +973,7 @@ sub saveindex () { #{{{
if (exists $pagestate{$page}) {
foreach my $id (@hookids) {
foreach my $key (keys %{$pagestate{$page}{$id}}) {
$line.=' '.$id.'_'.encode_entities($key)."=".encode_entities($pagestate{$page}{$id}{$key});
$line.=' '.$id.'_'.encode_entities($key)."=".encode_entities($pagestate{$page}{$id}{$key}, " \t\n");
}
}
}

View File

@ -6,13 +6,7 @@ use warnings;
use strict;
use IkiWiki 2.00;
my %meta;
my %title;
my %permalink;
my %author;
my %authorurl;
my %license;
my %copyright;
my %metaheaders;
sub import { #{{{
hook(type => "needsbuild", id => "meta", call => \&needsbuild);
@ -71,16 +65,16 @@ sub preprocess (@) { #{{{
# Metadata collection that needs to happen during the scan pass.
if ($key eq 'title') {
$title{$page}=HTML::Entities::encode_numeric($value);
$pagestate{$page}{meta}{title}=HTML::Entities::encode_numeric($value);
}
elsif ($key eq 'license') {
push @{$meta{$page}}, '<link rel="license" href="#page_license" />';
$license{$page}=$value;
push @{$metaheaders{$page}}, '<link rel="license" href="#page_license" />';
$pagestate{$page}{meta}{license}=$value;
return "";
}
elsif ($key eq 'copyright') {
push @{$meta{$page}}, '<link rel="copyright" href="#page_copyright" />';
$copyright{$page}=$value;
push @{$metaheaders{$page}}, '<link rel="copyright" href="#page_copyright" />';
$pagestate{$page}{meta}{copyright}=$value;
return "";
}
elsif ($key eq 'link' && ! %params) {
@ -89,11 +83,11 @@ sub preprocess (@) { #{{{
return "";
}
elsif ($key eq 'author') {
$author{$page}=$value;
$pagestate{$page}{meta}{author}=$value;
# fallthorough
}
elsif ($key eq 'authorurl') {
$authorurl{$page}=$value;
$pagestate{$page}{meta}{authorurl}=$value;
# fallthrough
}
@ -111,8 +105,8 @@ sub preprocess (@) { #{{{
}
}
elsif ($key eq 'permalink') {
$permalink{$page}=$value;
push @{$meta{$page}}, scrub('<link rel="bookmark" href="'.encode_entities($value).'" />');
$pagestate{$page}{meta}{permalink}=$value;
push @{$metaheaders{$page}}, scrub('<link rel="bookmark" href="'.encode_entities($value).'" />');
}
elsif ($key eq 'stylesheet') {
my $rel=exists $params{rel} ? $params{rel} : "alternate stylesheet";
@ -123,17 +117,17 @@ sub preprocess (@) { #{{{
if (! length $stylesheet) {
return "[[meta ".gettext("stylesheet not found")."]]";
}
push @{$meta{$page}}, '<link href="'.urlto($stylesheet, $page).
push @{$metaheaders{$page}}, '<link href="'.urlto($stylesheet, $page).
'" rel="'.encode_entities($rel).
'" title="'.encode_entities($title).
"\" type=\"text/css\" />";
}
elsif ($key eq 'openid') {
if (exists $params{server}) {
push @{$meta{$page}}, '<link href="'.encode_entities($params{server}).
push @{$metaheaders{$page}}, '<link href="'.encode_entities($params{server}).
'" rel="openid.server" />';
}
push @{$meta{$page}}, '<link href="'.encode_entities($value).
push @{$metaheaders{$page}}, '<link href="'.encode_entities($value).
'" rel="openid.delegate" />';
}
elsif ($key eq 'redir') {
@ -172,11 +166,11 @@ sub preprocess (@) { #{{{
if (! $safe) {
$redir=scrub($redir);
}
push @{$meta{$page}}, $redir;
push @{$metaheaders{$page}}, $redir;
}
elsif ($key eq 'link') {
if (%params) {
push @{$meta{$page}}, scrub("<link href=\"".encode_entities($value)."\" ".
push @{$metaheaders{$page}}, scrub("<link href=\"".encode_entities($value)."\" ".
join(" ", map {
encode_entities($_)."=\"".encode_entities(decode_entities($params{$_}))."\""
} keys %params).
@ -184,7 +178,7 @@ sub preprocess (@) { #{{{
}
}
else {
push @{$meta{$page}}, scrub('<meta name="'.encode_entities($key).
push @{$metaheaders{$page}}, scrub('<meta name="'.encode_entities($key).
'" content="'.encode_entities($value).'" />');
}
@ -197,32 +191,80 @@ sub pagetemplate (@) { #{{{
my $destpage=$params{destpage};
my $template=$params{template};
if (exists $meta{$page} && $template->query(name => "meta")) {
if (exists $metaheaders{$page} && $template->query(name => "meta")) {
# avoid duplicate meta lines
my %seen;
$template->param(meta => join("\n", grep { (! $seen{$_}) && ($seen{$_}=1) } @{$meta{$page}}));
$template->param(meta => join("\n", grep { (! $seen{$_}) && ($seen{$_}=1) } @{$metaheaders{$page}}));
}
if (exists $title{$page} && $template->query(name => "title")) {
$template->param(title => $title{$page});
if (exists $pagestate{$page}{meta}{title} && $template->query(name => "title")) {
$template->param(title => $pagestate{$page}{meta}{title});
$template->param(title_overridden => 1);
}
$template->param(permalink => $permalink{$page})
if exists $permalink{$page} && $template->query(name => "permalink");
$template->param(author => $author{$page})
if exists $author{$page} && $template->query(name => "author");
$template->param(authorurl => $authorurl{$page})
if exists $authorurl{$page} && $template->query(name => "authorurl");
if (exists $license{$page} && $template->query(name => "license") &&
($page eq $destpage || ! exists $license{$destpage} ||
$license{$page} ne $license{$destpage})) {
$template->param(license => htmlize($page, $destpage, $license{$page}));
foreach my $field (qw{author authorurl permalink}) {
$template->param($field => $pagestate{$page}{meta}{$field})
if exists $pagestate{$page}{meta}{$field} && $template->query(name => $field);
}
if (exists $copyright{$page} && $template->query(name => "copyright") &&
($page eq $destpage || ! exists $copyright{$destpage} ||
$copyright{$page} ne $copyright{$destpage})) {
$template->param(copyright => htmlize($page, $destpage, $copyright{$page}));
foreach my $field (qw{license copyright}) {
if (exists $pagestate{$page}{meta}{$field} && $template->query(name => $field) &&
($page eq $destpage || ! exists $pagestate{$destpage}{meta}{$field} ||
$pagestate{$page}{meta}{$field} ne $pagestate{$destpage}{meta}{$field})) {
$template->param($field => htmlize($page, $destpage, $pagestate{$page}{meta}{$field}));
}
}
} # }}}
sub match { #{{{
my $field=shift;
my $page=shift;
# turn glob into a safe regexp
my $re=quotemeta(shift);
$re=~s/\\\*/.*/g;
$re=~s/\\\?/./g;
my $val;
if (exists $pagestate{$page}{meta}{$field}) {
$val=$pagestate{$page}{meta}{$field};
}
elsif ($field eq 'title') {
$val=pagetitle($page);
}
if (defined $val) {
if ($val=~/^$re$/i) {
return IkiWiki::SuccessReason->new("$re matches $field of $page");
}
else {
return IkiWiki::FailReason->new("$re does not match $field of $page");
}
}
else {
return IkiWiki::FailReason->new("$page does not have a $field");
}
} #}}}
package IkiWiki::PageSpec;
sub match_title ($$;@) { #{{{
IkiWiki::Plugin::meta::match("title", @_);
} #}}}
sub match_author ($$;@) { #{{{
IkiWiki::Plugin::meta::match("author", @_);
} #}}}
sub match_authorurl ($$;@) { #{{{
IkiWiki::Plugin::meta::match("authorurl", @_);
} #}}}
sub match_license ($$;@) { #{{{
IkiWiki::Plugin::meta::match("license", @_);
} #}}}
sub match_copyright ($$;@) { #{{{
IkiWiki::Plugin::meta::match("copyright", @_);
} #}}}
1

View File

@ -377,6 +377,7 @@ sub refresh () { #{{{
$pagemtime{$page}=$mtime;
if (isinternal($page)) {
push @internal, $file;
scan($file);
}
else {
push @needsbuild, $file;

5
debian/changelog vendored
View File

@ -31,6 +31,11 @@ ikiwiki (2.21) UNRELEASED; urgency=low
the svnrepo and notify settings, though both will be ignored if left in
setup files. Also gone with it is the "user()" pagespec.
* Add refresh hook.
* meta: Add pagespec functions to match against title, author, authorurl,
license, and copyright. This can be used to create custom RecentChanges.
* meta: To support the pagespec functions, metadata about pages has to be
retained as pagestate.
* Fix encoding bug when pagestate values contained spaces.
-- Joey Hess <joeyh@debian.org> Fri, 11 Jan 2008 15:09:37 -0500

View File

@ -33,10 +33,13 @@ functions:
was created
* "`created_before(page)`" - match only pages created before the given page
was created
* "`glob(foo)`" - match pages that match the given glob `foo`. Just writing
* "`glob(someglob)`" - match pages that match the given glob. Just writing
the glob by itself is actually a shorthand for this function.
* "`internal(foo)`" - like `glob()`, but matches even internal-use
* "`internal(glob)`" - like `glob()`, but matches even internal-use
pages that globs do not usually match.
* "`title(glob)`", "`author(glob)`", "`authorurl(glob)`",
"`license(glob)`", "`copyright(glob)`" - match pages that have the given
metadata, matching the specified glob.
For example, to match all pages in a blog that link to the page about music
and were written in 2005:

View File

@ -10,3 +10,17 @@ plugin, but you can use it elsewhere too if you like. It's used like this:
\[[inline pages="internal(recentchanges/change_*)"
template=recentchanges show=0]]
Here's an example of how to show only changes to "bugs/*".
This matches against the title of the change, which includes a list of
modified pages.
\[[inline pages="internal(recentchanges/change_*) and title(*bugs/*)"
template=recentchanges show=0]]
Here's an example of how to show only changes that Joey didn't make.
(Joey commits sometimes as user `joey`, and sometimes via openid.)
\[[inline pages="internal(recentchanges/change_*) and
!author(joey) and !author(http://joey.kitenet.net*)"
template=recentchanges show=0]]

View File

@ -533,18 +533,16 @@ rendered to.
## Internal use pages
Sometimes it's useful to put pages in the wiki without having them be
rendered to individual html files. Such internal use pages are collected
together to form the RecentChanges page, for example.
Sometimes it's useful to put pages in the wiki without the overhead of
having them be rendered to individual html files. Such internal use pages
are collected together to form the RecentChanges page, for example.
To make an internal use page, register a filename extension that starts
with "_". Internal use pages cannot be edited with the web interface, are
not scanned for wikilinks (though wikilinks and preprocessor directives can
appear on them, this is rarely a good idea and should be done with caution),
and are not matched by regular PageSpecs glob patterns, but instead only by a
special `internal()` [[ikiwiki/PageSpec]].
Ikiwiki is optimised to handle lots of internal use pages, very quickly.
with "_". Internal use pages cannot be edited with the web interface,
generally shouldn't contain wikilinks or preprocessor directives (use
either on them with extreme caution), and are not matched by regular
PageSpecs glob patterns, but instead only by a special `internal()`
[[ikiwiki/PageSpec]].
## RCS plugins

View File

@ -15,6 +15,8 @@ use IkiWiki::Setup::Standard {
syslog => 0,
userdir => "users",
usedirs => 0,
rcs => "git",
rss => 1,
url => "http://ikiwiki.info/",
add_plugins => [qw{goodstuff version haiku polygen fortune}],
disable_plugins => [qw{recentchanges}],
}

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-01-29 15:46-0500\n"
"POT-Creation-Date: 2008-01-29 17:15-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -47,8 +47,8 @@ msgstr ""
#: ../IkiWiki/CGI.pm:382 ../IkiWiki/Plugin/brokenlinks.pm:24
#: ../IkiWiki/Plugin/inline.pm:241 ../IkiWiki/Plugin/opendiscussion.pm:17
#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:100
#: ../IkiWiki/Render.pm:180
#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:101
#: ../IkiWiki/Render.pm:181
msgid "discussion"
msgstr ""
@ -218,7 +218,7 @@ msgstr ""
msgid "nonexistant template %s"
msgstr ""
#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:104
#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:105
msgid "Discussion"
msgstr ""
@ -240,15 +240,15 @@ msgstr ""
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
#: ../IkiWiki/Plugin/meta.pm:124
#: ../IkiWiki/Plugin/meta.pm:118
msgid "stylesheet not found"
msgstr ""
#: ../IkiWiki/Plugin/meta.pm:148
#: ../IkiWiki/Plugin/meta.pm:142
msgid "redir page not found"
msgstr ""
#: ../IkiWiki/Plugin/meta.pm:161
#: ../IkiWiki/Plugin/meta.pm:155
msgid "redir cycle is not allowed"
msgstr ""
@ -503,47 +503,47 @@ msgstr ""
msgid "getctime not implemented"
msgstr ""
#: ../IkiWiki/Render.pm:280 ../IkiWiki/Render.pm:301
#: ../IkiWiki/Render.pm:281 ../IkiWiki/Render.pm:302
#, perl-format
msgid "skipping bad filename %s"
msgstr ""
#: ../IkiWiki/Render.pm:350
#: ../IkiWiki/Render.pm:351
#, perl-format
msgid "removing old page %s"
msgstr ""
#: ../IkiWiki/Render.pm:389
#: ../IkiWiki/Render.pm:391
#, perl-format
msgid "scanning %s"
msgstr ""
#: ../IkiWiki/Render.pm:394
#: ../IkiWiki/Render.pm:396
#, perl-format
msgid "rendering %s"
msgstr ""
#: ../IkiWiki/Render.pm:415
#: ../IkiWiki/Render.pm:417
#, perl-format
msgid "rendering %s, which links to %s"
msgstr ""
#: ../IkiWiki/Render.pm:436
#: ../IkiWiki/Render.pm:438
#, perl-format
msgid "rendering %s, which depends on %s"
msgstr ""
#: ../IkiWiki/Render.pm:475
#: ../IkiWiki/Render.pm:477
#, perl-format
msgid "rendering %s, to update its backlinks"
msgstr ""
#: ../IkiWiki/Render.pm:487
#: ../IkiWiki/Render.pm:489
#, perl-format
msgid "removing %s, no longer rendered by %s"
msgstr ""
#: ../IkiWiki/Render.pm:513
#: ../IkiWiki/Render.pm:515
#, perl-format
msgid "ikiwiki: cannot render %s"
msgstr ""

View File

@ -2,7 +2,7 @@
<TMPL_IF AUTHORURL>
[[meta authorurl="""<TMPL_VAR AUTHORURL>"""]]
</TMPL_IF>
[[meta title="""update of <TMPL_VAR WIKINAME>'s <TMPL_LOOP NAME="PAGES"> <TMPL_VAR PAGE></TMPL_LOOP>"""]]
[[meta title="""update of <TMPL_VAR WIKINAME>'s<TMPL_LOOP NAME="PAGES"> <TMPL_VAR PAGE></TMPL_LOOP>"""]]
<div class="metadata">
<span class="desc"><br />Changed pages:</span>
<span class="pagelinks">