# ==================================================================== # Copyright (C) 1997,1998 Stephen Farrell # # All rights reserved. This program is free software; you can # redistribute it and/or modify it under the same terms as Perl # itself. # # ==================================================================== # File: Form.pm # Author: Stephen Farrell # Created: August 1997 # Locations: http://www.palefire.org/~sfarrell/TableLayout/ # CVS $Id: Form.pm,v 1.21 1998/09/20 21:06:01 sfarrell Exp $ # ==================================================================== ## =================================================================== ## This is the Form class itself ## =================================================================== ## ## NB: only cells know how to print forms. If you have your own ## spiffy componentcontainer that you want to contain a form, you have ## to be very careful (it's best to just stick it into a cell or ## table--which puts it in a cell for you). If you decide you know ## what you're doing and want to not heed this advice, then know the ## following: You probably do NOT want to make the form be one of ## tl_components, and you must call _print_end(). And maybe some ## other stuff. Heads up. ## package HTML::TableLayout::Form; use HTML::TableLayout::Symbols; @HTML::TableLayout::Form::ISA=qw(HTML::TableLayout::ComponentContainer); use Carp; use strict; sub setMethod { shift->{TL_PARAMS}->{method} = pop } sub getMethod { return shift->{TL_PARAMS}->{method} } sub setAction { shift->{TL_PARAMS}->{action} = pop } sub getAction { return shift->{TL_PARAMS}->{action} } ## ## I think this is the ideal for passCGI... if just a hashref is ## given, then it passes all those values as hidden. If that is given ## plus a list afterwards, then it fills in the values just for the ## members of the list. Additionally, if you put an "=" sign in those ## elements of the list, it replaces the value with the one you ## provided (this can also be accomplished by adding "hidden" fields ## to a cell that contains a form. ## sub passCGI { my ($this, $hashref, @pass) = @_; ## ## We want a *copy* of this hashref because we don't want it ## changing under our feet, and we want to be able to muck with it. ## if (ref $hashref) { my %copy = %$hashref; $this->{passcgi} = \ %copy; } if (ref $pass[0] eq "ARRAY" and scalar(@{ $pass[0] }) > 0) { my @copy = @{ $pass[0] }; $this->{passlist} = \ @copy; } elsif (scalar(@pass) > 0) { $this->{passlist} = \ @pass; } return $this; } ## ## NB: We just get a reference, not a copy. No guarantees that your ## original will not get trampled! In my code, I take care to use ## exists to check if keys exist in the hash... ## sub useData { my ($this, @data) = @_; if (ref $data[0] eq "HASH") { $this->{default_data} = $data[0]; } else { $this->{default_data} = { @data }; } return $this; } ## ## NB: One must be careful when using this insert. Normally it is ## AUTOMAGICALLY called when you insert an object into a cell or ## table. HOWEVER, you CAN choose to insert hidden items directly ## into the form. The deal is that form won't call tl_print() on the ## object, so if it doesn't need tl_print() to be called (such as ## hidden) then it's ok to insert only into the form. I think you'll ## agree this actually makes a kind of sense.... ## sub insert { my ($this, $c) = @_; if ($c->isa("HTML::TableLayout::FormComponent::Hidden")) { if ($this->{passlist}) { ## ## Note we don't check if it is already on the passlist ## this doesn't matter too much because it'll just show up ## twice and both times it'll have the same value--but it'll ## still cause problems! ## push @{ $this->{passlist} }, $c->tl_getName(); } $this->{passcgi}->{$c->tl_getName()} = $c->tl_getValue() || $this->{default_data}->{$c->tl_getName()}; } else { ## ## Note it is not deleted off the passlist--this is your own dang ## problem if you insert things AND add them to the passlist ## delete $this->{passcgi}->{$c->tl_getName()}; } $this->SUPER::insert($c); } ## ## this function can only be called during the tl_setup() phase ## sub getName { my ($this, $force_numeric) = @_; if ($force_numeric or $this->{TL_PARAMS}->{name} eq undef) { return $this->{TL_WINDOW}->_getNumForms() - 1; } else { return $this->{TL_PARAMS}->{name}; } } sub tl_print { my ($this) = @_; my $w = $this->{TL_WINDOW}; $w->i_print(">tl_getParameters()).""); } sub _print_end { my ($this) = @_; my $w = $this->{TL_WINDOW}; my @pass; if ($this->{passlist}) { @pass = @{ $this->{passlist} }; } else { @pass = keys %{ $this->{passcgi} }; } my $k; foreach $k (@pass) { my $v; if ($k =~ s/=(.*)//) { $v = $1; } else { $v = $this->{passcgi}->{$k}; } $w->i_print(">i_print(">{default_data} } ## ## FIXME: this is NOT a full implementation of clone for this class!!! ## # sub clone { # my ($this) = @_; # my $class; # my $clone = HTML::TableLayout::Form->new(); # my %passcgi_copy = %{ $this->{passcgi} }; # my %params_copy = %{ $this->{TL_PARAMS} }; # $clone->{passcgi} = \%passcgi_copy; # $clone->{TL_PARAMS} = \%params_copy; # return $clone; # } ## ## ==================================================================== ## These are the form components ## ==================================================================== ## package HTML::TableLayout::FormComponent; @HTML::TableLayout::FormComponent::ISA=qw(HTML::TableLayout::Component); use HTML::TableLayout::Symbols; sub tl_getName { return shift->{TL_PARAMS}->{name} } sub tl_setName { shift->{TL_PARAMS}->{name} = pop } sub tl_getValue { return shift->{TL_PARAMS}->{value} } sub tl_setValue { shift->{TL_PARAMS}->{value} = pop } sub tl_setDefaultValue { my ($this) = @_; return if $this->{TL_PARAMS}->{value}; die("No form (BUG!) [$this]") unless $this->{TL_FORM}; my $data_hash = $this->{TL_FORM}->_getDefaultData(); return unless exists $data_hash->{$this->{TL_PARAMS}->{name}}; my $v; if ($v = $data_hash->{$this->{TL_PARAMS}->{name}}) { $this->{TL_PARAMS}->{value} = $v; } } sub tl_setup { my ($this) = @_; $this->SUPER::tl_setup(); $this->tl_setDefaultValue(); } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponent::Hidden; use HTML::TableLayout::Symbols; @HTML::TableLayout::FormComponent::Hidden::ISA= qw(HTML::TableLayout::FormComponent); sub tl_init { my $this = shift; my $name = shift; my $value = shift; $this->{visible} = shift; $this->SUPER::tl_init(@_); $this->{TL_PARAMS}->{name} = $name; $this->{TL_PARAMS}->{value} = $value; } ## ## Everything about hidden is handled by the Form itself, using the ## "passcgi" mechanism. ## sub tl_print { my ($this) = @_; if ($this->{visible}) { ## ## This is kind of funky, but a "visible" hidden entry displays the ## value as plain text. ## $this->{TL_WINDOW}->i_print($this->{TL_PARAMS}->{value}); } } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponent::Faux; @HTML::TableLayout::FormComponent::Faux::ISA= qw(HTML::TableLayout::FormComponent); ## ## This behaves like a form component, but it just prints the text ## value; it does not do any other form-like things such as *passing ## it's value*. Use a "visible" Hidden if you want to do this. ## sub tl_init { my $this = shift; my $name = shift; my $value = shift; $this->SUPER::tl_init(@_); $this->{TL_PARAMS}->{name} = $name; $this->{TL_PARAMS}->{value} = shift; } sub tl_print { my ($this) = @_; $this->{TL_WINDOW}->i_print($this->{TL_PARAMS}->{value}); } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponent::InputText; use HTML::TableLayout::Symbols; @HTML::TableLayout::FormComponent::InputText::ISA= qw(HTML::TableLayout::FormComponent); sub tl_print { my ($this) = @_; $this->{TL_WINDOW} ->i_print(">{TL_PARAMS} }).""); } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponent::Button; use HTML::TableLayout::Symbols; @HTML::TableLayout::FormComponent::Button::ISA= qw(HTML::TableLayout::FormComponent); sub tl_print { my ($this) = @_; $this->{TL_WINDOW} ->i_print(">{TL_PARAMS} }).""); } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponent::Checkbox; use HTML::TableLayout::Symbols; @HTML::TableLayout::FormComponent::Checkbox::ISA= qw(HTML::TableLayout::FormComponent); sub tl_print { my ($this) = @_; $this->{TL_WINDOW} ->i_print(">{TL_PARAMS} }).""); } sub tl_setDefaultValue { my ($this) = @_; return if exists $this->{TL_PARAMS}->{checked}; die("No form (BUG!) [$this]") unless $this->{TL_FORM}; my $data_hash = $this->{TL_FORM}->_getDefaultData(); return unless exists $data_hash->{$this->{TL_PARAMS}->{name}}; if (exists $data_hash->{$this->{TL_PARAMS}->{name}} and $data_hash->{$this->{TL_PARAMS}->{name}}) { $this->{TL_PARAMS}->{checked} = undef; } } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponent::Textarea; use HTML::TableLayout::Symbols; @HTML::TableLayout::FormComponent::Textarea::ISA= qw(HTML::TableLayout::FormComponent); sub tl_init { my $this = shift; my $value = shift; $this->SUPER::tl_init(@_); $this->{text} = $value; } sub tl_print { my ($this) = @_; my $w = $this->{TL_WINDOW}; $w->i_print(">{TL_PARAMS} }).">"); $w->f_print($this->{text}); $w->i_print("{TL_WINDOW} ->i_print(">{TL_PARAMS} }).""); } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponent::Submit; use HTML::TableLayout::Symbols; @HTML::TableLayout::FormComponent::Submit::ISA= qw(HTML::TableLayout::FormComponent); ## 99/100 times, you'll just be passing in the value here sub tl_init { my $this = shift; my $value = shift; $this->SUPER::tl_init(@_); (defined $value) and $this->{TL_PARAMS}->{value} = $value; } ## ## I override this b/c chances are, if the value changes, it'll not be ## what was expected. ## sub tl_setDefaultValue { } sub tl_print { my ($this) = @_; die($this->{TL_PARAMS}->{value}) unless $this->{TL_WINDOW}; $this->{TL_WINDOW} ->i_print(">{TL_PARAMS} }).""); } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponentMulti; use HTML::TableLayout::Symbols; use Carp; @HTML::TableLayout::FormComponentMulti::ISA = qw(HTML::TableLayout::ComponentContainer HTML::TableLayout::FormComponent); ## ## FIXME: why is this a ComponentContainer?? ## sub tl_init { my $this = shift; $this->{TL_OPS} = shift; $this->SUPER::tl_init(@_); } sub tl_setup { my ($this) = @_; my ($x, $o, @new_tl_ops); foreach $o (@{ $this->{TL_OPS} }) { $x = (ref $o->[1]) ? $o->[1] : HTML::TableLayout::Component::Text->new($o->[1]); $this->insert($x); push @new_tl_ops, [ $o->[0], $x ]; } $this->{TL_OPS} = \ @new_tl_ops; $this->SUPER::tl_setup(); ## ## if "Default" was passed in as a parameter, then we use that as the ## default, otherwise we fall back on the form's default values. ## if (exists $this->{TL_PARAMS}->{Default}) { $this->{TL_DEFAULT_VALUE} = $this->{TL_PARAMS}->{Default}; delete $this->{TL_PARAMS}->{Default}; } else { ## ## Because of the order of the multiple inheretence, it doesn't find ## the super that does the tl_setDefaults() call on tl_setup(), so ## need to do so here. ## $this->tl_setDefaultValue(); } } sub tl_setDefaultValue { my ($this) = @_; my $data_hash = $this->{TL_FORM}->_getDefaultData(); return unless exists $data_hash->{$this->{TL_PARAMS}->{name}}; $this->{TL_DEFAULT_VALUE} = $data_hash->{$this->{TL_PARAMS}->{name}}; } # --------------------------------------------------------------------- package HTML::TableLayout::FormComponent::Radio; use HTML::TableLayout::Symbols; @HTML::TableLayout::FormComponent::Radio::ISA= qw(HTML::TableLayout::FormComponentMulti); ## ## Need to add an arbitrary flag to have it use breakafters ## call it "Breakafter" ## sub tl_setup { my ($this) = @_; if (exists $this->{TL_PARAMS}->{Breakafter}) { $this->{breakafter} = 1; delete $this->{TL_PARAMS}->{Breakafter}; } $this->SUPER::tl_setup(); } sub tl_print { my ($this) = @_; my $br = $this->{breakafter}; my $r; my $w = $this->{TL_WINDOW}; foreach $r (@{ $this->{TL_OPS} }) { my %params = %{ $this->{TL_PARAMS} }; $params{value} = $r->[0]; $w->i_print(">[0] eq $this->{TL_DEFAULT_VALUE}) { $w->f_print(" CHECKED"); } $r->[1]->tl_print(); $br and $w->i_print(">{TL_WINDOW}; $w->i_print(">{TL_PARAMS} }). ""); $w->_indentIncrement(); my $o; foreach $o (@{ $this->{TL_OPS} }) { if (! (ref $o eq "ARRAY")) { die("malformed options") } $w->i_print(">