JavaScript-Plugin: auch als Filter einsetzen können
[kivitendo-erp.git] / SL / Template / Plugin / JavaScript.pm
1 package SL::Template::Plugin::JavaScript;
2
3 use base qw( Template::Plugin::Filter );
4
5 use strict;
6
7 my $cached_instance;
8
9 sub new {
10   my $class = shift;
11
12   return $cached_instance ||= $class->SUPER::new(@_);
13 }
14
15 sub init {
16   my $self = shift;
17
18   $self->install_filter($self->{ _ARGS }->[0] || 'js');
19
20   return $self;
21 }
22
23 #
24 # public interface
25 #
26
27 # see ecmascript spec section 7.8.4
28 my @escape_chars = ('\\', '\'', '"');
29 my %control_chars = (
30   "\n"   => 'n',
31   "\t"   => 't',
32   "\r"   => 'r',
33   "\f"   => 'f',
34   "\x08" => 'b',
35   "\x0B" => 'v', # noone uses vertical tab anyway...
36 );
37 my $re = join '', map { qr/($_)/s } join '|', keys(%control_chars), map { "\Q$_\E" } @escape_chars;
38
39 sub escape {
40   my $self = shift;
41   my $text = shift;
42
43   $text =~ s/$re/'\\' . ($control_chars{$1} || $1)/egs;
44
45   return $text;
46 }
47
48 sub filter {
49   my ($self, $text) = @_;
50   return $self->escape($text);
51 }
52
53 sub replace_with {
54   return _replace_helper('replaceWith', @_);
55 }
56
57 sub replace_html_with {
58   return _replace_helper('html', @_);
59 }
60
61 #
62 # private methods
63 #
64
65 sub _context {
66   die 'not an accessor' if @_ > 1;
67   return $_[0]->{CONTEXT};
68 }
69
70 sub _replace_helper {
71   my ($method, $self, $selector, $template, $locals) = @_;
72
73   $template .= '.html' unless $template =~ m/\.html$/;
74   my $html   = $self->escape($self->_context->process($template, %{ $locals || { } }));
75   my $code = <<CODE;
76 \$('${selector}').${method}("$html");
77 CODE
78
79   return $code;
80 }
81
82 1;
83
84
85 __END__
86
87 =pod
88
89 =encoding utf8
90
91 =head1 NAME
92
93 SL::Template::Plugin::JavaScript - Template plugin for JavaScript helper functions
94
95 =head1 FUNCTIONS
96
97 =over 4
98
99 =item C<escape $value>
100
101 Returns C<$value> escaped for inclusion in a JavaScript string. The
102 value is not wrapped in quotes. Example:
103
104   <input type="submit" value="Delete"
105          onclick="if (confirm('Do you really want to delete this: [% JavaScript.escape(obj.description) %]') return true; else return false;">
106
107 You can also use the filter syntax instead:
108
109   <input type="submit" value="Delete"
110          onclick="if (confirm('Do you really want to delete this: [% obj.description | js %]') return true; else return false;">
111
112 =item C<replace_with $selector, $template, %locals>
113
114 Returns code replacing the DOM elements matched by C<$selector> with
115 the content rendered by Template's I<PROCESS> directive applied to
116 C<$template>. C<%locals> are passed as local parameters to I<PROCESS>.
117
118 Uses jQuery's C<obj.replaceWith()> function. Requires jQuery to be loaded.
119
120 Example:
121
122   <div>TODO:</div>
123   <ul>
124     <li id="item1">First item</li>
125     <li id="item2">Second item</li>
126     <li id="item3">Another item</li>
127   </ul>
128
129   <script type="text/javascript">
130     function do_work() {
131       [% JavaScript.replace_with('#item2', 'todo/single_item', item => current_todo_item) %]
132     }
133   </script>
134
135   <input type="submit" onclick="do_work(); return false;" value="Replace single item">
136
137 =item C<replace_html_with $selector, $template, %locals>
138
139 Returns code replacing the inner HTML of the DOM elements matched by
140 C<$selector> with the content rendered by Template's I<PROCESS>
141 directive applied to C<$template>. C<%locals> are passed as local
142 parameters to I<PROCESS>.
143
144 Uses jQuery's C<obj.html()> function. Requires jQuery to be loaded.
145
146   <div>TODO:</div>
147   <ul id="todo_list">
148     <li id="item1">First item</li>
149     <li id="item2">Second item</li>
150     <li id="item3">Another item</li>
151   </ul>
152
153   <script type="text/javascript">
154     function do_work() {
155       [% JavaScript.replace_html_with('#todo_list', 'todo/full_list', items => todo_items) %]
156     }
157   </script>
158
159   <input type="submit" onclick="do_work(); return false;" value="Replace list">
160
161 =back
162
163 =head1 BUGS
164
165 Nothing here yet.
166
167 =head1 AUTHOR
168
169 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
170
171 =cut