File Coverage

blib/lib/Form/Factory/Interface/HTML.pm
Criterion Covered Total %
statement 94 97 96.9
branch 13 18 72.2
condition 3 4 75.0
subroutine 28 28 100.0
pod 11 11 100.0
total 149 158 94.3


line stmt bran cond sub pod time code
1             package Form::Factory::Interface::HTML;
2             $Form::Factory::Interface::HTML::VERSION = '0.022';
3 1     1   591 use Moose;
  1         1  
  1         7  
4              
5             with qw( Form::Factory::Interface );
6              
7 1     1   4719 use Carp ();
  1         1  
  1         14  
8 1     1   4 use Scalar::Util qw( blessed );
  1         1  
  1         59  
9              
10 1     1   398 use Form::Factory::Interface::HTML::Widget::Div;
  1         263  
  1         34  
11 1     1   555 use Form::Factory::Interface::HTML::Widget::Input;
  1         306  
  1         42  
12 1     1   544 use Form::Factory::Interface::HTML::Widget::Label;
  1         290  
  1         40  
13 1     1   532 use Form::Factory::Interface::HTML::Widget::List;
  1         306  
  1         41  
14 1     1   526 use Form::Factory::Interface::HTML::Widget::ListItem;
  1         460  
  1         38  
15 1     1   519 use Form::Factory::Interface::HTML::Widget::Select;
  1         292  
  1         40  
16 1     1   515 use Form::Factory::Interface::HTML::Widget::Span;
  1         278  
  1         39  
17 1     1   534 use Form::Factory::Interface::HTML::Widget::Textarea;
  1         296  
  1         1276  
18              
19             # ABSTRACT: Simple HTML form interface
20              
21              
22             has renderer => (
23             is => 'ro',
24             isa => 'CodeRef',
25             required => 1,
26             default => sub { sub { print @_ } },
27             );
28              
29              
30             has consumer => (
31             is => 'ro',
32             isa => 'CodeRef',
33             required => 1,
34             default => sub { sub { $_[0] } },
35             );
36              
37              
38             sub new_widget_for_control {
39 135     135 1 172 my $self = shift;
40 135         139 my $control = shift;
41 135         404 my $results = shift;
42              
43 135         426 my $control_type = blessed $control;
44 135         548 my ($name) = $control_type =~ /^Form::Factory::Control::(\w+)$/;
45 135 50       281 return unless $name;
46 135         218 $name = lc $name;
47              
48 135         149 my @alerts;
49 135 100       266 @alerts = _alerts_for_control($control->name, $name, $results)
50             if $results;
51              
52 135         230 my $method = 'new_widget_for_' . $name;
53 135 50       712 return $self->$method($control, @alerts) if $self->can($method);
54 0         0 return;
55             }
56              
57             sub _wrapper($$@) {
58 130     130   235 my ($name, $type, @widgets) = @_;
59              
60 130         5449 return Form::Factory::Interface::HTML::Widget::Div->new(
61             id => $name . '-wrapper',
62             classes => [ qw( widget wrapper ), $type ],
63             widgets => \@widgets,
64             );
65             }
66              
67             sub _label($$$;$) {
68 130     130   280 my ($name, $type, $label, $is_required) = @_;
69              
70 130         549 return Form::Factory::Interface::HTML::Widget::Label->new(
71             id => $name . '-label',
72             classes => [ qw( widget label ), $type ],
73             for => $name,
74             content => $label . _required_marker($is_required),
75             );
76             }
77              
78             sub _required_marker($) {
79 130     130   151 my ($is_required) = @_;
80            
81 130 100       252 if ($is_required) {
82 5         204 return Form::Factory::Interface::HTML::Widget::Span->new(
83             classes => [ qw( required ) ],
84             content => '*',
85             )->render;
86             }
87             else {
88 125         4761 return '';
89             }
90             }
91              
92             sub _input($$$;$%) {
93 135     135   354 my ($name, $type, $input_type, $value, %args) = @_;
94              
95 135   100     5883 return Form::Factory::Interface::HTML::Widget::Input->new(
96             id => $name,
97             name => $name,
98             type => $input_type,
99             classes => [ qw( widget field ), $type ],
100             value => $value || '',
101             %args,
102             );
103             }
104              
105             sub _alerts($$@) {
106 130     130   203 my ($name, $type, @items) = @_;
107              
108 130         5196 return Form::Factory::Interface::HTML::Widget::List->new(
109             id => $name . '-alerts',
110             classes => [ qw( widget alerts ), $type ],
111             items => \@items,
112             );
113             }
114              
115             sub _alerts_for_control {
116 1     1   3 my ($name, $type, $results) = @_;
117 1         3 my @items;
118              
119 1         3 my $count = 0;
120 1         11 my @messages = $results->field_messages($name);
121 1         9 for my $message (@messages) {
122 0         0 push @items, Form::Factory::Interface::HTML::Widget::ListItem->new(
123             id => $name . '-message-' . ++$count,
124             classes => [ qw( widget message ), $type, $message->type ],
125             content => $message->english_message,
126             );
127             }
128              
129 1         5 return @items;
130             }
131              
132              
133             sub new_widget_for_button {
134 4     4 1 6 my ($self, $control) = @_;
135              
136 4         144 return _input($control->name, 'button', 'submit', $control->label);
137             }
138              
139              
140             sub new_widget_for_checkbox {
141 1     1 1 3 my ($self, $control, @alerts) = @_;
142              
143 1   50     37 return _wrapper($control->name, 'checkbox',
144             _input($control->name, 'checkbox', 'checkbox', $control->true_value,
145             checked => $control->is_true || ''),
146             _label($control->name, 'checkbox', $control->label),
147             _alerts($control->name, 'checkbox', @alerts),
148             );
149             }
150              
151              
152             sub new_widget_for_fulltext {
153 1     1 1 2 my ($self, $control, @alerts) = @_;
154              
155 1         30 return _wrapper($control->name, 'full-text',
156             _label($control->name, 'full-text', $control->label,
157             $control->has_feature('required')),
158             Form::Factory::Interface::HTML::Widget::Textarea->new(
159             id => $control->name,
160             name => $control->name,
161             classes => [ qw( widget field full-text ) ],
162             content => $control->current_value,
163             ),
164             _alerts($control->name, 'full-text', @alerts),
165             );
166             }
167              
168              
169             sub new_widget_for_password {
170 1     1 1 2 my ($self, $control, @alerts) = @_;
171              
172 1         47 return _wrapper($control->name, 'password',
173             _label($control->name, 'password', $control->label,
174             $control->has_feature('required')),
175             _input($control->name, 'password', 'password', $control->current_value),
176             _alerts($control->name, 'password', @alerts),
177             );
178             }
179              
180              
181             sub new_widget_for_selectmany {
182 1     1 1 5 my ($self, $control, @alerts) = @_;
183              
184 1         2 my @checkboxes;
185 1         3 for my $choice (@{ $control->available_choices }) {
  1         66  
186 5         269 push @checkboxes, _input(
187             $control->name, 'select-many choice', 'checkbox',
188             $choice->value, checked => $control->is_choice_selected($choice),
189             );
190             }
191              
192 1         47 return _wrapper($control->name, 'select-many',
193             _label($control->name, 'select-many', $control->label,
194             $control->has_feature('required')),
195             Form::Factory::Interface::HTML::Widget::Div->new(
196             id => $control->name . '-list',
197             classes => [ qw( widget list select-many ) ],
198             widgets => \@checkboxes,
199             ),
200             _alerts($control->name, 'select-many', @alerts),
201             );
202             }
203              
204              
205             sub new_widget_for_selectone {
206 2     2 1 5 my ($self, $control, @alerts) = @_;
207              
208 2         81 return _wrapper($control->name, 'select-one',
209             _label($control->name, 'select-one', $control->label,
210             $control->has_feature('required')),
211             Form::Factory::Interface::HTML::Widget::Select->new(
212             id => $control->name,
213             name => $control->name,
214             classes => [ qw( widget field select-one ) ],
215             size => 1,
216             available_choices => $control->available_choices,
217             selected_choices => [ $control->current_value ],
218             ),
219             _alerts($control->name, 'select-one', @alerts),
220             );
221             }
222              
223              
224             sub new_widget_for_text {
225 124     124 1 204 my ($self, $control, @alerts) = @_;
226              
227 124         3687 return _wrapper($control->name, 'text',
228             _label($control->name, 'text', $control->label,
229             $control->has_feature('required')),
230             _input($control->name, 'text', 'text', $control->current_value),
231             _alerts($control->name, 'text', @alerts),
232             );
233             }
234              
235              
236             sub new_widget_for_value {
237 1     1 1 2 my ($self, $control, @alerts) = @_;
238              
239 1 50       32 if ($control->is_visible) {
240 0         0 return _wrapper($control->name, 'value',
241             _label($control->name, 'value', $control->label),
242             Form::Factory::Interface::HTML::Widget::Span->new(
243             id => $control->name,
244             content => $control->value,
245             classes => [ qw( widget field value ) ],
246             ),
247             _alerts($control->name, 'text', @alerts),
248             );
249             }
250              
251 1         3 return;
252             }
253              
254              
255             sub render_control {
256 1     1 1 3 my ($self, $control, %options) = @_;
257              
258 1         7 my $widget = $self->new_widget_for_control($control, $options{results});
259 1 50       4 return unless $widget;
260 1         13 $self->renderer->($widget->render);
261             }
262              
263              
264             sub consume_control {
265 134     134 1 279 my ($self, $control, %options) = @_;
266              
267 134 50       279 Carp::croak("no request option passed") unless defined $options{request};
268              
269 134         345 my $widget = $self->new_widget_for_control($control);
270 134 100       641 return unless defined $widget;
271              
272 133         4783 my $params = $widget->consume( params => $self->consumer->($options{request}) );
273              
274 133 100       3908 return unless defined $params->{ $control->name };
275              
276 87         2388 $control->current_value( $params->{ $control->name } );
277             }
278              
279              
280              
281             __PACKAGE__->meta->make_immutable;
282              
283             __END__
284              
285             =pod
286              
287             =encoding UTF-8
288              
289             =head1 NAME
290              
291             Form::Factory::Interface::HTML - Simple HTML form interface
292              
293             =head1 VERSION
294              
295             version 0.022
296              
297             =head1 SYNOPSIS
298              
299             use Form::Factory;
300              
301             my $q = CGI->new;
302             my $html = '<form>';
303              
304             my $form = Form::Factory->new(HTML => {
305             renderer => sub { $html .= join('', @_) },
306             consumer => sub { shift->Vars },
307             });
308              
309             my $action = $form->new_action('MyApp::Action::Foo');
310             $action->consume_and_clean_and_check_and_process( request => $q );
311             $action->render;
312              
313             $html .= '</form>';
314              
315             print $q->header('text/html');
316             print $html;
317              
318             =head1 DESCRIPTION
319              
320             This renders plain HTML forms and consumes value from a hash.
321              
322             =head1 ATTRIBUTES
323              
324             =head2 renderer
325              
326             This is a code reference responsible for printing the HTML elements. The HTML for the controls is passed to this subroutine as a string. The default implementation just prints to the screen.
327              
328             sub { print @_ }
329              
330             =head2 consumer
331              
332             This is a code reference responsible for taking the request object and turning it into a hash reference of values passed in from the HTTP request. The value passed in is the value passed as the C<request> parameter to L<Form::Factory::Action/consume>.
333              
334             =head1 METHODS
335              
336             =head2 new_widget_for_control
337              
338             Returns a L<Form::Factory::Interface::HTML::Widget> implementation for the given control.
339              
340             =head2 new_widget_for_button
341              
342             Returns a widget for a L<Form::Factory::Control::Button>.
343              
344             =head2 new_widget_for_checkbox
345              
346             Returns a widget for a L<Form::Factory::Control::Checkbox>.
347              
348             =head2 new_widget_for_fulltext
349              
350             Returns a widget for a L<Form::Factory::Control::FullText>.
351              
352             =head2 new_widget_for_password
353              
354             Returns a widget for a L<Form::Factory::Control::Password>.
355              
356             =head2 new_widget_for_selectmany
357              
358             Returns a widget for a L<Form::Factory::Control::SelectMany>.
359              
360             =head2 new_widget_for_selectone
361              
362             Returns a widget for a L<Form::Factory::Control::SelectOne>.
363              
364             =head2 new_widget_for_text
365              
366             Returns a widget for a L<Form::Factory::Control::Text>.
367              
368             =head2 new_widget_for_value
369              
370             Returns a widget for a L<Form::Factory::Control::Value>.
371              
372             =head2 render_control
373              
374             Renders the widget for the given control.
375              
376             =head2 consume_control
377              
378             Consumes values using the widget for the given control.
379              
380             =head1 CAVEATS
381              
382             When I initially implemented this, using the widget classes made sense. However, the API has changed in some subtle ways since then. Originally, widgets were a required piece of the factory API, but they are not anymore. As such, they don't make nearly as much sense as they once did.
383              
384             They will probably be removed in a future release.
385              
386             =head1 SEE ALSO
387              
388             L<Form::Factory::Interface>
389              
390             =head1 AUTHOR
391              
392             Andrew Sterling Hanenkamp <hanenkamp@cpan.org>
393              
394             =head1 COPYRIGHT AND LICENSE
395              
396             This software is copyright (c) 2015 by Qubling Software LLC.
397              
398             This is free software; you can redistribute it and/or modify it under
399             the same terms as the Perl 5 programming language system itself.
400              
401             =cut