NAME
Text::Xslate::Manual::Cookbook - How to cook Xslate templates
DESCRIPTION
The Xslate cookbook is a set of recipes showing Xslate features.
RECIPES
How to manage HTML forms
Managing HTML forms is an important issue on web applications. You'd better to use modules that manage HTML forms, rather than do something with templates by yourself. This section proposes two basic solutions: using FillInForm and HTML form builders.
In both solutions, one should not use the mark_raw filter
in templates, which easily makes security holes. Instead, application code should be responsible to call the mark_raw function
that Text::Xslate
can export.
Using FillInForm
One solution to manage HTML forms is to use FillInForm modules with the block filter syntax.
Example code using HTML::FillInForm
:
#!perl -w
use strict;
use Text::Xslate qw(html_builder);
use HTML::FillInForm; # HTML::FillInForm::Lite is okay
sub fillinform {
my($q) = @_;
my $fif = HTML::FillInForm->new();
return html_builder {
my($html) = @_;
return $fif->fill(\$html, $q);
};
}
my $tx = Text::Xslate->new(
function => {
fillinform => \&fillinform,
},
);
my %vars = (
q => { foo => "<filled value>" },
);
print $tx->render_string(<<'T', \%vars);
FillInForm:
: block form | fillinform($q) -> {
<form>
<input type="text" name="foo" />
</form>
: }
T
Output:
FillInForm:
<form>
<input type="text" name="foo" value="<filled value>" />
</form>
Because HTML::FillInForm::Lite provides fillinform
function, it becomes more simple:
use HTML::FillInForm qw(fillinform);
my $tx = Text::Xslate->new(
function => { fillinform => html_builder(\&fillinform) },
);
See also HTML::FillInForm or HTML::FillInForm::Lite for details.
Using HTML form builders
Another solution to manage HTML forms is to use form builders. In such cases, all you have to do is to apply mark_raw()
to HTML parts.
Here is a PSGI application that uses HTML::Shakan
:
#!psgi
use strict;
use warnings;
use Text::Xslate qw(mark_raw);
use HTML::Shakan;
use Plack::Request;
my $tx = Text::Xslate->new();
sub app {
my($env) = @_;
my $req = Plack::Request->new($env);
my $shakan = HTML::Shakan->new(
request => $req,
fields => [ TextField(name => 'name', label => 'Your name: ') ],
);
my $res = $req->new_response(200);
# do mark_raw here, not in templates
my $form = mark_raw($shakan->render());
$res->body( $tx->render_string(<<'T', { form => $form }) );
<!doctype html>
<html>
<head><title>Building form</title></head>
<body>
<form>
<p>
Form:<br />
<: $form :>
</p>
</body>
</html>
T
return $res->finalize();
}
return \&app;
Output:
<!doctype html>
<html>
<head><title>Building form</title></head>
<body>
<form>
<p>
Form:<br />
<label for="id_name">Your name</label>
<input id="id_name" name="name" type="text" value="<Xslate>" />
</p>
</body>
</html>
See also HTML::Shakan for details.
How to use Template Toolkit's WRAPPER feature in Kolon
Use template cascading, which is a super-set of the WRAPPER
directive.
wrapper.tx:
<div class="wrapper">
block content -> { }
</div>
content.tx
: cascade wrapper
: override content -> {
Hello, world!
: }
Output:
<div class="wrapper">
Hello, world!
</div>
See "Template cascading" in Text::Xslate for details.
How to map __DATA__ sections to the include path
Use Data::Section::Simple
, and the path
option of new()
, which accepts HASH references which contain $file_name => $content
mapping.
use Text::Xslate;
use Data::Section::Simple;
my $vpath = Data::Section::Simple->new()->get_data_section();
my $tx = Text::Xslate->new(
path => [$vpath],
);
print $tx->render('child.tx');
__DATA__
@@ base.tx
<html>
<body><: block body -> { :>default body<: } :></body>
</html>
@@ child.tx
: cascade base;
: override body -> {
child body
: } # endblock body
This feature is directly inspired by Text::MicroTemplate::DataSection, and originated from Mojo.
See also Data::Section::Simple, Text::MicroTemplate::DataSection, and Mojolicious.
How to assign a specific path
by user's environment
If you want to assign a specific path
by users environment, namely their language or platform (PC or mobile), you'd better create Xslate instances with those path
s.
For example:
my %common_config = ( cache_dir => $dir, module => \@module );
my %xslate = (
ja => Text::Xslate->new( path => [ $template_ja ], %common_config ),
en => Text::Xslate->new( path => [ $template_en ], %common_config ),
ro => Text::Xslate->new( path => [ $template_ro ], %common_config ),
);
$xslate{$lang}->render(...);
How to interpolate data into JavaScript sections without XSS
(This section is not yet completed. Example code should be provided.)
Because Xslate escapes only HTML meta characters, you must escape JavaScript meta characters by yourself when you give data into <script> ... </script>
sections.
It is better to use secure modules for JavaScript escaping to avoid XSS. JavaScript::Value::Escape may help you for this aim.
How to interpolate structured texts into HTML without XSS
(This section is not yet completed. Example code should be provided.)
See String::Filter.
How to manage localization in templates
You can register any functions including _()
, so no specific techniques are required.
For example:
use I18N::Handle;
# I18N::Handle installs the locale function "_" to the global namespace.
# (remember the symbol *_ is global)
I18N::Handle->new( ... )->speak('zh_tw');
my $tx = Text::Xslate->new(
function => {
_ => \&_,
},
);
Then in your templates:
<: _('Hello %1', $john ) :>
See also: I18N::Handle, App::I18N.
How to load templates before fork()
ing?
It is a good idea to load templates in preforking-model applications. Here is an example to to load all the templates which is in a given path:
use File::Find;
my $path = ...;
my $tx = Text::Xslate->new(
path => [$path],
cache_dir => $path,
);
# pre-load files
find sub {
if(/\.tx$/) {
my $file = $File::Find::name;
$file =~ s/\Q$path\E .//xsm; # fix path names
$tx->load_file($file);
}
}, $path;
# fork and render ...