2 # Ikiwiki metadata plugin.
3 package IkiWiki::Plugin::meta;
18 hook(type => "needsbuild", id => "meta", call => \&needsbuild);
19 hook(type => "preprocess", id => "meta", call => \&preprocess, scan => 1);
20 hook(type => "pagetemplate", id => "meta", call => \&pagetemplate);
23 sub needsbuild (@) { #{{{
25 foreach my $page (keys %pagestate) {
26 if (exists $pagestate{$page}{meta}) {
27 if (grep { $_ eq $pagesources{$page} } @$needsbuild) {
28 # remove state, it will be re-added
29 # if the preprocessor directive is still
30 # there during the rebuild
31 delete $pagestate{$page}{meta};
38 if (IkiWiki::Plugin::htmlscrubber->can("sanitize")) {
39 return IkiWiki::Plugin::htmlscrubber::sanitize(content => shift);
46 sub htmlize ($$$) { #{{{
50 return IkiWiki::htmlize($page, pagetype($pagesources{$page}),
51 IkiWiki::linkify($page, $destpage,
52 IkiWiki::preprocess($page, $destpage, shift)));
55 sub preprocess (@) { #{{{
59 my $value=$params{$key};
61 my $page=$params{page};
63 my $destpage=$params{destpage};
64 delete $params{destpage};
65 delete $params{preview};
67 eval q{use HTML::Entities};
68 # Always decode, even if encoding later, since it might not be
70 $value=decode_entities($value);
72 # Metadata collection that needs to happen during the scan pass.
73 if ($key eq 'title') {
74 $title{$page}=HTML::Entities::encode_numeric($value);
76 elsif ($key eq 'license') {
77 push @{$meta{$page}}, '<link rel="license" href="#page_license" />';
78 $license{$page}=$value;
81 elsif ($key eq 'copyright') {
82 push @{$meta{$page}}, '<link rel="copyright" href="#page_copyright" />';
83 $copyright{$page}=$value;
86 elsif ($key eq 'link' && ! %params) {
88 push @{$links{$page}}, $value;
91 elsif ($key eq 'author') {
92 $author{$page}=$value;
95 elsif ($key eq 'authorurl') {
96 $authorurl{$page}=$value;
100 if (! defined wantarray) {
101 # avoid collecting duplicate data during scan pass
105 # Metadata collection that happens only during preprocessing pass.
106 if ($key eq 'date') {
107 eval q{use Date::Parse};
109 my $time = str2time($value);
110 $IkiWiki::pagectime{$page}=$time if defined $time;
113 elsif ($key eq 'permalink') {
114 $permalink{$page}=$value;
115 push @{$meta{$page}}, scrub('<link rel="bookmark" href="'.encode_entities($value).'" />');
117 elsif ($key eq 'stylesheet') {
118 my $rel=exists $params{rel} ? $params{rel} : "alternate stylesheet";
119 my $title=exists $params{title} ? $params{title} : $value;
120 # adding .css to the value prevents using any old web
121 # editable page as a stylesheet
122 my $stylesheet=bestlink($page, $value.".css");
123 if (! length $stylesheet) {
124 return "[[meta ".gettext("stylesheet not found")."]]";
126 push @{$meta{$page}}, '<link href="'.urlto($stylesheet, $page).
127 '" rel="'.encode_entities($rel).
128 '" title="'.encode_entities($title).
129 "\" type=\"text/css\" />";
131 elsif ($key eq 'openid') {
132 if (exists $params{server}) {
133 push @{$meta{$page}}, '<link href="'.encode_entities($params{server}).
134 '" rel="openid.server" />';
136 push @{$meta{$page}}, '<link href="'.encode_entities($value).
137 '" rel="openid.delegate" />';
139 elsif ($key eq 'redir') {
140 return "" if $page ne $destpage;
142 if ($value !~ /^\w+:\/\//) {
143 my ($redir_page, $redir_anchor) = split /\#/, $value;
145 add_depends($page, $redir_page);
146 my $link=bestlink($page, $redir_page);
147 if (! length $link) {
148 return "[[meta ".gettext("redir page not found")."]]";
151 $value=urlto($link, $page);
152 $value.='#'.$redir_anchor if defined $redir_anchor;
155 # redir cycle detection
156 $pagestate{$page}{meta}{redir}=$link;
159 while (exists $pagestate{$at}{meta}{redir}) {
161 return "[[meta ".gettext("redir cycle is not allowed")."]]";
164 $at=$pagestate{$at}{meta}{redir};
168 $value=encode_entities($value);
170 my $delay=int(exists $params{delay} ? $params{delay} : 0);
171 my $redir="<meta http-equiv=\"refresh\" content=\"$delay; URL=$value\">";
173 $redir=scrub($redir);
175 push @{$meta{$page}}, $redir;
177 elsif ($key eq 'link') {
179 push @{$meta{$page}}, scrub("<link href=\"".encode_entities($value)."\" ".
181 encode_entities($_)."=\"".encode_entities(decode_entities($params{$_}))."\""
187 push @{$meta{$page}}, scrub('<meta name="'.encode_entities($key).
188 '" content="'.encode_entities($value).'" />');
194 sub pagetemplate (@) { #{{{
196 my $page=$params{page};
197 my $destpage=$params{destpage};
198 my $template=$params{template};
200 if (exists $meta{$page} && $template->query(name => "meta")) {
201 # avoid duplicate meta lines
203 $template->param(meta => join("\n", grep { (! $seen{$_}) && ($seen{$_}=1) } @{$meta{$page}}));
205 if (exists $title{$page} && $template->query(name => "title")) {
206 $template->param(title => $title{$page});
207 $template->param(title_overridden => 1);
209 $template->param(permalink => $permalink{$page})
210 if exists $permalink{$page} && $template->query(name => "permalink");
211 $template->param(author => $author{$page})
212 if exists $author{$page} && $template->query(name => "author");
213 $template->param(authorurl => $authorurl{$page})
214 if exists $authorurl{$page} && $template->query(name => "authorurl");
216 if (exists $license{$page} && $template->query(name => "license") &&
217 ($page eq $destpage || ! exists $license{$destpage} ||
218 $license{$page} ne $license{$destpage})) {
219 $template->param(license => htmlize($page, $destpage, $license{$page}));
221 if (exists $copyright{$page} && $template->query(name => "copyright") &&
222 ($page eq $destpage || ! exists $copyright{$destpage} ||
223 $copyright{$page} ne $copyright{$destpage})) {
224 $template->param(copyright => htmlize($page, $destpage, $copyright{$page}));