1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
package FixMyStreet::Template;
use parent Template;
use strict;
use warnings;
use FixMyStreet;
use mySociety::Locale;
use Attribute::Handlers;
my %FILTERS;
my %SUBS;
# HASH is where we want to store the thing, either FILTERS or SUBS. SYMBOL is a
# symbol table ref, where NAME then returns its name (perlref has the gory
# details). FN is a ref to the function. DATA is an arrayref of any passed in
# arguments.
sub add_attr {
my ($hash, $symbol, $fn, $data) = @_;
my $name = $data ? $data->[0] : *{$symbol}{NAME};
$hash->{$name} = $fn;
}
# Create two attributes, Filter and Fn, which you apply to a function to turn
# them into a template filter or function. You can optionally provide an argument
# name for what to call the thing in the template if it's not the same as the
# function name. They're called at the BEGIN stage rather than the default CHECK
# as this code might be imported by an eval.
sub Filter : ATTR(CODE,BEGIN) {
add_attr(\%FILTERS, $_[1], $_[2], $_[4]);
}
sub Fn : ATTR(CODE,BEGIN) {
add_attr(\%SUBS, $_[1], $_[2], $_[4]);
}
sub new {
my ($class, $config) = @_;
$config->{FILTERS}->{$_} = $FILTERS{$_} foreach keys %FILTERS;
$config->{ENCODING} = 'utf8';
$class->SUPER::new($config);
}
sub process {
my ($class, $template, $vars, $output, %options) = @_;
$vars->{$_} = $SUBS{$_} foreach keys %SUBS;
$class->SUPER::process($template, $vars, $output, %options);
}
=head2 loc
[% loc('Some text to localize', 'Optional comment for translator') %]
Passes the text to the localisation engine for translations.
=cut
sub loc : Fn {
return _(@_);
}
=head2 nget
[% nget( 'singular', 'plural', $number ) %]
Use first or second string depending on the number.
=cut
sub nget : Fn {
return mySociety::Locale::nget(@_);
}
=head2 file_exists
[% file_exists("web/cobrands/$cobrand/image.png") %]
Checks to see if a file exists, relative to the codebase root.
=cut
sub file_exists : Fn {
-e FixMyStreet->path_to(@_);
}
=head2 html_filter
Same as Template Toolkit's html_filter, but escapes ' too, as we don't (and
shouldn't have to) know whether we'll be used inbetween single or double
quotes.
=cut
sub html_filter : Filter('html') {
my $text = shift;
for ($text) {
s/&/&/g;
s/</</g;
s/>/>/g;
s/"/"/g;
s/'/'/g;
}
return $text;
}
=head2 html_paragraph
Same as Template Toolkit's html_paragraph, but converts single newlines
into <br>s too.
=cut
sub html_paragraph : Filter('html_para') {
my $text = shift;
my @paras = split(/(?:\r?\n){2,}/, $text);
s/\r?\n/<br>\n/ for @paras;
$text = "<p>\n" . join("\n</p>\n\n<p>\n", @paras) . "</p>\n";
return $text;
}
1;
|