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",
|
type => "internal",
|
||||||
default => [qw{mdwn link inline meta htmlscrubber passwordauth
|
default => [qw{mdwn link inline meta htmlscrubber passwordauth
|
||||||
openid signinedit lockedit conditional
|
openid signinedit lockedit conditional
|
||||||
recentchanges parentlinks editpage}],
|
recentchanges parentlinks editpage
|
||||||
|
templatebody}],
|
||||||
description => "plugins to enable by default",
|
description => "plugins to enable by default",
|
||||||
safe => 0,
|
safe => 0,
|
||||||
rebuild => 1,
|
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".
|
"silent=yes".
|
||||||
|
|
||||||
Often the template page contains a simple skeleton for a particular type of
|
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
|
page, wrapped in a [[templatebody]] directive. For the bug report pages in
|
||||||
something like:
|
the above example, it might look something like:
|
||||||
|
|
||||||
|
\[[!templatebody <<ENDBODY
|
||||||
Package:
|
Package:
|
||||||
Version:
|
Version:
|
||||||
Reproducible: y/n
|
Reproducible: y/n
|
||||||
Details:
|
Details:
|
||||||
|
ENDBODY]]
|
||||||
|
|
||||||
The template page can also contain [[!cpan HTML::Template]] directives,
|
The template page can also contain [[!cpan HTML::Template]] directives,
|
||||||
like other ikiwiki [[templates]]. Currently only one variable is
|
like other ikiwiki [[templates]]. Currently only one variable is
|
||||||
set: `<TMPL_VAR name>` is replaced with the name of the page being
|
set: `<TMPL_VAR name>` is replaced with the name of the page being
|
||||||
created.
|
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"]]
|
[[!meta robots="noindex, follow"]]
|
||||||
|
|
|
@ -31,16 +31,25 @@ large chunks of marked up text to be embedded into a template:
|
||||||
|
|
||||||
## Creating 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.
|
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,
|
Alternatively, templates can be stored in a directory outside the wiki,
|
||||||
as files with the extension ".tmpl".
|
as files with the extension ".tmpl".
|
||||||
By default, these are searched for in `/usr/share/ikiwiki/templates`,
|
By default, these are searched for in `/usr/share/ikiwiki/templates`,
|
||||||
the `templatedir` setting can be used to make another directory be searched
|
the `templatedir` setting can be used to make another directory be searched
|
||||||
first. When referring to templates outside the wiki source directory, the "id"
|
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
|
parameter is not interpreted as a pagespec, you must include the full filename
|
||||||
of the template page, including the ".tmpl" extension. E.g.:
|
of the template page including the ".tmpl" extension,
|
||||||
|
and the templatebody directive is not used. E.g.:
|
||||||
|
|
||||||
\[[!template id=blogpost.tmpl]]
|
\[[!template id=blogpost.tmpl]]
|
||||||
|
|
||||||
|
@ -63,6 +72,7 @@ few things:
|
||||||
|
|
||||||
Here's a sample template:
|
Here's a sample template:
|
||||||
|
|
||||||
|
\[[!templatebody <<ENDBODY
|
||||||
<span class="infobox">
|
<span class="infobox">
|
||||||
Name: \[[<TMPL_VAR raw_name>]]<br />
|
Name: \[[<TMPL_VAR raw_name>]]<br />
|
||||||
Age: <TMPL_VAR age><br />
|
Age: <TMPL_VAR age><br />
|
||||||
|
@ -76,6 +86,10 @@ Here's a sample template:
|
||||||
<TMPL_VAR notes>
|
<TMPL_VAR notes>
|
||||||
</TMPL_IF>
|
</TMPL_IF>
|
||||||
</span>
|
</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
|
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
|
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
|
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]].
|
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:
|
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="""
|
[[!if test="enabled(template) or enabled(edittemplate)" then="""
|
||||||
## template pages
|
## template pages
|
||||||
|
|
||||||
Template pages are regular wiki pages that are used as templates for other
|
Template pages are regular wiki pages containing a
|
||||||
pages.
|
[[!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="""
|
[[!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:"]]
|
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
|
||||||
|
|
||||||
Template files are unlike template pages in that they have the extension
|
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