1package HTML::FormHandler::Render::Simple;
2# ABSTRACT: simple rendering role
3$HTML::FormHandler::Render::Simple::VERSION = '0.40068';
4use Moose::Role;
5
6requires( 'sorted_fields', 'field' );
7
8use HTML::FormHandler::Render::Util ('process_attrs', 'ucc_widget');
9
10
11
12sub render {
13    my $self   = shift;
14    my $output = $self->render_start;
15
16    $output .= $self->render_form_errors;
17
18    foreach my $field ( $self->sorted_fields ) {
19        $output .= $self->render_field($field);
20    }
21
22    $output .= $self->render_end;
23    return $output;
24}
25
26
27sub render_form_errors {
28    my $self = shift;
29
30    return '' unless $self->has_form_errors;
31    my $output = "\n<div class=\"form_errors\">";
32    $output .= qq{\n<span class="error_message">$_</span>}
33        for $self->all_form_errors;
34    $output .= "\n</div>";
35    return $output;
36}
37
38sub render_field {
39    my ( $self, $field ) = @_;
40
41    if ( ref( \$field ) eq 'SCALAR' ) {
42        $field = $self->field($field);
43    }
44    die "must pass field to render_field"
45        unless ( defined $field && $field->isa('HTML::FormHandler::Field') );
46    # widgets should be in camel case, since they are Perl package names
47    my $widget = ucc_widget($field->widget);
48    return '' if $widget eq 'no_render';
49    my $rendered_field;
50    my $form_render = 'render_' . $widget;
51    if ( $self->can($form_render) ) {
52        $rendered_field = $self->$form_render($field);
53    }
54    elsif ( $field->can('render') ) {
55        $rendered_field = $field->render;
56    }
57    else {
58        die "No widget method found for '$widget' in H::F::Render::Simple";
59    }
60    return $self->wrap_field( $field, $rendered_field );
61}
62
63sub wrap_field {
64    my ( $self, $field, $rendered_field ) = @_;
65
66    return "\n$rendered_field" if $field->uwrapper eq 'none';
67    return "\n$rendered_field" if ! $field->do_wrapper;
68
69    my $output = "\n";
70
71    my $wrapper_tag = $field->get_tag('wrapper_tag');
72    $wrapper_tag ||= $field->has_flag('is_repeatable') ? 'fieldset' : 'div';
73    my $attrs = process_attrs($field->wrapper_attributes);
74
75    $output .= qq{<$wrapper_tag$attrs>};
76    if( $wrapper_tag eq 'fieldset' ) {
77        $output .= '<legend>' . $field->loc_label . '</legend>';
78    }
79    elsif ( ! $field->get_tag('label_none') && $field->do_label && length( $field->label ) > 0 ) {
80        $output .= "\n" . $self->render_label($field);
81    }
82
83    $output .= "\n$rendered_field";
84    $output .= qq{\n<span class="error_message">$_</span>}
85        for $field->all_errors;
86
87    $output .= "\n</$wrapper_tag>";
88
89    return "$output";
90}
91
92sub render_text {
93    my ( $self, $field ) = @_;
94    my $output = '<input type="' . $field->input_type . '" name="';
95    $output .= $field->html_name . '"';
96    $output .= ' id="' . $field->id . '"';
97    $output .= ' size="' . $field->size . '"' if $field->size;
98    $output .= ' maxlength="' . $field->maxlength . '"' if $field->maxlength;
99    $output .= ' value="' . $field->html_filter($field->fif) . '"';
100    $output .= process_attrs($field->element_attributes);
101    $output .= ' />';
102    return $output;
103}
104
105sub render_password {
106    my ( $self, $field ) = @_;
107    my $output = '<input type="password" name="';
108    $output .= $field->html_name . '"';
109    $output .= ' id="' . $field->id . '"';
110    $output .= ' size="' . $field->size . '"' if $field->size;
111    $output .= ' maxlength="' . $field->maxlength . '"' if $field->maxlength;
112    $output .= ' value="' . $field->html_filter($field->fif) . '"';
113    $output .= process_attrs($field->element_attributes);
114    $output .= ' />';
115    return $output;
116}
117
118sub render_hidden {
119    my ( $self, $field ) = @_;
120    my $output = '<input type="hidden" name="';
121    $output .= $field->html_name . '"';
122    $output .= ' id="' . $field->id . '"';
123    $output .= ' value="' . $field->html_filter($field->fif) . '"';
124    $output .= process_attrs($field->element_attributes);
125    $output .= ' />';
126    return $output;
127}
128
129sub render_select {
130    my ( $self, $field ) = @_;
131
132    my $multiple = $field->multiple;
133    my $id = $field->id;
134    my $output = '<select name="' . $field->html_name . '"';
135    $output .= qq{ id="$id"};
136    $output .= ' multiple="multiple"' if $multiple == 1;
137    $output .= ' size="' . $field->size . '"' if $field->size;
138    my $html_attributes = process_attrs($field->element_attributes);
139    $output .= $html_attributes;
140    $output .= '>';
141    my $index = 0;
142    if( defined $field->empty_select ) {
143        $output .= '<option value="">' . $field->_localize($field->empty_select) . '</option>';
144    }
145    my $fif = $field->fif;
146    my %fif_lookup;
147    @fif_lookup{@$fif} = () if $multiple;
148    foreach my $option ( @{ $field->{options} } ) {
149        my $value = $option->{value};
150        $output .= '<option value="'
151            . $field->html_filter($value)
152            . qq{" id="$id.$index"};
153        if( defined $option->{disabled} && $option->{disabled} ) {
154            $output .= ' disabled="disabled"';
155        }
156        if ( defined $fif ) {
157            if ( $multiple && exists $fif_lookup{$value} ) {
158                $output .= ' selected="selected"';
159            }
160            elsif ( $fif eq $value ) {
161                $output .= ' selected="selected"';
162            }
163        }
164        $output .= $html_attributes;
165        my $label = $option->{label};
166        $label = $field->_localize($label) if $field->localize_labels;
167        $output .= '>' . ( $field->html_filter($label) ) . '</option>';
168        $index++;
169    }
170    $output .= '</select>';
171    return $output;
172}
173
174sub render_checkbox {
175    my ( $self, $field ) = @_;
176
177    my $output = '<input type="checkbox" name="' . $field->html_name . '"';
178    $output .= ' id="' . $field->id . '"';
179    $output .= ' value="' . $field->html_filter($field->checkbox_value) . '"';
180    $output .= ' checked="checked"' if $field->fif eq $field->checkbox_value;
181    $output .= process_attrs($field->element_attributes);
182    $output .= ' />';
183    return $output;
184}
185
186sub render_radio_group {
187    my ( $self, $field ) = @_;
188
189    my $output = " <br />";
190    my $index  = 0;
191    foreach my $option ( @{ $field->options } ) {
192        my $id = $field->id . ".$index";
193        $output .= qq{<label for="$id"><input type="radio" value="} . $field->html_filter($option->{value}) . '"';
194        $output .= ' name="' . $field->html_name . '" id="' . "$id\"";
195        $output .= ' checked="checked"' if $option->{value} eq $field->fif;
196        $output .= ' />';
197        $output .= $field->html_filter($option->{label}) . '</label><br />';
198        $index++;
199    }
200    return $output;
201}
202
203sub render_textarea {
204    my ( $self, $field ) = @_;
205    my $fif  = $field->fif || '';
206    my $id   = $field->id;
207    my $cols = $field->cols || 10;
208    my $rows = $field->rows || 5;
209    my $name = $field->html_name;
210
211    my $output =
212        qq(<textarea name="$name" id="$id" )
213        . process_attrs($field->element_attributes)
214        . qq(rows="$rows" cols="$cols">)
215        . $field->html_filter($fif)
216        . q(</textarea>);
217
218    return $output;
219}
220
221sub render_upload {
222    my ( $self, $field ) = @_;
223
224    my $output;
225    $output = '<input type="file" name="';
226    $output .= $field->html_name . '"';
227    $output .= ' id="' . $field->id . '"';
228    $output .= process_attrs($field->element_attributes);
229    $output .= ' />';
230    return $output;
231}
232
233sub render_label {
234    my ( $self, $field ) = @_;
235
236    my $attrs = process_attrs( $field->label_attributes );
237    my $label = $field->html_filter($field->loc_label);
238    $label .= $field->get_tag('label_after')
239        if( $field->tag_exists('label_after') );
240    my $label_tag = $field->tag_exists('label_tag') ? $field->get_tag('label_tag') : 'label';
241    return qq{<$label_tag$attrs for="} . $field->id . qq{">$label</$label_tag>};
242}
243
244sub render_compound {
245    my ( $self, $field ) = @_;
246
247    my $output = '';
248    foreach my $subfield ( $field->sorted_fields ) {
249        $output .= $self->render_field($subfield);
250    }
251    return $output;
252}
253
254sub render_submit {
255    my ( $self, $field ) = @_;
256
257    my $output = '<input type="submit" name="';
258    $output .= $field->html_name . '"';
259    $output .= ' id="' . $field->id . '"';
260    $output .= process_attrs($field->element_attributes);
261    $output .= ' value="' . $field->html_filter($field->_localize($field->value)) . '" />';
262    return $output;
263}
264
265sub render_reset {
266    my ( $self, $field ) = @_;
267
268    my $output = '<input type="reset" name="';
269    $output .= $field->html_name . '"';
270    $output .= ' id="' . $field->id . '"';
271    $output .= process_attrs($field->element_attributes);
272    $output .= ' value="' . $field->html_filter($field->value) . '" />';
273    return $output;
274}
275
276sub render_captcha {
277    my ( $self, $field ) = @_;
278
279    my $output .= '<img src="' . $self->captcha_image_url . '"/>';
280    $output .= '<input id="' . $field->id . '" name="';
281    $output .= $field->html_name . '"/>';
282    return $output;
283}
284
285
286use namespace::autoclean;
2871;
288
289__END__
290
291=pod
292
293=encoding UTF-8
294
295=head1 NAME
296
297HTML::FormHandler::Render::Simple - simple rendering role
298
299=head1 VERSION
300
301version 0.40068
302
303=head1 SYNOPSIS
304
305This is a Moose role that is an example of a simple rendering
306routine for L<HTML::FormHandler>. It's here as an example of
307how to write a custom renderer in one package, if you prefer
308that to using the widgets. It won't always be updated with
309improvements by default, because it was becoming a lot of work to update
310the rendering in multiple places.
311
312For a 'MyApp::Form::Renderer' which you've created and modified,
313in your Form class:
314
315   package MyApp::Form::Silly;
316   use Moose;
317   extends 'HTML::FormHandler::Model::DBIC';
318   with 'MyApp::Form::Renderers';
319
320In a template:
321
322   [% form.render %]
323
324The widgets are rendered with C<< $field->render >>; rendering
325routines from a class like this use C<< $form->render_field('field_name') >>
326to render individual fields:
327
328   [% form.render_field( 'title' ) %]
329
330=head1 DESCRIPTION
331
332This role provides HTML output routines for the 'widget' types
333defined in the provided FormHandler fields. Each 'widget' name
334has a 'widget_$name' method here.
335
336These widget routines output strings with HTML suitable for displaying
337form fields.
338
339The widget for a particular field can be defined in the form. You can
340create additional widget routines in your form for custom widgets.
341
342The fill-in-form values ('fif') are cleaned with the 'render_filter'
343method of the base field class. You can change the filter to suit
344your own needs: see L<HTML::FormHandler::Manual::Rendering>
345
346=head2 render
347
348To render all the fields in a form in sorted order (using
349'sorted_fields' method).
350
351=head2 render_start, render_end
352
353These use the methods in L<HTML::FormHandler::Widget::Form::Simple> now. If
354you want to customize them, copy them to your own package.
355
356Will render the beginning and ending <form> tags and fieldsets. Allows for easy
357splitting up of the form if you want to hand-render some of the fields.
358
359   [% form.render_start %]
360   [% form.render_field('title') %]
361   <insert specially rendered field>
362   [% form.render_field('some_field') %]
363   [% form.render_end %]
364
365=head2 render_field
366
367Render a field passing in a field object or a field name
368
369   $form->render_field( $field )
370   $form->render_field( 'title' )
371
372=head2 render_text
373
374Output an HTML string for a text widget
375
376=head2 render_password
377
378Output an HTML string for a password widget
379
380=head2 render_hidden
381
382Output an HTML string for a hidden input widget
383
384=head2 render_select
385
386Output an HTML string for a 'select' widget, single or multiple
387
388=head2 render_checkbox
389
390Output an HTML string for a 'checkbox' widget
391
392=head2 render_radio_group
393
394Output an HTML string for a 'radio_group' selection widget.
395This widget should be for a field that inherits from 'Select',
396since it requires the existence of an 'options' array.
397
398=head2 render_textarea
399
400Output an HTML string for a textarea widget
401
402=head2 render_compound
403
404Renders field with 'compound' widget
405
406=head2 render_submit
407
408Renders field with 'submit' widget
409
410=head1 AUTHOR
411
412FormHandler Contributors - see HTML::FormHandler
413
414=head1 COPYRIGHT AND LICENSE
415
416This software is copyright (c) 2017 by Gerda Shank.
417
418This is free software; you can redistribute it and/or modify it under
419the same terms as the Perl 5 programming language system itself.
420
421=cut
422