BingoX

 view release on metacpan or  search on metacpan

lib/BingoX/Chromium.pm  view on Meta::CPAN


=head1 REQUIRES

Time::Object, Apache, CGI, Carp

=head1 EXPORTS

Nothing

=head1 DESCRIPTION

 BingoX::Chromium provides the generic API for BingoX admin classes.
 BingoX::Chromium uses admin objects that wrap Carbon data objects

=head1 CLASS VARIABLES

Classes that inherit from BingoX::Chromium should have the following class variables:

=over 4

=item * @fieldlist

The order in which to display fields (if one so chose to display them ;)

=item * %fields

A hash whose keys are columns (same as in the fieldlist array) and whose values 
are complex arrays. Each array index is described below.

=over 4

=item [0] Descriptive Title

A string describing the field

=item [1] HTML Entity Type

A string that contains one of the following HTML etity types:

 view
 text
 textarea
 datetime
 popup
 reference
 FIXME: more!!!

=item [2] HTML Options

A hash reference containing options for creating the HTML form field for 
this field.

=item [3] Related Classes

FIXME: I dunno

=item [4] Field Options

A hash reference containing special options for this field. The options include:

  not_null - this field cannot be NULL

=item [5] Sanity Methods

This is a list reference. Each item in the list is either a string with a 
sanity method name, or a list ref containing the method name, then any parameters 
that need to be passed to it. An example:

  [
   'sane_foo',
   ['sane_bar', 'baz'],
  ]

For more info, see L<"SANITY METHODS">.

=back

=item * $adminuri

An optional class variable, corresponds to the C<adminuri()> method.  
FIXME: Can someone who knows more about this elaborate?

=item * $classdesc

A simple one- or two-word description of the class being administered.

=back

=item * $data_class

The name of the data class that corresponds to the admin class. If this 
value is not defined, it will default to the name of the admin class, with 
the first instance of "::Admin::" changed to "::Data::".

=back

=head1 METHODS

=over 4

=cut

package BingoX::Chromium;

use Apache;
use Apache::Constants qw(:response);
use BingoX::Time;

use Carp;
use strict;
use vars qw($AUTOLOAD $debug);

BEGIN {
	$BingoX::Chromium::REVISION	= (qw$Revision: 2.36 $)[-1];
	$BingoX::Chromium::VERSION	= '1.92';

	$debug	= undef;

	if ($debug) {
		require Data::Dumper;
	}

lib/BingoX/Chromium.pm  view on Meta::CPAN

							-VALUE	=> $fields->{$_});
	}
	return $string;
} # END sub admin_name


=item display_start_html( \%params )

Accessor method to $self->cgi->start_html();  
Put into params exactly what you'd put in  CGI::start_html().  
Overload this in your admin class if you want to set any special 
BG,text,link colors, or anything else you want to pass to start_html()

=cut

sub display_start_html {
	my $self	= shift;
	my $options	= shift || { };
	my $ui		= $self->ui;
	$options->{'-bgcolor'}	||= $ui->{'page_bg'};
	$options->{'-text'}		||= $ui->{'text_color'};
	$options->{'-link'}		||= $ui->{'link_color'};
	$options->{'-vlink'}	||= $ui->{'vlink_color'};
	$options->{'-alink'}	||= $ui->{'alink_color'};
	return $self->cgi->start_html(%{ $options });
} # END sub display_start_html


=item C<display_search> (  )

Prints an HTML page meant for limiting what appears on the display_list page.

Not Implimented Yet.

=cut

sub display_search {
	warn "display_search method not implimented yet!";
	return undef;
} # END sub display_search


=item C<display_row> ( $field )

Takes a column (field) name and prints a 2 columned table row where the left 
column has the fields descriptive name ($self->fieldname($field)) and the right 
column has the output of that fields method ($self->$field)

=cut

sub display_row {
	my $self	= shift;
	return undef unless ref $self;
	my $q		= $self->cgi;
	my $field	= shift;
	my $ui		= $self->ui;

	return undef if ($self->fieldtype($field) eq 'hidden');

	## Is this field required? (i.e. not null?) ##
	my $req = %{$self->fieldoptions($field) || { }}->{not_null} || 0;

	if (($self->fieldtype($field) eq 'row')) {
		print $self->$field();
	} elsif ($self->fieldtype($field) eq 'textarea') {
		print $q->Tr({ },
				$q->td({	-VALIGN		=> 'top',
							-COLSPAN	=> 2,
							-ALIGN		=> 'center',
							-WIDTH		=> 100,
							-BGCOLOR	=> $ui->{'row_key'}
						},
						$q->font(
							$ui->{'font_key'},
							$q->b(
								($req ? '* ' : '') . $self->fieldname( $field ) . ':'
							)
						)
					)
				)."\n"
			. $q->Tr({ },
				$q->td({	-VALIGN		=> 'top',
							-COLSPAN	=> 2,
							-BGCOLOR	=> $ui->{'row_value'}
						},
						$q->font(
							$ui->{'font_value'},
							($self->$field() ? $self->$field() : '&nbsp;')
						)
					)
				) . "\n";
	} elsif (($self->fieldtype($field) eq 'password') && ($self->displaymode() ne 'view')) {
		# Once to enter
		print $q->Tr({ },
				$q->td({	-VALIGN		=> 'top',
							-ALIGN		=> 'right',
							-WIDTH		=> 100,
							-BGCOLOR	=> $ui->{'row_key'}
						},
						$q->font(
							$ui->{'font_key'},
							$q->b(
								($req ? '* ' : '') . $self->fieldname( $field ) . ':'
							)
						)
					)
			.	$q->td({	-VALIGN		=> 'top',
							-WIDTH		=> 400,
							-BGCOLOR	=> $ui->{'row_value'}
						},
						$q->font(
							$ui->{'font_value'},
							$self->$field()
						)
					)
			) . "\n"
		# again to verify
			. $q->Tr({ },
				$q->td({	-VALIGN		=> 'top',
							-ALIGN		=> 'right',
							-WIDTH		=> 100,

lib/BingoX/Chromium.pm  view on Meta::CPAN

	return undef unless ref $self;
	my $dbh		= $self->dbh();
	my $data	= shift || $self->get_data();

	warn 'save_data after get_data data: ' . Data::Dumper::Dumper($data) . "\n" if ($debug > 1);
	return undef unless (ref($data) eq 'HASH');
	return undef unless ($self->sanity($data));

	my $newself;
	warn 'save data==> ' . Data::Dumper::Dumper($data) . "\n" if ($debug);
	if ($self->displaymode eq 'add') {
		if ($newself = $self->data_class->new( $dbh, $data )) {
			warn "save_data - new succeeded\n" if ($debug > 1);
			$self->{'_db_obj'} = $newself;
			warn 'save_data - after new - new self ==> ' . Data::Dumper::Dumper($self->{'_db_obj'}) if ($debug > 1);
		} else {
			warn "save_date - new failed\n" if ($debug > 1);
			$self->{'_errors'}->{'General Database Error'} = $dbh->errstr || $self->data_class->errors;
			return undef;
		}
	} else {
		if ($newself = $self->db_obj->modify( $data )) {
			warn "save_data - modify succeeded\n" if ($debug > 1);
			$self->{'_db_obj'} = $newself;
			warn 'save_data - after modify - new self ==> ' . Data::Dumper::Dumper($self->{'_db_obj'}) if ($debug > 1);
		} else {
			warn "save_date - modify failed\n" if ($debug > 1);
			$self->{'_errors'}->{'General Database Error'} = $dbh->errstr || $self->db_obj->errors;
			return undef;
		}
	}
	return 1;
} # END sub save_data


=item C<get_data> ( [ $data, ] [ $fields ] )

Takes the fields hash (returned by $self->fields()) and the CGI object and 
returns a data hashref which can be sent to Carbon's new or modify 
You can optionaly pass a $data hash and a $fields hash which it will use.

B<OPTIMIZE>

=cut

sub get_data {
	my $self	= shift;
	return undef unless ref $self;
	my $data	= shift || { };
	my $fields	= shift || $self->fields;
	my $q		= $self->cgi;
	my $db_obj	= $self->db_obj;
	warn 'Admin:get_data q ==> ' . Data::Dumper::Dumper($q) . "\n" if ($debug > 2);
	warn 'Admin:get_data fields ==> ' . Data::Dumper::Dumper($fields) . "\n" if ($debug > 2);
	warn 'Admin:get_data db_obj ==> ' . Data::Dumper::Dumper($db_obj) . "\n" if ($debug > 2);

	foreach (keys %$fields) {
		my $qfieldname	= $self->qfieldname( $_ );
		my $foptions	= $self->fieldoptions( $_ );
		my $qoptions	= $self->fieldhtmloptions( $_ ) || { };
#		if (!$foptions->{not_null} && ($q->param( $qfieldname ) =~ /^NULL$/i)) {
#			warn "Null option selected.";
#			$q->param( $qfieldname, undef );
#			last;
#		}
		if ($self->fieldrelclass( $_ )) {
			warn "reclass - $_ ==> " . $self->fieldrelclass($_) . " qfieldname ==> $qfieldname - q ==> " . Data::Dumper::Dumper($q->param( $qfieldname )) ."\n" if ($debug > 1);
			if ($self->fieldrelclasstype($_)) {
				$data->{$self->fieldrelclass($_)} = [ $q->param( $qfieldname ) ];
			} else {
				warn "no classtype $_\n" if ($debug > 1);
				if ($q->param( $qfieldname ) eq 'NULL') {
					$data->{$_} = undef;
				} else {
					$data->{$_} = $q->param( $qfieldname ) unless (ref $db_obj && ($db_obj->$_() eq $q->param( $qfieldname )));
					warn Data::Dumper::Dumper( $data->{$_} ) if ($debug > 1);
				}
			}
		} elsif ($self->fieldtype($_) eq 'checkbox') {
			unless (defined $q->param( $qfieldname )) {
				$q->param(-NAME => $qfieldname, -VALUE => '0');
			}
			$data->{$_} = $q->param( $qfieldname )
				unless (ref $db_obj && ($db_obj->$_() eq $q->param( $qfieldname )));
		} elsif ($self->fieldtype($_) eq 'date') {
			next unless ($q->param( $qfieldname.'_year' ));
		
			my $date = BingoX::Time->new;
			warn "date field => $qfieldname\n" if ($debug > 1);

			## Year ##
			my $year	= $q->param( $qfieldname.'_year' );
			if (length($year) <= 2) {
				$self->{'_errors'}->{$_} = "Invalid Date Entered: be compliant and the use full year";
				return undef;
			}

			## Month ##
			my $month;
			my $mon		= $q->param( $qfieldname.'_mon' );
			if ($mon	=~ /\D/) {
				$self->{'_errors'}->{$_} = "Invalid Date Entered: must be of the value [ 1 .. 12 ]";
				return undef;
			} else {
				$month = $date->months->{ $mon };
			}

			## Day ##
			my $day		= $q->param( $qfieldname.'_day' );
			my $lday	= $date->last_days->{ $mon - 1 };
			if ($day < 1 || $day > 31) {
				$self->{'_errors'}->{$_} = "Invalid Date Entered: day is out of range";
				return undef;
			} elsif ($day =~ /\D/) {
				$self->{'_errors'}->{$_} = "Invalid Date Entered: must be of the value [ 1 .. last day ]";
				return undef;
			} elsif ($day > $lday) {
				$day = $lday;
			}

			## Hour ##

lib/BingoX/Chromium.pm  view on Meta::CPAN

				if ($am_pm eq 'PM') {
					$hour += 12 unless ($hour == 12);
				} else {
					$hour = 0 if ($hour == 12);
				}
			}

			## Minute ##
			my $min		= $q->param( $qfieldname.'_min' ) || '00';

			## Jun 04 1998 21:09:55 ##
			my $string		= sprintf("%s %2d %4d %02d:%02d:00", $month, $day, $year, $hour, $min);
			my $timelocal	= $self->data_class->str2time( $string );
			my $new_date	= BingoX::Time->new( $timelocal );
			$data->{$_}		= $new_date->strftime( $self->data_class->date_format )
				unless (ref $db_obj && ($db_obj->$_() eq $new_date));

			warn 'get_data date ==> ' . Data::Dumper::Dumper($data->{$_}) . "\n" if ($debug > 1);
		} else {
			warn "qfieldname ==> $qfieldname\n" if ($debug > 1);
			next if ($self->fieldtype( $_ ) eq 'view');

			## Verify that password fields match verification
			if ($self->fieldtype($_) eq 'password') {
				my @pw_values = $q->param( $qfieldname );
				if ($pw_values[0] ne $pw_values[1]) {
					$q->param( $qfieldname, '' );
					$self->{'_errors'}->{$_} = 'passwords do not match.';
				}
			}
			if ($q->param( $qfieldname ) eq 'NULL') {
				$data->{$_} = undef;
			} else {
				$data->{$_} = $q->param( $qfieldname )
					unless (ref $db_obj && ($db_obj->$_() eq $q->param( $qfieldname )));
			}
		}
	}
	warn 'get_data ==> ' . Data::Dumper::Dumper($data) ."\n" if ($debug > 2);
	return $data;
} # END sub get_data


=item C<sanity> (  )

Populates the _errors data instance in the case that the data does not conform 
to what is allowed to be entered into the database.

=cut

sub sanity {
	my $self		= shift;
	my $data_hash	= shift;
	ref($data_hash) || return undef;
	my $q			= $self->cgi;
	my $qfield;

	## Step through each field, calling all the necessary sanity methods ##
	foreach my $field (@{ $self->fieldlist }) {
		my $sanity = $self->fieldsanity( $field );
		my $req = %{ $self->fieldoptions( $field ) || { } }->{'not_null'} || 0;
		unless (ref($sanity) eq 'ARRAY' || $req) {
			warn "BingoX::Chromium::fieldsanity('$field') is not an array ref\n" if ($debug);
			next;
		}

		$qfield	 = $self->qfieldname( $field );

		my @errors = ( );
		my $data = (exists $data_hash->{ $field })
					? $data_hash->{$field}
					: (	$self->displaymode eq 'add'
						? ''
						: $self->db_obj->$field());
		## Is this a required field? If it's empty,	##
		## we can complain here and move on...		##
		if ($req && !$data) {
			$self->{'_errors'}{$field} ||= 'This field is required.';
			next;
		}

		## Check each sanity method for this field ##
		foreach my $sane (@$sanity) {
			if (ref $sane) {	# listref, call the method, passing paramters
				my $method	= shift @$sane;
				my $err		= $self->$method($data, @$sane);
				warn("SANITY ERROR: $err") if ($err && $debug);
				push(@errors, $err) if $err;
			} else {			# not a ref, call the method only
				my $err = $self->$sane( $data );
				warn("SANITY ERROR: $err") if ($err && $debug);
				push(@errors, $err) if $err;
			}
		}
		$self->{'_errors'}{$field} = join('<BR>', @errors) if @errors;
	}

	## Parlance -- true result means "sane" ##
	(%{ $self->{'_errors'} }) ? 0 : 1;
} # END sub sanity

sub qfd		{ return "#" }
sub pkd		{ return $_[0]->data_class->pkd }
sub prefix	{ return $_[0]->data_class_name . $_[0]->qfd }


=item C<cpkey> ( [ $db_obj ] )

Returns a string representing a single composite primary key joined by $self->qfd.

=cut

sub cpkey {
	my $self	= shift;
	my $obj		= shift || $self->db_obj;
	return undef unless (ref($self) && ref($obj));
	return $obj->cpkey;
} # END sub cpkey


=item C<cpkey_params> ($cpkey) 

lib/BingoX/Chromium.pm  view on Meta::CPAN

					-COLS		=> $qoptions->{'-COLS'}		|| 50,
					-WRAP		=> $qoptions->{'-WRAP'}		|| 'VIRTUAL',
					-OVERRIDE	=> $qoptions->{'-OVERRIDE'}	|| 1,
					-DEFAULT	=> (defined($q->param( $qfieldname ))
									?	$q->param( $qfieldname )
									:	(($self->displaymode eq 'modify')
										? $self->db_obj->$fieldname()
										: ($qoptions->{'-DEFAULT'} || '')))
				) . "\n";
} # END sub HTML_textarea


=item C<HTML_popup> ( $fieldname [, $qoptions ] )

Object Method:

Generic form field method called by AUTOLOAD.  
Gets the default field params based on the fieldname and returns the value 
in a popup field or in viewable format if the displaymode is 'view'.

Note: Not used yet because its not easy to populate the 
vaules & labels fields. USually always overloaded in the subclasses.

B<OPTIMIZE>

=cut

sub HTML_popup {
	my $self		= shift;
	my $class		= ref($self) || return undef;
	my $fieldname	= shift;
	my $qoptions	= shift || $self->fieldhtmloptions( $fieldname );
	my $foptions	= $self->fieldoptions( $fieldname );
	my $q			= $self->cgi;

	## if modify then grab the actual values of the primary keys of the obect				##
	## and prepend the fieldname with them.  This will allow people to modify multiple		##
	## objects on the same page.   Always put the classname and the fieldname at the end	##
	## of the fieldname.																	##
	my $qfieldname				= $self->qfieldname( $fieldname );
	my $relclass				= $class->fieldrelclass( $fieldname );
	my $relclass_title_field	= $relclass->title_field;
	$relclass					=~ /(.+)::Data::(.+)$/;
	my $reladminclass			= "${1}::Admin::${2}";

	## show all of the objects as text. ##
	if ($self->displaymode eq 'view') {
		my $obj		= @{ $relclass->list_obj(
							$self->dbh,
							{
								$relclass->primary_keys->[0] => $self->db_obj->$fieldname()
							}
					) || [ ] }->[0];
		(ref($obj) ? return $obj->$relclass_title_field() : return 'None Selected') . "\n";

	## get all of the objects with get_list_hash. ##
	} else {
		my $hashref	= $relclass->get_list_hash( $self->dbh );

		## Allows null value for popups ##
		if (!$foptions->{'not_null'} && $foptions->{'null_label'}) {
			$hashref->{'NULL'} = $foptions->{'null_label'};
		}

#		## if the displaymode isn't add, then highlite the already related objects. ##
#		my $selected = ($self->displaymode eq 'add')
#					? [ ]
#					: $self->db_obj->list_related( $relclass );
#		warn "Too Many Related" if ($selected->[1] && $debug);

		## default - if there's already data in the query object, highlite those objects,			##
		## otherwise if the displaymode if modify, show the data in the scrolling list where the	##
		## keys are composit primary keys seperated by $self->pkd and the									##
		## values are the title_fields of the objects, else don't highlite anything.				##
		$q->popup_menu(	-NAME		=> $qfieldname,
						-VALUES		=> [ sort { $hashref->{$a} cmp $hashref->{$b} } keys %$hashref ],	# need to fill in info later
						-LABELS		=> $hashref,														# need to fill in info later
						-DEFAULT	=> (defined($q->param( $qfieldname ))
									?	$q->param( $qfieldname )
									:	(($self->displaymode eq 'modify')
										? (defined($self->db_obj->$fieldname())
											? $self->db_obj->$fieldname()
											: ($foptions->{'null_label'}
												? 'NULL'
												: $qoptions->{'-DEFAULT'} || ''))
		## The trinary below is for parent child relationships.  Basically, if	##
		## we're adding a new object and this pop-up represents a list of our	##
		## parent fields, we should default to the parent we came through.		##
										: ((($self->displaymode eq 'add') && ($reladminclass eq $self->parent_class) && ($q->param('parent_pcpkey'))) 
											? (substr($q->param('parent_pcpkey'),rindex($q->param('parent_pcpkey'),$self->qfd)+1))
											: ($qoptions->{'-DEFAULT'} || ''))))
						) . "\n";
	}
} # END sub HTML_popup


=item C<HTML_radio> ( $fieldname [, $qoptions ] )

Object Method:

Generic form field method called by AUTOLOAD.  
Gets the default field params based on the fieldname and returns the value 
in a group of radio buttons or in viewable format if the displaymode is 'view'.

=cut

sub HTML_radio {
	my $self		= shift;
	my $class		= ref($self) || return undef;
	my $fieldname	= shift;
	my $qoptions	= shift || $self->fieldhtmloptions( $fieldname );
	my $q			= $self->cgi;
	my $qfieldname	= $self->qfieldname( $fieldname );

	my $relclass	= $class->fieldrelclass( $fieldname );
	my $relclass_title_field = $relclass->title_field;

	## show all of the objects as text. ##
	if ($self->displaymode eq 'view') {
		my $obj		= @{ $relclass->list_obj(	$self->dbh,
												{

lib/BingoX/Chromium.pm  view on Meta::CPAN

    and to flow

 Revision 2.8  2000/08/03 20:48:09  thai
  - addd qfd() method to handle qfds
  - fixed bug in HTML_date() that would create a new date object when
    displaymode was 'view'
  - the sub pkd() now calls data_class->pkd()

 Revision 2.7  2000/08/01 00:43:51  thai
  - changed db_obj->errstr to dbh->errstr on line 305
  - moved all the $qfieldname stuff to the qfieldname() method
  - removed the fieldtype eq 'custom' from line 1174 in get_data()

 Revision 2.6  2000/07/14 19:27:05  dougw
 save_data returns undef if it can't ref get_data's return value, should be a hashref.
 Small typo fix, hidden_fields returns a string as it should.

 Revision 2.5  2000/07/12 19:30:17  thai
  - fixed POD, cleaned up code

 Revision 2.4  2000/07/07 01:20:43  dougw
  - Added 1 instead of Turned On for the check box value. Who ever thought 
    of that?  Changed the comparisons for hashrefs. Beware !%$hashref is 
    different than ref $hashref ne 'HASH'

 Revision 2.3  2000/05/31 02:39:20  greg
 changed use of s/.*:// to substr(...) in AUTOLOAD for efficiency.

 Revision 2.2  2000/05/24 20:47:25  thai
  - added more sanity when dereferencing, @{ $code->() || [ ] }
  - added warning when creating new date objects fail

 Revision 2.1  2000/05/19 01:25:11  thai
  - cleaned up code
  - is now part of the Bingo user space

 Revision 2.0  2000/05/02 00:54:33  thai
  - committed as 2.0

 Revision 1.38  2000/03/21 02:00:23  dougw
 Fixed a bug introduced recently that broke adding new object when
 the identity key was in the fields list. This is so wierd. (zack)

 Revision 1.37  2000/03/17 21:09:00  dougw
 Allowed hidden values to be used in HTML_date for -TYPE=>'view'
 Fixed checkbox undef error

 Revision 1.36  2000/03/15 22:26:17  zack
 Added HTML_radio() and modified new() to allow passing a display mode.

 Revision 1.35  2000/03/15 19:25:43  colin
 -HTML_popup now sorts options alphabetically

 Revision 1.34  2000/03/14 21:45:08  dougw
 Fixed get_data->save_data problems (thanks dave).
 Removed spurious comments.

 Revision 1.33  2000/03/14 20:58:10  dougw
 Modified HTML_popup to allow a NULL selection. Use the fieldoption -null_label
 to specify what you want the option to be named. The option must not have the
 -not_null option set for obvious reasons.

 Revision 1.32  2000/03/10 01:57:54  colin
 made display_list()'s hash sorter even cooler (thanks doug)

 Revision 1.31  2000/03/10 01:18:02  colin
 -display_list() now sorts its entries alphabetically.

 Revision 1.30  2000/03/09 18:58:23  colin
 -fixed a bug in HTML_date() where $qfieldname was being used as a global.
 -fixed similar bugs in HTML_day(),HTML_month(),and HTML_year()
 -one can now pass a hashref to hidden_fields(). If one wanted to.

 Revision 1.29  2000/03/09 00:45:32  colin
 -(thai) fixed a bug in HTML_date() where it wasn't passing fieldnames to its helper methods.
 -HTML_date() now checks the -TYPE it's passed in fieldoptions

 Revision 1.28  2000/03/08 03:09:32  thai
  - parsed out HTML_date() to HTML_day(), HTML_month(), HTML_year(),
    and HTML_time()

 Revision 1.27  2000/02/25 20:24:17  colin
 corrected some minor ui bugs in display_list() and display_modify()

 Revision 1.26  2000/02/18 23:38:56  colin
 - altered sanity() so that it now accepts a passed \%data hashref instead
   of looking for things in the query object. this way the data is already
   formatted and we don't have to format data again (especially useful because
   we don't have to re-sort all the date fields, etc)

 Revision 1.25  2000/02/17 23:37:43  colin
 -get_data() now gives meaningful error messages when users enter invalid info in date fields

 Revision 1.24  2000/02/17 03:46:27  dougw
 Small modifications to take advantage of DateTime changes.
 Using $obj instead of $obj->time_local;

 Revision 1.23  2000/02/11 18:52:00  colin
 - (doug) HTML_* methods now use DateTime to manage date info.
 - (colin) Changed ui() so that a) it caches the hasref if called as an object method and b)
   allows you to override default settings (and add others) when calling the method, as
   opposed to calling SUPER::ui() and then re-setting the resulting hashref.

 Revision 1.22  2000/02/08 03:34:31  zack
 - documented the %fields class variable
 - added not_null to field options (index [4])
 - implemented flexible sanity checking
   - added sane_regex()
   - added sane_minlength() and sane_maxlength()
 - updated docs for fieldoptions() and fieldsanity()
 - HTML_textarea(): 'WRAP' defaults to 'VIRTUAL'

 Revision 1.21  2000/02/04 19:48:28  derek
  - Fixed two instances where $ui wasn't being accessed to include font tags

 Revision 1.20  2000/02/04 19:28:45  derek
  - Changed Cancel button on View page to Return to List and modified flow
    to reflect the change
  - Added tons of CGI HTML code to make the Chromium interface look better
  - Added ui method that has defaults for colors and fonts that are used
    in the newly designed skin-like interfaces
  - Added Greg's adminclass method to return the project specific admin
    super class
  - Fixed display bug in HTML_textarea where content fields weren't being
    broken up into paragraphs in View mode
  - Added flow to display_row method to check for content fields and break
    them into two rows for the key/value pair

 Revision 1.19  2000/02/03 03:42:35  zack
 Documentation fixes and updates

 Revision 1.18  2000/01/31 02:00:19  adam
  - dbh was using a GLOBAL flag to see if had already set the
   $r->register_cleanup.  That was bad since the global was living beyond
   each hit.  In the end, the DBH wasn't being cleared after every hit.
   So now it uses the Apache notes to store the flag.
 - display_row() - oops...  thats not the variable name!

 "The best laid plans..."

 Revision 1.17  2000/01/30 04:30:46  adam
  - using an HTMl fieldtype of 'row' makes display_row() not print table
   tags, it just prints the results of the method $_().

 Revision 1.16  2000/01/27 22:12:17  colin
 Added cgi() and marked CGI_obj() as deprecated (evil music here).
 Added some \%qoptions to HTML_file

 Revision 1.15  2000/01/27 01:17:14  colin
 - finished HTML_file(). Also, due to popular request, display_modify() now uses
   $q->start_multipart_form() instead of $q->startform().
 - Well, it actually wasn't a *popular* request, but when the email went out asking
   if anyone had problems with it there was no response. 
 Ever. And that's good enough for me!

 Revision 1.14  2000/01/25 20:55:48  colin
 added:
 postmodify_handler()
 postadd_handler()
 hidden_fields()
 display_list_buttons()
 display_modify_buttons()

 HooHah!

 Revision 1.13  2000/01/24 22:19:39  dougw



( run in 2.156 seconds using v1.01-cache-2.11-cpan-5a3173703d6 )