summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/meta.pm
blob: 4aa545a93a67c6aa759a4aa67d7aa2ff65e6c66a (plain)
  1. #!/usr/bin/perl
  2. # Ikiwiki metadata plugin.
  3. package IkiWiki::Plugin::meta;
  4. use warnings;
  5. use strict;
  6. use IkiWiki 2.00;
  7. my %meta;
  8. my %title;
  9. my %permalink;
  10. my %author;
  11. my %authorurl;
  12. my %license;
  13. my %copyright;
  14. sub import { #{{{
  15. hook(type => "preprocess", id => "meta", call => \&preprocess, scan => 1);
  16. hook(type => "filter", id => "meta", call => \&filter);
  17. hook(type => "pagetemplate", id => "meta", call => \&pagetemplate);
  18. } # }}}
  19. sub filter (@) { #{{{
  20. my %params=@_;
  21. $meta{$params{page}}='';
  22. delete $pagestate{$params{page}}{meta}{redir};
  23. return $params{content};
  24. } # }}}
  25. sub scrub ($) { #{{{
  26. if (IkiWiki::Plugin::htmlscrubber->can("sanitize")) {
  27. return IkiWiki::Plugin::htmlscrubber::sanitize(content => shift);
  28. }
  29. else {
  30. return shift;
  31. }
  32. } #}}}
  33. sub preprocess (@) { #{{{
  34. if (! @_) {
  35. return "";
  36. }
  37. my %params=@_;
  38. my $key=shift;
  39. my $value=$params{$key};
  40. delete $params{$key};
  41. my $page=$params{page};
  42. delete $params{page};
  43. my $destpage=$params{destpage};
  44. delete $params{destpage};
  45. delete $params{preview};
  46. eval q{use HTML::Entities};
  47. # Always dencode, even if encoding later, since it might not be
  48. # fully encoded.
  49. $value=decode_entities($value);
  50. if ($key eq 'link') {
  51. if (%params) {
  52. $meta{$page}.=scrub("<link href=\"".encode_entities($value)."\" ".
  53. join(" ", map {
  54. encode_entities($_)."=\"".encode_entities(decode_entities($params{$_}))."\""
  55. } keys %params).
  56. " />\n");
  57. }
  58. else {
  59. # hidden WikiLink
  60. push @{$links{$page}}, $value;
  61. }
  62. }
  63. elsif ($key eq 'redir') {
  64. return "" if $destpage ne $page;
  65. my $safe=0;
  66. if ($value !~ /^\w+:\/\//) {
  67. add_depends($page, $value);
  68. my $link=bestlink($page, $value);
  69. if (! length $link) {
  70. return "[[meta ".gettext("redir page not found")."]]";
  71. }
  72. $value=urlto($link, $page);
  73. $safe=1;
  74. # redir cycle detection
  75. $pagestate{$page}{meta}{redir}=$link;
  76. my $at=$page;
  77. my %seen;
  78. while (exists $pagestate{$at}{meta}{redir}) {
  79. if ($seen{$at}) {
  80. return "[[meta ".gettext("redir cycle is not allowed")."]]";
  81. }
  82. $seen{$at}=1;
  83. $at=$pagestate{$at}{meta}{redir};
  84. }
  85. }
  86. else {
  87. $value=encode_entities($value);
  88. }
  89. my $delay=int(exists $params{delay} ? $params{delay} : 0);
  90. my $redir="<meta http-equiv=\"refresh\" content=\"$delay; URL=$value\">";
  91. if (! $safe) {
  92. $redir=scrub($redir);
  93. }
  94. $meta{$page}.=$redir;
  95. }
  96. elsif ($key eq 'title') {
  97. $title{$page}=HTML::Entities::encode_numeric($value);
  98. }
  99. elsif ($key eq 'permalink') {
  100. $permalink{$page}=$value;
  101. $meta{$page}.=scrub("<link rel=\"bookmark\" href=\"".encode_entities($value)."\" />\n");
  102. }
  103. elsif ($key eq 'date') {
  104. eval q{use Date::Parse};
  105. if (! $@) {
  106. my $time = str2time($value);
  107. $IkiWiki::pagectime{$page}=$time if defined $time;
  108. }
  109. }
  110. elsif ($key eq 'stylesheet') {
  111. my $rel=exists $params{rel} ? $params{rel} : "alternate stylesheet";
  112. my $title=exists $params{title} ? $params{title} : $value;
  113. # adding .css to the value prevents using any old web
  114. # editable page as a stylesheet
  115. my $stylesheet=bestlink($page, $value.".css");
  116. if (! length $stylesheet) {
  117. return "[[meta ".gettext("stylesheet not found")."]]";
  118. }
  119. $meta{$page}.='<link href="'.urlto($stylesheet, $page).
  120. '" rel="'.encode_entities($rel).
  121. '" title="'.encode_entities($title).
  122. "\" type=\"text/css\" />\n";
  123. }
  124. elsif ($key eq 'openid') {
  125. if (exists $params{server}) {
  126. $meta{$page}.='<link href="'.encode_entities($params{server}).
  127. "\" rel=\"openid.server\" />\n";
  128. }
  129. $meta{$page}.='<link href="'.encode_entities($value).
  130. "\" rel=\"openid.delegate\" />\n";
  131. }
  132. elsif ($key eq 'license') {
  133. $meta{$page}.="<link rel=\"license\" href=\"#page_license\" />\n";
  134. $license{$page}=$value;
  135. }
  136. elsif ($key eq 'copyright') {
  137. $meta{$page}.="<link rel=\"copyright\" href=\"#page_copyright\" />\n";
  138. $copyright{$page}=$value;
  139. }
  140. else {
  141. $meta{$page}.=scrub("<meta name=\"".encode_entities($key).
  142. "\" content=\"".encode_entities($value)."\" />\n");
  143. if ($key eq 'author') {
  144. $author{$page}=$value;
  145. }
  146. elsif ($key eq 'authorurl') {
  147. $authorurl{$page}=$value;
  148. }
  149. }
  150. return "";
  151. } # }}}
  152. sub pagetemplate (@) { #{{{
  153. my %params=@_;
  154. my $page=$params{page};
  155. my $destpage=$params{destpage};
  156. my $template=$params{template};
  157. $template->param(meta => $meta{$page})
  158. if exists $meta{$page} && $template->query(name => "meta");
  159. if (exists $title{$page} && $template->query(name => "title")) {
  160. $template->param(title => $title{$page});
  161. $template->param(title_overridden => 1);
  162. }
  163. $template->param(permalink => $permalink{$page})
  164. if exists $permalink{$page} && $template->query(name => "permalink");
  165. $template->param(author => $author{$page})
  166. if exists $author{$page} && $template->query(name => "author");
  167. $template->param(authorurl => $authorurl{$page})
  168. if exists $authorurl{$page} && $template->query(name => "authorurl");
  169. if ($page ne $destpage &&
  170. ((exists $license{$page} && ! exists $license{$destpage}) ||
  171. (exists $copyright{$page} && ! exists $copyright{$destpage}))) {
  172. # Force a scan of the destpage to get its copyright/license
  173. # info. If the info is declared after an inline, it will
  174. # otherwise not be available at this point.
  175. IkiWiki::scan($pagesources{$destpage});
  176. }
  177. if (exists $license{$page} && $template->query(name => "license") &&
  178. ($page eq $destpage || ! exists $license{$destpage} ||
  179. $license{$page} ne $license{$destpage})) {
  180. $template->param(license => IkiWiki::linkify($page, $destpage, $license{$page}));
  181. }
  182. if (exists $copyright{$page} && $template->query(name => "copyright") &&
  183. ($page eq $destpage || ! exists $copyright{$destpage} ||
  184. $copyright{$page} ne $copyright{$destpage})) {
  185. $template->param(copyright => IkiWiki::linkify($page, $destpage, $copyright{$page}));
  186. }
  187. } # }}}
  188. 1