# Copyright (c) 1999-2007 bivio Software, Inc. All rights reserved. # # Visit http://www.bivio.biz for more info. # # This library is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2.1 of the # License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, you may get a copy from: # http://www.opensource.org/licenses/lgpl-license.html # # $Id: Form.pm,v 2.19 2009/11/28 03:06:18 nagler Exp $ package Bivio::UI::HTML::Widget::Form; use strict; #TODO: Probably should subclass Tag, but cell_end_form is messy use Bivio::Base 'HTMLWidget.ControlBase'; use Bivio::HTML; # C is an HTML C
tag surrounding # a widget, which is usually a # L, # but might be a # L. # The widget or its children should contain a # L. # # No special formatting is implemented. For layout, use, e.g. # # # # action : string [$req->format_uri] # # Literal text to use as # the C attribute of the C tag. # # action : Bivio::Agent::TaskId [$req->format_uri] # # Task to format_stateless_uri. # # action : array_ref [$req->format_uri] # # Dereferenced, passed to C<$source-Eget_widget_value>, and # used as the C attribute of the C tag. # # cell_end_form : boolean [0] # # Same value as L. # Used to set default for I. # # end_tag : boolean [see below] # # Renders the C end tag if true. Default is true unless # I is true iwc is set to false. See # L. # # form_class : Bivio::Biz::FormModel (inherited, get_request) # # The simple name of the class or the mapped name, e.g. I. # This value is computed from I if it can be. # # form_end_cell : boolean [0] # # Opposite of I. Will end the cell as well as the form. # Do not set I or I with this value. You should # set I on a Grid to false. # # form_method : string [POST] (inherited) # # The value to be passed to the C attribute of the C tag. # # form_model : array_ref [*computed*] (required, inherited, get_request) # # B. Which form are we dealing with. # Use I. # # form_name : string [fnNNN] (inherited) # # Name of the form which can be used within JavaScript. Set dynamically # to CI where I is globally assigned starting at 1. # The value is set on the I, so it can be used by fields. # # link_target : string [] (inherited) # # The value to be passed to the C attribute of C tag. # # value : Bivio::UI::Widget (required) # # How to render the form. Usually a # L # or # L. our($VERSION) = sprintf('%d.%02d', q$Revision: 2.19 $ =~ /\d+/g); my($_VS) = b_use('UIHTML.ViewShortcuts'); my($_HTML) = b_use('Bivio.HTML'); my($_IDI) = __PACKAGE__->instance_data_index; my($_FORM_NAME_INDEX) = 0; sub initialize { my($self, $source) = @_; # Initializes static information. my($fields) = $self->[$_IDI]; return if $fields->{prefix}; $self->initialize_attr(want_timezone => 1, $source); $self->initialize_attr(want_hidden_fields => 1, $source); # Compute form_class from form_model or vice-versa my($class) = $self->unsafe_get('form_class'); if ($class && $class !~ /:/) { # lookup the full class name $class = ref(Bivio::Biz::Model->get_instance($class)); $self->put(form_class => $class); } my($model) = $self->unsafe_get('form_model'); if ($class && $model) { # fall through } elsif ($model) { # DEPRECATED $class = $model->[0]; $self->put(form_class => $class); } elsif ($class) { $model = ['->req', $class]; $self->put(form_model => $model); } else { die('form_class not set'); } die($class, ': invalid or not set form_class') unless UNIVERSAL::isa($class, 'Bivio::Biz::FormModel'); $fields->{class} = $class; # Compute form_name my($name) = $self->ancestral_get('form_name', undef); if ($name) { # Should be at least two chars starting with a letter die($name, ': invalid form_name') unless $name =~ /^[a-z]\w+$/i; } else { $name = 'fn'.$_FORM_NAME_INDEX++; $self->put(form_name => $name); } $self->initialize_attr( action => [['->get_request'], '->format_uri'], $source); my($a) = $self->get('action'); $self->put(action => [['->get_request'], '->format_stateless_uri', $a]) if $self->is_blessed($a, 'Bivio::Agent::TaskId'); my($p) = 'vs_link_target_as_html($self) . qq{ id="$name" action="}; $fields->{prefix} = $p; $fields->{end_tag} = $self->get_or_default('end_tag', $self->get_or_default('cell_end_form', 0) ? 0 : 1); $fields->{form_end_cell} = $self->get_or_default('form_end_cell', 0); $fields->{value} = $self->get('value'); $fields->{value}->put(parent => $self); $fields->{value}->initialize($source); return shift->SUPER::initialize(@_); } sub internal_new_args { my(undef, $class, $value, $attributes) = @_; # Implements positional argument parsing for L. return '"form_class" attribute must be defined' unless defined($class); return '"value" attribute must be defined' unless defined($value); return { form_class => $class, value => $value, ($attributes ? %$attributes : ()), }; } sub new { my($self) = shift->SUPER::new(@_); # Passes I and I as attributes. And optionally, set extra # I. # # # Creates a new Form widget using I. $self->[$_IDI] = {}; return $self; } sub control_on_render { my($self, $source, $buffer) = @_; # Render the form. my($fields) = $self->[$_IDI]; my($req) = $source->get_request; my($model) = $req->get_widget_value($fields->{class}); my($action) = ${$self->render_attr('action', $source)}; #TODO: Tightly Coupled with FormModel & Location. Do not propagate form # context when you have a form to store the context in fields. # Context management is hard.... $action =~ s/[&?]fc=[^&=]+//; $$buffer .= $fields->{prefix} . $_HTML->escape_attr_value($action) . '"'; $self->SUPER::control_on_render($source, $buffer); $$buffer .= ' enctype="multipart/form-data"' if $model->get_info('file_fields'); $$buffer .= ">\n"; if ($self->render_simple_attr('want_hidden_fields', $source)) { $_VS->vs_new('TimezoneField')->render($source, $buffer) if $self->render_simple_attr('want_timezone', $source); $$buffer .= _render_hidden($self, $model->get_hidden_field_values); } $fields->{value}->render($source, $buffer); $$buffer .= '' if $fields->{form_end_cell}; $$buffer .= '' if $fields->{end_tag}; return; } sub form_model_for_initialize { my(undef, $widget, $source) = @_; my($fc) = $widget->ancestral_get('form_class'); return $source ? $source->req->get($fc) : $fc->get_instance; } sub _render_hidden { my($self, $values) = @_; return join( '', @{$self->map_by_two( sub { my($k, $v) = @_; return qq{\n}; }, $values, )}, ); } 1;