File Coverage

blib/lib/HTML/FormHandlerX/Field/JSON.pm
Criterion Covered Total %
statement 46 52 88.4
branch 11 12 91.6
condition 9 14 64.2
subroutine 11 13 84.6
pod 0 5 0.0
total 77 96 80.2


line stmt bran cond sub pod time code
1             package HTML::FormHandlerX::Field::JSON;
2             # ABSTRACT: a script tag which sets a var using JSON C<data>, encoded from perl data supplied via field for L<HTML::FormHandler>.
3             $HTML::FormHandlerX::Field::JSON::VERSION = '0.001'; # TRIAL
4              
5 2     2   1826480 use Moose;
  2         3  
  2         14  
6             extends 'HTML::FormHandler::Field::NoValue';
7 2     2   8488 use namespace::autoclean;
  2         3  
  2         18  
8              
9 2     2   937 use JSON::MaybeXS;
  2         8508  
  2         100  
10 2     2   375 use JavaScript::Minifier::XS qw();
  2         423  
  2         1083  
11              
12             has 'data_key' => ( is => 'rw', isa => 'Str', builder => 'build_data_key', lazy => 1 );
13 3     3 0 7 sub build_data_key { HTML::FormHandler::Field::convert_full_name( shift->full_name ) }
14              
15             has 'data' => (
16             is => 'rw',
17             # isa => 'Str',
18             builder => 'build_data',
19             lazy => 1
20             );
21 0     0 0 0 sub build_data { '' }
22             has 'set_data' => ( isa => 'Str', is => 'ro' );
23              
24             has 'do_minify' => ( isa => 'Bool', is => 'rw', default => 0 );
25             has '+do_label' => ( default => 0 );
26              
27             has 'render_method' => (
28             traits => ['Code'],
29             is => 'ro',
30             isa => 'CodeRef',
31             lazy => 1,
32             predicate => 'does_render_method',
33             handles => { 'render' => 'execute_method' },
34             builder => 'build_render_method',
35             );
36              
37             sub build_render_method {
38 8     8 0 28 my $self = shift;
39              
40 8         213 my $set_data = $self->set_data;
41 8   66     23 $set_data ||= "data_" . HTML::FormHandler::Field::convert_full_name( $self->full_name );
42 5     5   4 return sub { my $self = shift; $self->wrap_data( $self->form->$set_data($self) ); }
  5         97  
43 8 100 66     439 if ( $self->form && $self->form->can($set_data) );
44             return sub {
45 5     5   6 my $self = shift;
46 5         130 return $self->wrap_data( $self->data );
47 3         202 };
48             } ## end sub build_render_method
49              
50             sub _result_from_object {
51 0     0   0 my ( $self, $result, $value ) = @_;
52 0         0 $self->_set_result($result);
53 0         0 $self->value($value);
54 0         0 $result->_set_field_def($self);
55 0         0 return $result;
56             }
57              
58             sub wrap_data {
59 10     10 0 43 my $self = shift;
60              
61 10 50       23 my $json = $self->deflator( @_ > 1 ? [@_] : $_[0] );
62 10         159 chomp $json;
63              
64 10         305 my $data_key = $self->data_key;
65              
66 10         8 my $javascript = '';
67 10 100       32 if ( $data_key =~ m/.+\..+/ ) { # key contains 'dot' properties, so don't create a var, just set property
    100          
    100          
68 1         3 $javascript .= qq{\n $data_key = $json;};
69             } elsif ( $data_key =~ m/.+\.$/ ) { # key ends with 'dot', so assume data_key is object and field_name is property, don't create a var, just set property
70 1         4 my $property_key = HTML::FormHandler::Field::convert_full_name( $self->full_name );
71 1         72 $javascript .= qq{\n $data_key$property_key = $json;};
72             } elsif ( $data_key =~ m/^\..+/ )
73             { # key starts with 'dot', so assume data_key is property and field_name is object, don't create a var, just set property, and assume property is an array
74 1         4 my $object_key = HTML::FormHandler::Field::convert_full_name( $self->full_name );
75 1         72 $javascript .= qq{\n $object_key$data_key = $json;};
76             } else {
77 7         13 $javascript .= qq{\n var $data_key = $json;};
78             }
79              
80 10         9 my $output = qq{\n<script type="text/javascript">};
81 10 100       267 $output .= $self->do_minify ? JavaScript::Minifier::XS::minify($javascript) : $javascript;
82 10         13 $output .= qq{\n</script>};
83              
84 10         46 return $output;
85             } ## end sub wrap_data
86              
87              
88             has "json_opts" => (
89             is => "rw",
90             traits => ['Hash'],
91             isa => "HashRef",
92             default => sub { { pretty => undef, relaxed => undef, canonical => undef } },
93             handles => {
94             set_json_opt => 'set',
95             get_json_opt => 'get',
96             },
97             );
98              
99             sub deflator {
100 10     10 0 11 my ( $self, $value ) = @_;
101 10   100     324 my $pretty = $self->get_json_opt('pretty') // 1;
102 10   50     314 my $relaxed = $self->get_json_opt('relaxed') // 1;
103 10   50     307 my $canonical = $self->get_json_opt('canonical') // 1;
104 10   50     24 return JSON->new
105             ->utf8
106             ->allow_nonref
107             ->pretty($pretty)
108             ->relaxed($relaxed)
109             ->canonical($canonical)
110             ->encode($value)
111             || '';
112             } ## end sub deflator
113              
114              
115             __PACKAGE__->meta->make_immutable;
116 2     2   10 use namespace::autoclean;
  2         3  
  2         13  
117             1;
118              
119             __END__
120              
121             =pod
122              
123             =encoding UTF-8
124              
125             =head1 NAME
126              
127             HTML::FormHandlerX::Field::JSON - a script tag which sets a var using JSON C<data>, encoded from perl data supplied via field for L<HTML::FormHandler>.
128              
129             =head1 VERSION
130              
131             version 0.001
132              
133             =head1 SYNOPSIS
134              
135             This class can be used for fields that need to supply JSON data for use
136             by scripts in the form. It will JSONify and render the value returned by
137             a form's C<data_[field_name]> method, or the field's C<data> attribute.
138              
139             has_field 'user_addresses' => ( type => 'JSON',
140             data => { john => 'john@example.com', sarah => 'sarah@example.com' } );
141              
142             or using a method:
143              
144             has_field 'user_addresses' => ( type => 'JSON' );
145             sub data_user_addresses {
146             my ( $self, $field ) = @_;
147             if( $field->value == 'foo' ) {
148             return { john => 'john@example.com', sarah => 'sarah@example.com' };
149             } else {
150             return [ 'john@example.com', 'sarah@example.com' ];
151             }
152             }
153             #----
154             has_field 'usernames' => ( type => 'JSON' );
155             sub data_usernames {
156             my ( $self, $field ) = @_;
157             return [ qw'john sarah' ];
158             }
159              
160             or set the name of the rendering method:
161              
162             has_field 'user_addresses' => ( type => 'JSON', set_data => 'my_user_addresses' );
163             sub my_user_addresses {
164             ....
165             }
166              
167             or provide a 'render_method':
168              
169             has_field 'user_addresses' => ( type => 'JSON', render_method => \&render_user_addresses );
170             sub render_user_addresses {
171             my $self = shift;
172             ....
173             return '...';
174             }
175              
176             =head2 variable names
177              
178             By default, the name of the variable being assigned is same as the field
179             name. The variable name can be changed with the data_key attribute. If
180             the data_key value is simple string (no dot separator) then the variable
181             will be created with C<var varName;>, otherwise it is assumed the
182             variable is already defined.
183              
184             The data_key can begin or end with a dot, in which case the field name
185             is either appended or prepended to the data_key.
186              
187             has_field 'user_addresses' => ( type => 'JSON',
188             data_key => '.email',
189             data_ => [ qw'john@acme.org sarah@acme.org' ],
190             );
191              
192             Will render as:
193              
194             <script type="text/javascript">
195             user_addresses.email = [ "john@acme.org", "sarah@acme.org" ];
196             </script>);
197              
198             =head1 FIELD OPTIONS
199              
200             We support the following additional field options, over what is inherited from
201             L<HTML::FormHandler::Field>
202              
203             =head2 do_minify
204              
205             Boolean to indicate whether code should be minified using L<JavaScript::Minifier::XS>
206              
207             =head2 json_opts
208              
209             Hashref with 3 possible keys; C<pretty>, C<relaxed>, C<canonical>. The
210             values are passed to L<JSON> when encoding the data.
211              
212             =head1 AUTHOR
213              
214             Charlie Garrison <garrison@zeta.org.au>
215              
216             =head1 COPYRIGHT AND LICENSE
217              
218             This software is copyright (c) 2014 by Charlie Garrison.
219              
220             This is free software; you can redistribute it and/or modify it under
221             the same terms as the Perl 5 programming language system itself.
222              
223             =cut