package HTML::Widget::Element; use warnings; use strict; use base qw/HTML::Widget::Accessor Class::Data::Accessor/; use HTML::Element; use HTML::Widget::Container; use NEXT; use Carp qw/croak/; __PACKAGE__->mk_classaccessor( container_class => 'HTML::Widget::Container' ); __PACKAGE__->mk_accessors(qw/name passive allow_filter allow_constraint/); __PACKAGE__->mk_attr_accessors(qw/class/); =head1 NAME HTML::Widget::Element - Element Base Class =head1 SYNOPSIS my $e = $widget->element( $type, $name, {disabled => 'disabled'} ); $e->name('bar'); $e->class('foo'); =head1 DESCRIPTION Element Base Class. =head1 METHODS =head2 new =head2 attributes =head2 attrs Arguments: %attributes Arguments: \%attributes Return Value: $element Arguments: none Return Value: \%attributes Accepts either a list of key/value pairs, or a hash-ref. $e->attributes( $key => $value ); $e->attributes( { $key => $value } ); Returns the C<$element> object, to allow method chaining. As of v1.10, passing a hash-ref no longer deletes current attributes, instead the attributes are added to the current attributes hash. This means the attributes hash-ref can no longer be emptied using C<< $e->attributes( { } ); >>. Instead, you may use C<< %{ $e->attributes } = (); >>. As a special case, if no arguments are passed, the return value is a hash-ref of attributes instead of the object reference. This provides backwards compatability to support: $e->attributes->{key} = $value; L is an alias for L. =head2 container Arguments: \%attributes Return Value: $container Creates a new $container_class. Defaults to L. =cut sub container { my ( $self, $attributes ) = @_; my $class = $self->container_class || 'HTML::Widget::Container'; my $file = $class . ".pm"; $file =~ s{::}{/}g; eval { require $file }; croak "Unable to load element container class $class: $@" if $@; return $class->new( { passive => $self->passive, %$attributes } ); } =head2 id Arguments: $widget Return Value: $id Creates a element id. =cut sub id { my ( $self, $w, $id ) = @_; my $name = $self->name; return unless defined($name) || defined($id); return $w->name . '_' . ( $id || $self->name ); } =head2 init Arguments: $widget Called once when process() gets called for the first time. =cut sub init { } =head2 mk_error Arguments: $widget, \@errors Return Value: $error Creates a new L. =cut sub mk_error { my ( $self, $w, $errors ) = @_; return if ( !$w->{empty_errors} && ( !defined($errors) || !scalar(@$errors) ) ); my $no_render_count = 0; $no_render_count += $_->no_render ? 1 : 0 for @$errors; return if !$w->{empty_errors} && $no_render_count == scalar @$errors; my $id = $self->attributes->{id} || $self->id($w); my $cont_id = $id . '_errors'; my $container = HTML::Element->new( 'span', id => $cont_id, class => 'error_messages' ); for my $error (@$errors) { next if !$w->{empty_errors} && $error->no_render; my $e_id = $id . '_error_' . lc( $error->{type} ); my $e_class = lc( $error->{type} . '_errors' ); my $e = HTML::Element->new( 'span', id => $e_id, class => $e_class ); $e->push_content( $error->{message} ); $container->push_content($e); } return $container; } =head2 mk_input Arguments: $widget, \%attributes, \@errors Return Value: $input_tag Creates a new input tag. =cut sub mk_input { my ( $self, $w, $attrs, $errors ) = @_; return $self->mk_tag( $w, 'input', $attrs, $errors ); } =head2 mk_tag Arguments: $widget, $tagtype, \%attributes, \@errors Return Value: $element_tag Creates a new tag. =cut sub mk_tag { my ( $self, $w, $tag, $attrs, $errors ) = @_; my $e = HTML::Element->new($tag); my $id = $self->attributes->{id} || $self->id($w); my $type = ref $self; $type =~ s/^HTML::Widget::Element:://; $type =~ s/::/_/g; $self->attributes->{class} ||= lc($type); $e->attr( id => $id ) unless $self->attributes->{id} || $w->{explicit_ids}; $e->attr( name => $self->name ); for my $key ( keys %$attrs ) { my $value = $attrs->{$key}; $e->attr( $key, $value ) if defined $value; } $e->attr( $_ => ${ $self->attributes }{$_} ) for ( keys %{ $self->attributes } ); return $e; } =head2 mk_label Arguments: $widget, $name, $comment, \@errors Return Value: $label_tag Creates a new label tag. =cut sub mk_label { my ( $self, $w, $name, $comment, $errors ) = @_; return unless defined $name; my $for = $self->attributes->{id} || $self->id($w); my $id = $for . '_label'; my $e = HTML::Element->new( 'label', for => $for, id => $id ); if ($errors) { $e->attr( 'class' => 'labels_with_errors' ); } $e->push_content($name); if ($comment) { my $c = HTML::Element->new( 'span', id => "$for\_comment", class => 'label_comments' ); $c->push_content($comment); $e->push_content($c); } return $e; } =head2 name Arguments: $name Return Value: $name Contains the element name. =head2 passive Arguments: $bool Return Value: $bool Defines if element gets automatically rendered. =head2 prepare Arguments: $widget Called whenever C<< $widget->process >> gets called, before C<< $element->process >>. =cut sub prepare { } =head2 process Arguments: \%params, \@uploads Return Value: \@errors Called whenever C<< $widget->process >> is called. Returns an arrayref of L objects. =cut sub process { } =head2 containerize Arguments: $widget, $value, \@errors Return Value: $container_tag Containerize the element, label and error for later rendering. Uses L by default, but this can be over-ridden on a class or instance basis via L. =cut sub containerize { } =head2 container_class Arguments: $class Return Value: $class Contains the class to use for contain the element which then get rendered. Defaults to L. C can be set at a class or instance level: HTML::Widget::Element->container_class('My::Container'); # Override default to custom class HTML::Widget::Element::Password->container_class(undef); # Passwords use the default class $w->element('Textfield')->name('foo')->container_class->('My::Other::Container'); # This element only will use My::Other::Container to render =cut sub container_class { my ($self) = shift; if ( not $_[0] and @_ >= 1 ) { delete $self->{container_class}; } return $self->_container_class_accessor(@_); } =head2 find_elements Return Value: \@elements For non-block-container elements, simply returns a one-element list containing this element. =cut sub find_elements { return (shift); } =head2 new =cut sub new { return shift->NEXT::new(@_)->allow_filter(1)->allow_constraint(1); } =head2 allow_filter Used by C<< $widget->filter_all >>. If false, the filter won't be added. Default true. =head2 allow_constraint Used by C<< $widget->constraint_all >>. If false, the filter won't be added. Default true. =head1 AUTHOR Sebastian Riedel, C =head1 LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1;