Add templatebody plugin and directive, and enable it by default
Also add a regression test for templatebody.master
parent
cbb3218db7
commit
7672014582
|
@ -152,7 +152,8 @@ sub getsetup () {
|
|||
type => "internal",
|
||||
default => [qw{mdwn link inline meta htmlscrubber passwordauth
|
||||
openid signinedit lockedit conditional
|
||||
recentchanges parentlinks editpage}],
|
||||
recentchanges parentlinks editpage
|
||||
templatebody}],
|
||||
description => "plugins to enable by default",
|
||||
safe => 0,
|
||||
rebuild => 1,
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/perl
|
||||
# Define self-documenting templates as wiki pages without HTML::Template
|
||||
# markup leaking into IkiWiki's output.
|
||||
# Copyright © 2013-2014 Simon McVittie. GPL-2+, see debian/copyright
|
||||
package IkiWiki::Plugin::templatebody;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
use IkiWiki 3.00;
|
||||
use Encode;
|
||||
|
||||
sub import {
|
||||
hook(type => "getsetup", id => "templatebody", call => \&getsetup);
|
||||
hook(type => "preprocess", id => "templatebody", call => \&preprocess,
|
||||
scan => 1);
|
||||
hook(type => "readtemplate", id => "templatebody",
|
||||
call => \&readtemplate);
|
||||
}
|
||||
|
||||
sub getsetup () {
|
||||
return
|
||||
plugin => {
|
||||
safe => 1,
|
||||
rebuild => undef,
|
||||
section => "core",
|
||||
},
|
||||
}
|
||||
|
||||
# This doesn't persist between runs: we're going to read and scan the
|
||||
# template file regardless, so there's no point in saving it to the index.
|
||||
# Example contents:
|
||||
# ("templates/note" => "<div class=\"notebox\">\n<TMPL_VAR text>\n</div>")
|
||||
my %templates;
|
||||
|
||||
sub preprocess (@) {
|
||||
my %params=@_;
|
||||
|
||||
# [[!templatebody "<div>hello</div>"]] results in
|
||||
# preprocess("<div>hello</div>" => undef, page => ...)
|
||||
my $content = $_[0];
|
||||
if (length $_[1]) {
|
||||
error(gettext("first parameter must be the content"));
|
||||
}
|
||||
|
||||
$templates{$params{page}} = $content;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
sub readtemplate {
|
||||
my %params = @_;
|
||||
my $tpage = $params{page};
|
||||
my $content = $params{content};
|
||||
my $filename = $params{filename};
|
||||
|
||||
# pass-through if it's a .tmpl attachment or otherwise unsuitable
|
||||
return $content unless defined $tpage;
|
||||
return $content if $tpage =~ /\.tmpl$/;
|
||||
my $src = $pagesources{$tpage};
|
||||
return $content unless defined $src;
|
||||
return $content unless defined pagetype($src);
|
||||
|
||||
# We might be using the template for [[!template]], which has to run
|
||||
# during the scan stage so that templates can include scannable
|
||||
# directives which are expanded in the resulting page. Calls to
|
||||
# IkiWiki::scan are in arbitrary order, so the template might
|
||||
# not have been scanned yet. Make sure.
|
||||
require IkiWiki::Render;
|
||||
IkiWiki::scan($src);
|
||||
|
||||
# Having scanned it, we know whether it had a [[!templatebody]].
|
||||
if (exists $templates{$tpage}) {
|
||||
return $templates{$tpage};
|
||||
}
|
||||
|
||||
# If not, return the whole thing. (Eventually, after implementing
|
||||
# a transition, this can become an error.)
|
||||
return $content;
|
||||
}
|
||||
|
||||
1
|
|
@ -18,17 +18,25 @@ the directive displaying a note about the template being registered, add
|
|||
"silent=yes".
|
||||
|
||||
Often the template page contains a simple skeleton for a particular type of
|
||||
page. For the bug report pages in the above example, it might look
|
||||
something like:
|
||||
page, wrapped in a [[templatebody]] directive. For the bug report pages in
|
||||
the above example, it might look something like:
|
||||
|
||||
\[[!templatebody <<ENDBODY
|
||||
Package:
|
||||
Version:
|
||||
Reproducible: y/n
|
||||
Details:
|
||||
ENDBODY]]
|
||||
|
||||
The template page can also contain [[!cpan HTML::Template]] directives,
|
||||
like other ikiwiki [[templates]]. Currently only one variable is
|
||||
set: `<TMPL_VAR name>` is replaced with the name of the page being
|
||||
created.
|
||||
|
||||
Text outside the [[templatebody]] directive is not part of the template,
|
||||
and can be used to document it.
|
||||
|
||||
If the template does not contain a [[templatebody]] directive, the entire
|
||||
source of the page is used for the template. This is deprecated.
|
||||
|
||||
[[!meta robots="noindex, follow"]]
|
||||
|
|
|
@ -31,16 +31,25 @@ large chunks of marked up text to be embedded into a template:
|
|||
|
||||
## Creating a template
|
||||
|
||||
The template is a regular wiki page, located in the `templates/`
|
||||
The template is in a regular wiki page, located in the `templates/`
|
||||
subdirectory inside the source directory of the wiki.
|
||||
The contents of the [[templatebody]] directive are used as the
|
||||
template. Anything outside that directive is not included in the template,
|
||||
and is usually used as documentation describing the template.
|
||||
|
||||
If the template does not contain a [[templatebody]] directive, the entire
|
||||
source of the page is used for the template. This is deprecated, because
|
||||
it leads to the template markup being interpreted as ordinary
|
||||
page source when the page is built, as well as being used as the template.
|
||||
|
||||
Alternatively, templates can be stored in a directory outside the wiki,
|
||||
as files with the extension ".tmpl".
|
||||
By default, these are searched for in `/usr/share/ikiwiki/templates`,
|
||||
the `templatedir` setting can be used to make another directory be searched
|
||||
first. When referring to templates outside the wiki source directory, the "id"
|
||||
parameter is not interpreted as a pagespec, and you must include the full filename
|
||||
of the template page, including the ".tmpl" extension. E.g.:
|
||||
parameter is not interpreted as a pagespec, you must include the full filename
|
||||
of the template page including the ".tmpl" extension,
|
||||
and the templatebody directive is not used. E.g.:
|
||||
|
||||
\[[!template id=blogpost.tmpl]]
|
||||
|
||||
|
@ -63,6 +72,7 @@ few things:
|
|||
|
||||
Here's a sample template:
|
||||
|
||||
\[[!templatebody <<ENDBODY
|
||||
<span class="infobox">
|
||||
Name: \[[<TMPL_VAR raw_name>]]<br />
|
||||
Age: <TMPL_VAR age><br />
|
||||
|
@ -76,6 +86,10 @@ Here's a sample template:
|
|||
<TMPL_VAR notes>
|
||||
</TMPL_IF>
|
||||
</span>
|
||||
ENDBODY]]
|
||||
|
||||
This template describes a person. Parameters: name, age,
|
||||
color (favorite color, optional), notes (optional).
|
||||
|
||||
The filled out template will be formatted the same as the rest of the page
|
||||
that contains it, so you can include WikiLinks and all other forms of wiki
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
The `templatebody` directive is supplied by the
|
||||
[[!iki plugins/templatebody desc=templatebody]] plugin.
|
||||
|
||||
This directive allows wiki pages to be used as templates
|
||||
for the [[template]] or [[edittemplate]] directive, without having
|
||||
[[!cpan HTML::Template]] markup interpreted as wiki markup when that
|
||||
page is built.
|
||||
|
||||
This directive does not produce any output in the wiki page that
|
||||
defines the template; the rest of that page can be used to to document
|
||||
how to use the template.
|
||||
|
||||
The first, un-named parameter is the content of the template.
|
||||
Because templates often contain [[directives|ikiwiki/directive]], it's
|
||||
convenient to use the "here-document" syntax for it:
|
||||
|
||||
\[[!templatebody <<ENDBODY
|
||||
[[!meta title="<TMPL_VAR name>"]]
|
||||
[[!tag person]]
|
||||
<dl>
|
||||
<dt>Name:</dt><dd><TMPL_VAR name></dd>
|
||||
<dt>Age:</dt><dd><TMPL_VAR age></dd>
|
||||
</dl>
|
||||
|
||||
<TMPL_VAR description>
|
||||
ENDBODY]]
|
||||
|
||||
[[!meta robots="noindex, follow"]]
|
|
@ -0,0 +1,7 @@
|
|||
[[!template id=plugin name=templatebody author="[[smcv]]" core=1]]
|
||||
[[!tag type/special-purpose]]
|
||||
|
||||
This plugin provides the [[ikiwiki/directive/templatebody]]
|
||||
[[ikiwiki/directive]]. With this plugin, you can set up templates
|
||||
stored in the wiki for [[template]] or [[edittemplate]] without the
|
||||
[[!cpan HTML::Template]] markup being interpreted as wiki markup.
|
|
@ -217,6 +217,9 @@ value is ignored.
|
|||
|
||||
Runs on the raw source of a page or `*.tmpl` file that is being
|
||||
used as a template, before it is parsed by [[!cpan HTML::Template]].
|
||||
For instance, the [[plugins/templatebody]] plugin uses this to return
|
||||
the content of the [[ikiwiki/directive/templatebody]] directive (if there
|
||||
is one) instead of the page's full content.
|
||||
|
||||
The function is passed named parameters:
|
||||
|
||||
|
|
|
@ -14,8 +14,10 @@ easy to learn. All you really need to know to modify templates is this:
|
|||
[[!if test="enabled(template) or enabled(edittemplate)" then="""
|
||||
## template pages
|
||||
|
||||
Template pages are regular wiki pages that are used as templates for other
|
||||
pages.
|
||||
Template pages are regular wiki pages containing a
|
||||
[[!iki ikiwiki/directive/templatebody desc="templatebody directive"]],
|
||||
used as templates for other pages. The parts of the template
|
||||
page outside the directive can be used to document it.
|
||||
"""]]
|
||||
|
||||
[[!if test="enabled(template)" then="""
|
||||
|
@ -38,6 +40,9 @@ feeds=no archive=yes sort=title template=titlepage
|
|||
rootpage=templates postformtext="Add a new template page named:"]]
|
||||
"""]]
|
||||
|
||||
If the template does not contain a `templatebody` directive, the entire
|
||||
source of the page is used for the template. This is deprecated.
|
||||
|
||||
## template files
|
||||
|
||||
Template files are unlike template pages in that they have the extension
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
#!/usr/bin/perl
|
||||
package IkiWiki;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
use Test::More tests => 18;
|
||||
|
||||
BEGIN { use_ok("IkiWiki"); }
|
||||
BEGIN { use_ok("IkiWiki::Render"); }
|
||||
BEGIN { use_ok("IkiWiki::Plugin::templatebody"); }
|
||||
BEGIN { use_ok("IkiWiki::Plugin::mdwn"); }
|
||||
BEGIN { use_ok("IkiWiki::Plugin::tag"); }
|
||||
BEGIN { use_ok("IkiWiki::Plugin::template"); }
|
||||
|
||||
sub assert_pagespec_matches {
|
||||
my $page = shift;
|
||||
my $spec = shift;
|
||||
my @params = @_;
|
||||
@params = (location => 'index') unless @params;
|
||||
|
||||
my $res = pagespec_match($page, $spec, @params);
|
||||
|
||||
if ($res) {
|
||||
pass($res);
|
||||
}
|
||||
else {
|
||||
fail($res);
|
||||
}
|
||||
}
|
||||
|
||||
sub assert_pagespec_doesnt_match {
|
||||
my $page = shift;
|
||||
my $spec = shift;
|
||||
my @params = @_;
|
||||
@params = (location => 'index') unless @params;
|
||||
|
||||
my $res = pagespec_match($page, $spec, @params);
|
||||
|
||||
if (ref $res && $res->isa("IkiWiki::ErrorReason")) {
|
||||
fail($res);
|
||||
}
|
||||
elsif ($res) {
|
||||
fail($res);
|
||||
}
|
||||
else {
|
||||
pass($res);
|
||||
}
|
||||
}
|
||||
|
||||
ok(! system("rm -rf t/tmp; mkdir t/tmp t/tmp/src t/tmp/dst"));
|
||||
|
||||
$config{verbose} = 1;
|
||||
$config{srcdir} = 't/tmp/src';
|
||||
$config{underlaydir} = 't/tmp/src';
|
||||
$config{destdir} = 't/tmp/dst';
|
||||
$config{underlaydirbase} = '.';
|
||||
$config{templatedir} = 'templates';
|
||||
$config{usedirs} = 1;
|
||||
$config{htmlext} = 'html';
|
||||
$config{wiki_file_chars} = "-[:alnum:]+/.:_";
|
||||
$config{default_pageext} = "mdwn";
|
||||
$config{wiki_file_prune_regexps} = [qr/^\./];
|
||||
|
||||
is(checkconfig(), 1);
|
||||
|
||||
%oldrenderedfiles=%pagectime=();
|
||||
%pagesources=%pagemtime=%oldlinks=%links=%depends=%typedlinks=%oldtypedlinks=
|
||||
%destsources=%renderedfiles=%pagecase=%pagestate=();
|
||||
|
||||
$pagesources{index} = "index.mdwn";
|
||||
$pagemtime{index} = $pagectime{index} = 1000000;
|
||||
writefile("index.mdwn", "t/tmp/src", <<EOF
|
||||
[[!template id="deftmpl" greeting="hello" them="world"]]
|
||||
[[!template id="oldtmpl" greeting="greetings" them="earthlings"]]
|
||||
EOF
|
||||
);
|
||||
|
||||
$pagesources{"templates/deftmpl"} = "templates/deftmpl.mdwn";
|
||||
$pagemtime{index} = $pagectime{index} = 1000000;
|
||||
writefile("templates/deftmpl.mdwn", "t/tmp/src", <<EOF
|
||||
[[!templatebody <<ENDBODY
|
||||
<p><b><TMPL_VAR GREETING>, <TMPL_VAR THEM></b></p>
|
||||
[[!tag greeting]]
|
||||
ENDBODY]]
|
||||
|
||||
This template says hello to someone.
|
||||
[[!tag documentation]]
|
||||
EOF
|
||||
);
|
||||
|
||||
$pagesources{"templates/oldtmpl"} = "templates/oldtmpl.mdwn";
|
||||
$pagemtime{index} = $pagectime{index} = 1000000;
|
||||
writefile("templates/oldtmpl.mdwn", "t/tmp/src", <<EOF
|
||||
<p><i><TMPL_VAR GREETING>, <TMPL_VAR THEM></i></p>
|
||||
EOF
|
||||
);
|
||||
|
||||
my %content;
|
||||
|
||||
foreach my $page (keys %pagesources) {
|
||||
my $content = readfile("t/tmp/src/$pagesources{$page}");
|
||||
$content = IkiWiki::filter($page, $page, $content);
|
||||
$content = IkiWiki::preprocess($page, $page, $content);
|
||||
$content{$page} = $content;
|
||||
}
|
||||
|
||||
# Templates are expanded
|
||||
like($content{index}, qr{<p><b>hello, world</b></p>});
|
||||
like($content{index}, qr{<p><i>greetings, earthlings</i></p>});
|
||||
assert_pagespec_matches('index', 'tagged(greeting)');
|
||||
# The documentation from the templatebody-using page is not expanded
|
||||
unlike($content{index}, qr{This template says hello to someone});
|
||||
assert_pagespec_doesnt_match('index', 'tagged(documentation)');
|
||||
|
||||
# In the templatebody-using page, the documentation is expanded
|
||||
like($content{'templates/deftmpl'}, qr{This template says hello to someone});
|
||||
assert_pagespec_matches('templates/deftmpl', 'tagged(documentation)');
|
||||
# In the templatebody-using page, the template is *not* expanded
|
||||
unlike($content{'templates/deftmpl'}, qr{<p><b>hello, world</b></p>});
|
||||
unlike($content{'templates/deftmpl'}, qr{<p><i>greetings, earthlings</i></p>});
|
||||
assert_pagespec_doesnt_match('templates/deftmpl', 'tagged(greeting)');
|
||||
|
||||
1;
|
Loading…
Reference in New Issue