Skip to content

Commit

Permalink
better form-horizontal Bootstrap 3.0 support
Browse files Browse the repository at this point in the history
  • Loading branch information
gshank committed Oct 17, 2013
1 parent e338f29 commit 69f74aa
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 12 deletions.
9 changes: 9 additions & 0 deletions lib/HTML/FormHandler/Field.pm
Original file line number Diff line number Diff line change
Expand Up @@ -950,11 +950,15 @@ sub element_wrapper_attributes {
# local copy of label_attr
my $attr = {};
my $class = [@{$self->element_wrapper_class}];
$self->add_standard_element_wrapper_classes( $result, $class );
$attr->{class} = $class if @$class;
# call form hook
my $mod_attr = $self->form->html_attributes($self, 'element_wrapper', $attr, $result) if $self->form;
return ref($mod_attr) eq 'HASH' ? $mod_attr : $attr;
}
sub add_standard_element_wrapper_classes {
my ( $self, $result, $class ) = @_;
}

sub attributes { shift->element_attributes(@_) }
sub element_attributes {
Expand Down Expand Up @@ -996,12 +1000,17 @@ sub label_attributes {
# local copy of label_attr
my $attr = {%{$self->label_attr}};
my $class = [@{$self->label_class}];
$self->add_standard_label_classes($result, $class);
$attr->{class} = $class if @$class;
# call form hook
my $mod_attr = $self->form->html_attributes($self, 'label', $attr, $result) if $self->form;
return ref($mod_attr) eq 'HASH' ? $mod_attr : $attr;
}

sub add_standard_label_classes {
my ( $self, $result, $class ) = @_;
}

sub wrapper_attributes {
my ( $self, $result ) = @_;
$result ||= $self->result;
Expand Down
1 change: 1 addition & 0 deletions lib/HTML/FormHandler/Field/Checkbox.pm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ has 'checkbox_value' => ( is => 'rw', default => 1 );
has '+input_without_param' => ( default => 0 );
has '+type_attr' => ( default => 'checkbox' );
has 'option_label' => ( is => 'rw' );
has 'option_wrapper' => ( is => 'rw' );

sub value {
my $field = shift;
Expand Down
1 change: 1 addition & 0 deletions lib/HTML/FormHandler/Field/Select.pm
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ sub build_options { [] }
has 'options_from' => ( isa => 'Str', is => 'rw', default => 'none' );
has 'do_not_reload' => ( isa => 'Bool', is => 'ro' );
has 'no_option_validation' => ( isa => 'Bool', is => 'rw' );
has 'option_wrapper' => ( is => 'rw' );

sub BUILD {
my $self = shift;
Expand Down
98 changes: 91 additions & 7 deletions lib/HTML/FormHandler/Widget/Wrapper/Base.pm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ HTML::FormHandler::Widget::Wrapper::Base
Provides several common methods for wrapper widgets, including
'do_render_label' and 'wrap_checkbox'.
Implements the checkbox 'option_wrapper' rendering:
b3_label_left
b3_label_right
b3_label_left_inline
label_left
label_right
no_wrapped_label
=cut

sub do_render_label {
Expand All @@ -36,18 +45,25 @@ sub do_render_label {
}

sub wrap_checkbox {
my ( $self, $result, $rendered_widget, $default_wrapper ) = @_;

my $option_wrapper = $self->option_wrapper || $default_wrapper;
if ( $option_wrapper && $option_wrapper ne 'standard' ) {
return $self->$option_wrapper($result, $rendered_widget);
}
else {
return $self->standard_wrap_checkbox($result, $rendered_widget);
}

}

sub standard_wrap_checkbox {
my ( $self, $result, $rendered_widget ) = @_;

return $rendered_widget
if( $self->get_tag('no_wrapped_label' ) );

my $label = $self->option_label || '';
if( $label eq '' && ! $self->do_label ) {
$label = $self->html_filter($self->loc_label);
}
elsif( $label ne '' ) {
$label = $self->html_filter($self->_localize($label));
}
my $label = $self->get_checkbox_label;
my $id = $self->id;
my $for = qq{ for="$id"};

Expand All @@ -70,6 +86,74 @@ sub wrap_checkbox {
return $output;
}

sub get_checkbox_label {
my $self = shift;

my $label = $self->option_label || '';
if( $label eq '' && ! $self->do_label ) {
$label = $self->html_filter($self->loc_label);
}
elsif( $label ne '' ) {
$label = $self->html_filter($self->_localize($label));
}
return $label;
}

sub b3_label_left {
my ( $self, $result, $rendered_widget ) = @_;

my $label = $self->get_checkbox_label;
my $id = $self->id;
my $output = qq{<div class="checkbox">};
$output .= qq{<label for="$id">\n$label\n$rendered_widget</label>};
$output .= qq{</div>};
return $output;
}

sub b3_label_left_inline {
my ( $self, $result, $rendered_widget ) = @_;

my $label = $self->get_checkbox_label;
my $id = $self->id;
my $output .= qq{<label class="checkbox-inline" for="$id">\n$label\n$rendered_widget</label>};
return $output;
}

sub b3_label_right {
my ( $self, $result, $rendered_widget ) = @_;

my $label = $self->get_checkbox_label;
my $id = $self->id;
my $output = qq{<div class="checkbox">};
$output .= qq{<label for="$id">$rendered_widget\n$label\n</label>};
$output .= qq{</div>};
return $output;
}

sub label_left {
my ( $self, $result, $rendered_widget ) = @_;

my $label = $self->get_checkbox_label;
my $id = $self->id;
my $output .= qq{<label class="checkbox" for="$id">\n$label\n$rendered_widget</label>};
return $output;
}

sub label_right {
my ( $self, $result, $rendered_widget ) = @_;

my $label = $self->get_checkbox_label;
my $id = $self->id;
my $output .= qq{<label class="checkbox" for="$id">$rendered_widget\n$label\n</label>};
return $output;
}

sub no_wrapped_label {
my ( $self, $result, $rendered_widget ) = @_;
return $rendered_widget;
}


# for compatibility with older code
sub render_label {
my $self = shift;
Expand Down
2 changes: 1 addition & 1 deletion lib/HTML/FormHandler/Widget/Wrapper/Bootstrap.pm
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ sub wrap_field {
$rendered_widget = $self->do_prepend_append($rendered_widget);
}
elsif( lc $self->widget eq 'checkbox' ) {
$rendered_widget = $self->wrap_checkbox($result, $rendered_widget, 'label')
$rendered_widget = $self->wrap_checkbox($result, $rendered_widget)
}

$output .= "\n$rendered_widget";
Expand Down
24 changes: 22 additions & 2 deletions lib/HTML/FormHandler/Widget/Wrapper/Bootstrap3.pm
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ sub wrap_field {
$output .= $self->get_tag('before_element');

# the controls div; used to have 'controls' class. Now it comes from
# the 'element_wrapper_class'
# the 'element_wrapper_class'. Used for column layout.
my $ew_attr = $self->element_wrapper_attributes($result);
my $element_wrapper_attrs = process_attrs( $ew_attr );
$output .= qq{\n<div$element_wrapper_attrs>}
Expand All @@ -78,7 +78,7 @@ sub wrap_field {
$rendered_widget = $self->do_prepend_append($rendered_widget);
}
elsif( lc $self->widget eq 'checkbox' ) {
$rendered_widget = $self->wrap_checkbox($result, $rendered_widget, 'label')
$rendered_widget = $self->wrap_checkbox($result, $rendered_widget, 'b3_label_left')
}

$output .= "\n$rendered_widget";
Expand Down Expand Up @@ -125,6 +125,26 @@ sub add_standard_wrapper_classes {
# TODO: has-success?
}

sub add_standard_label_classes {
my ( $self, $result, $class ) = @_;
if ( my $classes = $self->form->get_tag('layout_classes') ) {
push @$class, @{$classes->{label_class}}
if exists $classes->{label_class};
}
}

sub add_standard_element_wrapper_classes {
my ( $self, $result, $class ) = @_;
if ( my $classes = $self->form->get_tag('layout_classes') ) {
push @$class, @{$classes->{element_wrapper_class}}
if exists $classes->{element_wrapper_class};
if ( exists $classes->{no_label_element_wrapper_class} &&
( ! $self->do_label || $self->type_attr eq 'checkbox' )) {
push @$class, @{$classes->{no_label_element_wrapper_class}};
}
}
}

sub wrap_checkbox {
my ( $self, $result, $rendered_widget ) = @_;

Expand Down
4 changes: 2 additions & 2 deletions lib/HTML/FormHandler/Widget/Wrapper/Simple.pm
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ sub wrap_field {
$label_tag = 'legend' if $wrapper_tag eq 'fieldset';
}
# write label; special processing for checkboxes
$rendered_widget = $self->wrap_checkbox($result, $rendered_widget, $label_tag)
$rendered_widget = $self->wrap_checkbox($result, $rendered_widget)
if ( lc $self->widget eq 'checkbox' );
$output .= "\n" . $self->do_render_label($result, $label_tag )
$output .= "\n" . $self->do_render_label($result, $label_tag)
if $self->do_label;
# append 'before_element'
$output .= $self->get_tag('before_element');
Expand Down
126 changes: 126 additions & 0 deletions t/bootstrap3/horiz.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use strict;
use warnings;
use Test::More;
use HTML::FormHandler::Test;

use_ok('HTML::FormHandler::Widget::Wrapper::Bootstrap3');

{
package MyApp::Form::Test;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';

has '+widget_wrapper' => ( default => 'Bootstrap3' );
sub build_form_tags {{
'layout_classes' => {
label_class => ['col-lg-2'],
element_wrapper_class => ['col-lg-10'],
no_label_element_wrapper_class => ['col-lg-offset-2'],
},
}}
has_field 'foo' => ( required => 1 );
has_field 'bar';
has_field 'active' => ( type => 'Checkbox' );
has_field 'vegetables' => ( type => 'Multiple', widget => 'RadioGroup' );
sub options_vegetables {
return (
1 => 'lettuce',
2 => 'broccoli',
3 => 'carrots',
4 => 'peas',
);
}
has_field 'save' => ( type => 'Submit' );

}

my $form = MyApp::Form::Test->new;
ok( $form, 'form builds' );

my $expected = '
<div class="form-group">
<label class="col-lg-2 control-label" for="foo">Foo</label>
<div class="col-lg-10">
<input class="form-control" id="foo" name="foo" type="text" value="" />
</div>
</div>
';
my $rendered = $form->field('foo')->render;
is_html( $rendered, $expected, 'foo renders ok' );

$expected = '
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<div class="checkbox">
<label for="active">
<input id="active" name="active" type="checkbox" value="1" /> Active
</label>
</div>
</div>
</div>
';
$rendered = $form->field('active')->render;
is_html( $rendered, $expected, 'checkbox renders ok' );

$expected = '
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<input id="save" name="save" type="submit" value="Save" />
</div>
</div>
';
$rendered = $form->field('save')->render;
is_html( $rendered, $expected, 'submit button renders ok' );

$expected = '
<div class="form-group">
<label class="col-lg-2 control-label" for="vegetables">Vegetables</label>
<div class="col-lg-10">
<div class="radio">
<label class="radio" for="vegetables.0">
<input id="vegetables.0" name="vegetables" type="radio" value="1" />
lettuce
</label>
</div>
<div class="radio">
<label class="radio" for="vegetables.1">
<input id="vegetables.1" name="vegetables" type="radio" value="2" />
broccoli
</label>
</div>
<div class="radio">
<label class="radio" for="vegetables.2">
<input id="vegetables.2" name="vegetables" type="radio" value="3" />
carrots
</label>
</div>
<div class="radio">
<label class="radio" for="vegetables.3">
<input id="vegetables.3" name="vegetables" type="radio" value="4" />
peas
</label>
</div>
</div>
</div>
';
$rendered = $form->field('vegetables')->render;
is_html( $rendered, $expected, 'radio group renders' );

# after processing
$form->process( params => { bar => 'bar' } );

$expected = '
<div class="form-group has-error">
<label class="col-lg-2 control-label" for="foo">Foo</label>
<div class="col-lg-10">
<input class="has-error form-control" id="foo" name="foo" type="text" value="" />
<span class="help-block">Foo field is required</span>
</div>
</div>
';
$rendered = $form->field('foo')->render;
is_html( $rendered, $expected, 'foo renders ok with error' );



done_testing;

0 comments on commit 69f74aa

Please sign in to comment.