[interchange-cvs] interchange - heins modified 2 files

interchange-core@icdevgroup.org interchange-core@icdevgroup.org
Wed Sep 18 23:26:02 2002


User:      heins
Date:      2002-09-19 03:25:47 GMT
Modified:  lib/Vend Interpolate.pm
Added:     lib/Vend/Table Editor.pm
Log:
* Slightly improve Interpolate.pm get_joiner() routine.

* Add new Vend::Table::Editor module. Some rough edges, but
  already does tabbed display.

* Will be adding more templating as time goes on.

* Table::Editor is not yet hooked into anything, you need to
  use a new table_editor.coretag to get it. (Basically, remove
  the Routine reference and "MapRoutine" to Vend::Table::Editor::editor).
  The module needs to get required as well.

Revision  Changes    Path
2.112     +4 -3      interchange/lib/Vend/Interpolate.pm


rev 2.112, prev_rev 2.111
Index: Interpolate.pm
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/interchange/lib/Vend/Interpolate.pm,v
retrieving revision 2.111
retrieving revision 2.112
diff -u -r2.111 -r2.112
--- Interpolate.pm	18 Sep 2002 00:45:56 -0000	2.111
+++ Interpolate.pm	19 Sep 2002 03:25:47 -0000	2.112
@@ -1,6 +1,6 @@
 # Vend::Interpolate - Interpret Interchange tags
 #=20
-# $Id: Interpolate.pm,v 2.111 2002/09/18 00:45:56 jon Exp $
+# $Id: Interpolate.pm,v 2.112 2002/09/19 03:25:47 mheins Exp $
 #
 # Copyright (C) 1996-2002 Red Hat, Inc. <interchange@redhat.com>
 #
@@ -27,7 +27,7 @@
 require Exporter;
 @ISA =3D qw(Exporter);
=20
-$VERSION =3D substr(q$Revision: 2.111 $, 10);
+$VERSION =3D substr(q$Revision: 2.112 $, 10);
=20
 @EXPORT =3D qw (
=20
@@ -440,11 +440,12 @@
=20
 sub get_joiner {
 	my ($joiner, $default) =3D @_;
+	return $default      unless defined $joiner and length $joiner;
 	if($joiner eq '\n') {
 		$joiner =3D "\n";
 	}
 	elsif($joiner =3D~ m{\\}) {
-		$joiner =3D tag_calc("qq{$joiner}");
+		$joiner =3D $safe_safe->reval("qq{$joiner}");
 	}
 	return length($joiner) ? $joiner : $default;
 }



1.1                  interchange/lib/Vend/Table/Editor.pm


rev 1.1, prev_rev 1.0
Index: Editor.pm
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
# Vend::Table::Editor - Swiss-army-knife table editor for Interchange
#
# $Id: Editor.pm,v 1.1 2002/09/19 03:25:47 mheins Exp $
#
# Copyright (C) 2002 ICDEVGROUP <interchange@icdevgroup.org>
# Copyright (C) 2002 Mike Heins <mike@perusion.net>
#
# This program was originally based on Vend 0.2 and 0.3
# Copyright 1995 by Andrew M. Wilcox <amw@wilcoxsolutions.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA  02111-1307  USA.

package Vend::Table::Editor;

use vars qw($VERSION);
$VERSION =3D substr(q$Revision: 1.1 $, 10);

use Vend::Util;
use Vend::Interpolate;
use Vend::Data;

=3Dhead1 NAME

Vend::Table::Editor -- Interchange do-all HTML table editor

=3Dhead1 SYNOPSIS

[table-editor OPTIONS]=20

[table-editor OPTIONS] TEMPLATE [/table-editor]

=3Dhead1 DESCRIPTION

The [table-editor] tag produces an HTML form that edits a database
table or collects values for a "wizard". It is extremely configurable
as to display and characteristics of the widgets used to collect the
input.

The widget types are based on the Interchange C<[display ...]> UserTag,
which in turn is heavily based on the ITL core C<[accessories ...]> tag.

The C<simplest> form of C<[table-editor]> is:

	[table-editor table=3Dfoo]

A page which contains only that tag will edit the table C<foo>, where
C<foo> is the name of an Interchange table to edit. If no C<foo> table
is C<defined>, then nothing will be displayed.

If the C<mv_metadata> entry "foo" is present, it is used as the
definition for table display, including the fields to edit and labels
for sections of the form. If C<ui_data_fields> is defined, this
cancels fetch of the view and any breaks and labels must be
defined with C<ui_break_before> and C<ui_break_before_label>. More
on the view concept later.

A simple "wizard" can be made with:

	[table-editor
			wizard=3D1
			ui_wizard_fields=3D"foo bar"
			mv_nextpage=3Dwizard2
			mv_prevpage=3Dwizard_intro
			]

The purpose of a "wizard" is to collect values from the user and
place them in the $Values array. A next page value (option mv_nextpage)
must be defined to give a destination; if mv_prevpage is defined then
a "Back" button is presented to allow paging backward in the wizard.

=3Dcut

my $Tag =3D new Vend::Tags;

%Vend::Interpolate::Filter_desc =3D (
	filesafe        =3D> 'Safe for filename',
	currency        =3D> 'Currency',
	mailto          =3D> 'mailto: link',
	commify         =3D> 'Commify',
	lookup          =3D> 'DB lookup',
	uc              =3D> 'Upper case',
	date_change     =3D> 'Date widget',
	null_to_space   =3D> 'NULL to SPACE',
	null_to_comma   =3D> 'NULL to COMMA',
	null_to_colons  =3D> 'NULL to ::',
	space_to_null   =3D> 'SPACE to NULL',
	colons_to_null  =3D> ':: to NULL',
	last_non_null   =3D> 'Reverse combo',
	nullselect      =3D> 'Combo box',
	tabbed          =3D> 'Newline to TAB',
	lc              =3D> 'Lower case',
	digits_dot      =3D> 'Digits-dots',
	backslash       =3D> 'Strip backslash',
	option_format   =3D> 'Option format',
	crypt           =3D> 'Crypt',
	namecase        =3D> 'Name case',
	name            =3D> 'Last&#44;First to First Last',
	digits          =3D> 'Digits only',
	word            =3D> 'A-Za-z_0-9',
	unix            =3D> 'DOS to UNIX newlines',
	dos             =3D> 'UNIX to DOS newlines',
	mac             =3D> 'UNIX/DOS to Mac OS newlines',
	no_white        =3D> 'No whitespace',
	strip           =3D> 'Trim whitespace',
	sql             =3D> 'SQL quoting',
	textarea_put    =3D> 'Textarea PUT',
	textarea_get    =3D> 'Textarea GET',
	text2html       =3D> 'Simple text2html',
	urlencode       =3D> 'URL encode',
	entities        =3D> 'HTML entities',
);

my $F_desc =3D \%Vend::Interpolate::Filter_desc;

my $fdesc_sort =3D sub {
	return 1 if $a and ! $b;
	return -1 if ! $a and $b;
	return lc($F_desc->{$a}) cmp lc($F_desc->{$b});
};

sub expand_values {
	my $val =3D shift;
	return $val unless $val =3D~ /\[/;
	$val =3D~ s/\[cgi\s+([^\[]+)\]/$CGI::values{$1}/ig;
	$val =3D~ s/\[var\s+([^\[]+)\]/$::Variable->{$1}/ig;
	$val =3D~ s/\[value\s+([^\[]+)\]/$::Values->{$1}/ig;
	return $val;
}

sub filters {
	my ($exclude, $opt) =3D @_;
	$opt ||=3D {};
	my @out =3D map { $_ . ($F_desc->{$_} ? "=3D$F_desc->{$_}" : '') }=20
				sort $fdesc_sort keys %Vend::Interpolate::Filter;
	if($exclude) {
		@out =3D grep /=3D/, @out;
	}
	unshift @out, "=3D--add--" unless $opt->{no_add};
	$opt->{joiner} =3D Vend::Interpolate::get_joiner($opt->{joiner}, ",\n");
	return join $opt->{joiner}, @out;
}

sub meta_record {
	my ($item, $view, $mdb) =3D @_;

#::logDebug("meta_record: item=3D$item view=3D$view mdb=3D$mdb");
	return undef unless $item;

	if(! ref ($mdb)) {
		my $mtable =3D $mdb || $::Variable->{UI_META_TABLE} || 'mv_metadata';
#::logDebug("meta_record mtable=3D$mtable");
		$mdb =3D database_exists_ref($mtable)
			or return undef;
	}
#::logDebug("meta_record has an item=3D$item and mdb=3D$mdb");

	my $record;

	my $mkey =3D $view ? "${view}::$item" : $item;

	if(ref $mdb eq 'HASH') {
		$record =3D $mdb;
	}
	else {
		$record =3D $mdb->row_hash($mkey);
	}

	$record ||=3D $mdb->row_hash($item) if $view;
#::logDebug("meta_record  record=3D$record");

	return undef if ! $record;

	# Get additional settings from extended field, which is a serialized
	# hash
	my $hash;
	if($record->{extended}) {
		## From Vend::Util
		$hash =3D get_option_hash($record->{extended});
		if(ref $hash eq 'HASH') {
			@$record{keys %$hash} =3D values %$hash;
		}
		else {
			undef $hash;
		}
	}

	# Allow view settings to be placed in the extended area
	if($view and $hash and $hash->{view}) {
		my $view_hash =3D $record->{view}{$view};
		ref $view_hash
			and @$record{keys %$view_hash} =3D values %$view_hash;
	}
#::logDebug("return meta_record=3D" . ::uneval($record) );
	return $record;
}

my $base_entry_value;

sub display {
	my ($table,$column,$key,$opt) =3D @_;

	if( ref($opt) ne 'HASH' ) {
		$opt =3D get_option_hash($opt);
	}

	my $template =3D $opt->{type} eq 'hidden' ? '' : $opt->{template};

	if($opt->{override}) {
		$opt->{value} =3D defined $opt->{default} ? $opt->{default} : '';
	}

	if(! defined $opt->{value} and $table and $column and length($key)) {
		$opt->{value} =3D tag_data($table, $column, $key);
	}

	my $mtab;
	my $record;

	my $no_meta =3D $CGI::values{ui_no_meta_display};

	METALOOK: {
		## No meta display wanted
		last METALOOK if $no_meta;
		## No meta display possible
		$table and $column or $opt->{meta}
			or last METALOOK;

		## We get a metarecord directly, though why it would be here
		## and not in options I don't know
		if($opt->{meta} and ref($opt->{meta}) eq 'HASH') {
			$record =3D $opt->{meta};
			last METALOOK;
		}

		$mtab =3D $opt->{meta_table} || $::Variable->{UI_META_TABLE} || 'mv_metad=
ata'
			or last METALOOK;
		my $meta =3D Vend::Data::database_exists_ref($mtab)
			or do {
				::logError("non-existent meta table: %s", $mtab);
				undef $mtab;
				last METALOOK;
			};

		my $view =3D $opt->{view} || $opt->{arbitrary};

		## This is intended to trigger on the first access
		if($column eq $meta->config('KEY')) {
			if($view and $opt->{value} !~ /::.+::/) {
				$base_entry_value =3D ($opt->{value} =3D~ /^([^:]+)::(\w+)$/)
									? $1
									: $opt->{value};
			}
			else {
				$base_entry_value =3D $opt->{value} =3D~ /::/
									? $table
									: $opt->{value};
			}
		}

		my (@tries) =3D "${table}::$column";
		unshift @tries, "${table}::${column}::$key"
			if length($key)
				and $CGI::values{ui_meta_specific} || $opt->{specific};

		my $sess =3D $Vend::Session->{mv_metadata} || {};

		push @tries, { type =3D> $opt->{type} }
			if $opt->{type} || $opt->{label};

		for my $metakey (@tries) {
			## In case we were passed a meta record
			last if $record =3D $sess->{$metakey} and ref $record;
			$record =3D UI::Primitive::meta_record($metakey, $view, $meta)
				and last;
		}
	}

	my $w;

	METAMAKE: {
		last METAMAKE if $no_meta;
		if( ! $record ) {
			$record =3D { %$opt };
		}
		else {
			## Here we allow override with the display tag, even with views and
			## extended
			my @override =3D qw/
								append
								attribute
								db
								extra
								field
								filter
								height
								help
								help_url
								label
								lookup
								lookup_exclude
								lookup_query
								name
								options
								outboard
								passed
								pre_filter
								prepend
								type
								width
								/;
			for(@override) {
				delete $record->{$_} if ! length($record->{$_});
				next unless defined $opt->{$_};
				$record->{$_} =3D $opt->{$_};
			}
		}

		$record->{name} ||=3D $column;
#::logDebug("record now=3D" . ::uneval($record));

		if($record->{options} and $record->{options} =3D~ /^[\w:]+$/) {
#::logDebug("checking options");
			PASS: {
				my $passed =3D $record->{options};

				if($passed eq 'tables') {
					my @tables =3D $Tag->list_databases();
					$record->{passed} =3D join (',', "=3D--none--", @tables);
				}
				elsif($passed eq 'filters') {
					$record->{passed} =3D filters(1);
				}
				elsif($passed =3D~ /^columns(::(\w*))?\s*$/) {
					my $total =3D $1;
					my $tname =3D $2 || $record->{db} || $table;
					if ($total eq '::' and $base_entry_value) {
						$tname =3D $base_entry_value;
					}
					$record->{passed} =3D join ",",
											"=3D--none--",
											$Tag->db_columns($tname),
										;
				}
				elsif($passed =3D~ /^keys(::(\w+))?\s*$/) {
					my $tname =3D $2 || $record->{db} || $table;
					$record->{passed} =3D join ",",
											"=3D--none--",
											$Tag->list_keys($tname),
										;
				}
			}
		}

#::logDebug("checking for custom widget");
		if ($record->{type} =3D~ s/^custom\s+//s) {
			my $wid =3D lc $record->{type};
			$wid =3D~ tr/-/_/;
			my $w;
			$record->{attribute} ||=3D $column;
			$record->{table}     ||=3D $mtab;
			$record->{rows}      ||=3D $record->{height};
			$record->{cols}      ||=3D $record->{width};
			$record->{field}     ||=3D 'options';
			$record->{name}      ||=3D $column;
			eval {
				$w =3D $Tag->$wid($record->{name}, $opt->{value}, $record, $opt);
			};
			if($@) {
				::logError("error using custom widget %s: %s", $wid, $@);
			}
			last METAMAKE;
		}

#::logDebug("formatting prepend/append");
		for(qw/append prepend/) {
			next unless $record->{$_};
			$record->{$_} =3D expand_values($record->{$_});
			$record->{$_} =3D Vend::Util::resolve_links($record->{$_});
			$record->{$_} =3D~ s/_UI_VALUE_/$opt->{value}/g;
			$record->{$_} =3D~ /_UI_URL_VALUE_/
				and do {
					my $tmp =3D $opt->{value};
					$tmp =3D~ s/(\W)/sprintf '%%%02x', ord($1)/eg;
					$record->{$_} =3D~ s/_UI_URL_VALUE_/$tmp/g;
				};
			$record->{$_} =3D~ s/_UI_TABLE_/$table/g;
			$record->{$_} =3D~ s/_UI_COLUMN_/$column/g;
			$record->{$_} =3D~ s/_UI_KEY_/$key/g;
		}

#::logDebug("overriding defaults");
#::logDebug("passed=3D$record->{passed}") if $record->{debug};
		my %things =3D (
			attribute	=3D> $column,
			cols	 	=3D> $opt->{cols}   || $record->{width},
			column	 	=3D> $column,
			passed	 	=3D> $record->{options},
			rows 		=3D> $opt->{rows}	|| $record->{height},
			table		=3D> $table,
			value		=3D> $opt->{value},
		);

		while( my ($k, $v) =3D each %things) {
			next if length $record->{$k};
			next unless defined $v;
			$record->{$k} =3D $v;
		}

#::logDebug("calling Vend::Form");
		$w =3D Vend::Form::display($record);
		if($record->{filter}) {
			$w .=3D qq{<INPUT TYPE=3Dhidden NAME=3D"ui_filter:$record->{name}" VALUE=
=3D"};
			$w .=3D $record->{filter};
			$w .=3D '">';
		}
	}

#::logDebug("widget=3D$w");
	# don't output label if widget is hidden form variable only
	return $w if $w =3D~ /^\s*<input\s[^>]*type\s*=3D\W*hidden\b[^>]*>\s*$/i;

	if(! defined $w) {
		my $text =3D $opt->{value};
		my $iname =3D $opt->{name} || $column;

		# Count lines for textarea
		my $count;
		$count =3D $text =3D~ s/(\r\n|\r|\n)/$1/g;

		HTML::Entities::encode($text, $ESCAPE_CHARS::std);
		my $size;
		if ($count) {
			$count++;
			$count =3D 20 if $count > 20;
			$w =3D <<EOF;
	<TEXTAREA NAME=3D"$iname" COLS=3D60 ROWS=3D$count>$text</TEXTAREA>
EOF
		}
		elsif ($text =3D~ /^\d+$/) {
			my $cur =3D length($text);
			$size =3D $cur > 8 ? $cur + 1 : 8;
		}
		else {
			$size =3D 60;
		}
			$w =3D <<EOF;
	<INPUT NAME=3D"$iname" SIZE=3D$size VALUE=3D"$text">
EOF
	}

	my $array_return =3D wantarray;

	return $w unless $template || $array_return;

	if($template and $template !~ /\s/) {
		$template =3D <<'EOF';
<TR>
<TD>
	<B>$LABEL$</B>
</TD>
<TD VALIGN=3DTOP>
	<TABLE CELLSPACING=3D0 CELLMARGIN=3D0><TR><TD>$WIDGET$</TD><TD><I>$HELP$</=
I>{HELP_URL}<BR><A HREF=3D"$HELP_URL$">help</A>{/HELP_URL}</TD></TR></TABLE>
</TD>
</TR>
EOF
	}

	$record->{label} ||=3D $column;

	my %sub =3D (
		WIDGET		=3D> $w,
		HELP		=3D> $opt->{applylocale}
						? errmsg($record->{help})
						: $record->{help},
        META_URL    =3D> $opt->{meta_url},
		HELP_URL	=3D> $record->{help_url},
		LABEL		=3D> $opt->{applylocale}
						? errmsg($record->{label})
						: $record->{label},
	);
#::logDebug("passed meta_url=3D$opt->{meta_url}");
      $sub{HELP_EITHER} =3D $sub{HELP} || $sub{HELP_URL};

	if($array_return) {
		return ($w, $sub{LABEL}, $sub{HELP}, $record->{help_url});
	}
	else {
		# Strip the {TAG} {/TAG} pairs if nothing there
		$template =3D~ s#{([A-Z_]+)}(.*?){/\1}#$sub{$1} ? $2: '' #ges;
		# Insert the TAG
              $sub{HELP_URL} ||=3D 'javascript:void(0)';
		$template =3D~ s/\$([A-Z_]+)\$/$sub{$1}/g;
#::logDebug("substituted template is: $template");
		return $template;
	}
}

sub tabbed_display {
	my ($tit, $cont, $opt) =3D @_;
=09
	$opt ||=3D {};

	$opt->{tab_bgcolor_template} ||=3D 'eeeeee';
	$opt->{tab_height} ||=3D '30';
	$opt->{tab_width} ||=3D '120';
	$opt->{tab_cellspacing} ||=3D 0;
	$opt->{tab_cellpadding} ||=3D 2;
	$opt->{panel_height} ||=3D '600';
	$opt->{panel_width} ||=3D '800';
	$opt->{panel_id} ||=3D 'mvpan';
	$opt->{tab_horiz_offset} ||=3D '10';
	$opt->{tab_vert_offset} ||=3D '8';
	$opt->{layer_tab_style} ||=3D q{
									font-weight:bold;
									text-align:center;
									font-family:sans-serif;
									};
	$opt->{layer_panel_style} ||=3D q{
									font-family:sans-serif;
									padding:6px;
									};

	my $id =3D $opt->{panel_id};
	my $num_panels =3D scalar(@$cont);
	my $tabs_per_row =3D int( $opt->{panel_width} / $opt->{tab_width}) || 1;
	my $num_rows =3D POSIX::ceil( $num_panels / $opt->{tab_width});
	my $width =3D $opt->{panel_width};
	my $height =3D $opt->{tab_height} * $num_rows + $opt->{panel_height};
	my $panel_y =3D
		$num_rows
		* ($opt->{tab_height} - $opt->{tab_vert_offset})
		+ $opt->{tab_vert_offset};
	my $int1 =3D $panel_y - 2;
	my $int2 =3D $opt->{tab_height} * $num_rows;
::logDebug("num rows=3D$num_rows");
	my $out =3D <<EOF;
<SCRIPT language=3D"JavaScript">
<!--
var panelID =3D "$id"
var numDiv =3D $num_panels;
var numRows =3D $num_rows;
var tabsPerRow =3D $tabs_per_row;
var numLocations =3D numRows * tabsPerRow
var tabWidth =3D $opt->{tab_width}
var tabHeight =3D $opt->{tab_height}
var vOffset =3D $opt->{tab_vert_offset};
var hOffset =3D $opt->{tab_horiz_offset};

var divLocation =3D new Array(numLocations)
var newLocation =3D new Array(numLocations)
for(var i=3D0; i<numLocations; ++i) {
	divLocation[i] =3D i
	newLocation[i] =3D i
}

function getDiv(s,i) {
	var div
	if (document.layers) {
		div =3D document.layers[panelID].layers[panelID+s+i]
	} else if (document.all && !document.getElementById) {
		div =3D document.all[panelID+s+i]
	} else {
		div =3D document.getElementById(panelID+s+i)
	}
	return div
}

function setZIndex(div, zIndex) {
	if (document.layers) div.style =3D div;
	div.style.zIndex =3D zIndex
}

function updatePosition(div, newPos) {
	newClip=3DtabHeight*(Math.floor(newPos/tabsPerRow)+1)
	if (document.layers) {
		div.style=3Ddiv;
		div.clip.bottom=3DnewClip; // clip off bottom
		} else {
		div.style.clip=3D"rect(0 auto "+newClip+" 0)"
		}
	div.style.top =3D (numRows-(Math.floor(newPos/tabsPerRow) + 1)) * (tabHeig=
ht-vOffset)
	div.style.left =3D (newPos % tabsPerRow) * tabWidth +	(hOffset * (Math.flo=
or(newPos / tabsPerRow)))
}

function selectTab(n) {
	// n is the ID of the division that was clicked
	// firstTab is the location of the first tab in the selected row
	var firstTab =3D Math.floor(divLocation[n] / tabsPerRow) * tabsPerRow
	// newLoc is its new location
	for(var i=3D0; i<numDiv; ++i) {
		// loc is the current location of the tab
		var loc =3D divLocation[i]
		// If in the selected row
		if(loc >=3D firstTab && loc < (firstTab + tabsPerRow)) newLocation[i] =3D=
 (loc - firstTab)
		else if(loc < tabsPerRow) newLocation[i] =3D firstTab+(loc % tabsPerRow)
		else newLocation[i] =3D loc
	}
	// Set tab positions & zIndex
	// Update location
	for(var i=3D0; i<numDiv; ++i) {
		var loc =3D newLocation[i]
		var div =3D getDiv("panel",i)
		if(i =3D=3D n) setZIndex(div, numLocations +1)
		else setZIndex(div, numLocations - loc)
		divLocation[i] =3D loc
		div =3D getDiv("tab",i)
		updatePosition(div, loc)
		if(i =3D=3D n) setZIndex(div, numLocations +1)
		else setZIndex(div,numLocations - loc)
	}
}

// Nav4: position component into a table
function positionPanel() {
	document.$id.top=3Ddocument.panelLocator.pageY;
	document.$id.left=3Ddocument.panelLocator.pageX;
}
if (document.layers) window.onload=3DpositionPanel;

//-->
</SCRIPT>
<STYLE type=3D"text/css">
<!--
.tab {
	font-family: sans-serif; line-height:150%; font-weight: bold; position:abs=
olute; text-align:center; border:2px; border-color:#999999; border-style:ou=
tset; border-bottom-style:none; width:$opt->{tab_width}px; margin:0px; heig=
ht: ${int2}px;
}

.panel {
	font-family: sans-serif;
	font-size: smaller;
	position:absolute;
	border: 2px;
	border-color:#999999;
	border-style:outset;
	width: $opt->{panel_width}px;
	height: $opt->{panel_height}px;
	left:0px;
	top:${int1}px;
	margin:0px;
	padding:6px;
}
-->
</STYLE>
EOF
	my $s1 =3D '';
	my $s2 =3D '';
	for(my $i =3D 0; $i < $num_panels; $i++) {
		my $c =3D '#eeeeee';
		my $zi =3D $num_panels - $i;
		my $pnum =3D $i + 1;
		my $left =3D (($i % $tabs_per_row)
					* $opt->{tab_width}
					+ ($opt->{tab_horiz_offset}
					* (int($i / $tabs_per_row))));
		my $top =3D ( $num_rows - (int($i / $tabs_per_row) + 1))
					- ($opt->{tab_height} - $opt->{tab_vert_offset});
		my $cliprect =3D $opt->{tab_height} * (int($i / $tabs_per_row) + 1);
		$s1 .=3D <<EOF;
<DIV id=3D"${id}panel$i" class=3D"panel" style=3D"background-color: $c;=20
 z-index:$zi">
<table>
$cont->[$i]
</table>
</DIV>
<DIV
	onclick=3D"selectTab($i)"
	id=3D"${id}tab$i"
	class=3D"tab"
	style=3D"
		background-color:$c;=20
		left: ${left}px;
		top: ${top}px;
		z-index:$zi;
		clip:rect(0 auto $cliprect 0);
		">
$tit->[$i]
</DIV>
EOF
		my $lheight =3D $opt->{tab_height} * $num_rows;
		my $ltop =3D $num_rows * ($opt->{tab_height} - $opt->{tab_vert_offset})
					+ $opt->{tab_vert_offset} - 2;
		$s2 .=3D <<EOF;
<LAYER
	bgcolor=3D"$c"
	style=3D"$opt->{layer_tab_style}"
	width=3D"$opt->{tab_width}"
	height=3D"$lheight"
	left=3D"$left"
	top=3D"$top"
	z-index=3D"$zi"
	id=3D"${id}tab$i"
	onfocus=3D"selectTab($i)"
	>
<table width=3D"100%" cellpadding=3D2 cellspacing=3D0>
$tit->[$i]
</LAYER>
<LAYER
	bgcolor=3D"$c"
	style=3D"$opt->{layer_panel_style}"
	width=3D"$opt->{panel_width}"
	height=3D"$opt->{panel_height}"
	left=3D"0"
	top=3D"$ltop"
	z-index=3D"$zi"
	id=3D"${id}panel$i"
	>$cont->[$i]
</LAYER>
EOF
	}
	return <<EOF;
$out
<div style=3D"
		position: relative;
		left: 0; top: 0; width=3D100%; height=3D100%;
		z-index: 0;
	">
$s1
<script>
	selectTab(0);
</script>
</div>
EOF
}

my $tcount_all;
my %alias;
my %exclude;
my %outhash;
my @titles;
my @controls;
my $ctl_index =3D 0;
my @out;

sub ttag {
	return 'TABLE_STD' . ++$tcount_all;
}

sub add_exclude {
	my ($tag, $string) =3D @_;
	$exclude{$tag} ||=3D ' ';
	$exclude{$tag} .=3D "$string ";
}

sub col_chunk {
	my $value =3D pop @_;
	my $tag =3D shift @_;
	my $exclude =3D shift @_;
	my @others =3D @_;

	$tag =3D "COLUMN_$tag";

#::logDebug("$tag content length=3D" . length($value));

	die "duplicate tag settor $tag" if exists $outhash{$tag};
	$outhash{$tag} =3D $value;

	if(@others) {
		$alias{$tag} ||=3D [];
		push @{$alias{$tag}}, @others;
	}

	my $ctl =3D $controls[$ctl_index] ||=3D [];
	add_exclude($tag, $exclude) if $exclude;

	return unless length($value);

	push @$ctl, $tag;
	return;
}

sub chunk_alias {
	my $tag =3D shift;
	$alias{$tag} ||=3D [];
	push @{$alias{$tag}}, @_;
	return;
}

sub chunk {
	my $value =3D pop @_;
	my $tag =3D shift @_;
	my $exclude =3D shift @_;
	my @others =3D @_;

	die "duplicate tag settor $tag" if exists $outhash{$tag};
	$outhash{$tag} =3D $value;

#::logDebug("$tag content length=3D" . length($value));

	if(@others) {
		$alias{$tag} ||=3D [];
		push @{$alias{$tag}}, @others;
	}

	add_exclude($tag, $exclude) if $exclude;

	return unless length($value);
	push @out, $tag;
}

sub resolve_exclude {
	my $exc =3D shift;
	while(my ($k, $v) =3D each %exclude) {
::logDebug("examining $k for $v");
		while ($v =3D~ m{(\S+)}g) {
			my $thing =3D $1;
			if($thing =3D~ s/^[^A-Z]//) {
				$outhash{$k} =3D '' unless $exc->{$thing};
			}
			else {
				$outhash{$k} =3D '' if $exc->{$thing};
			}
		}
	}
}

sub editor_init {
	undef $base_entry_value;

	## Why?
	Vend::Interpolate::init_calc() if ! $Vend::Calc_initialized;
	@out =3D ();
	@controls =3D ();
	@titles =3D ();
	%outhash =3D ();
	%alias =3D ();
	$tab_number =3D $tcount_all =3D 0;
}

sub editor {

	my ($table, $key, $opt, $template) =3D @_;
show_times("begin table editor call item_id=3D$key") if $Global::ShowTimes;

	use vars qw/$Tag/;

	if(ref($opt->{all_opts}) eq 'HASH') {
		my $o =3D $opt->{all_opts};
		for (keys %$o ) {
			$opt->{$_} =3D $o->{$_};
		}
	}
	elsif ($opt->{all_opts}) {
		logError("%s: improper option %s, must be %s, was %s.",
					'table_editor',
					'all_opts',
					'hash',
					ref $opt->{all_opts},
					);
	}
#Debug("options now=3D" . ::uneval($opt));

	my @messages;
	my @errors;

	$table =3D $CGI->{mv_data_table}
		if ! $table and $opt->{cgi} and $CGI->{mv_data_table};

	### Need cleanup. Probably should bring in, along with
	### display tag.
	my $tmeta =3D meta_record($table, $opt->{ui_meta_view}) || {};

	FORMATS: {
		no strict 'refs';
		my $ref;
		for(qw/
					default=20=20=20=20=20
					error=20=20=20=20=20=20=20
					extra=20=20=20=20=20=20=20
					filter=20=20=20=20=20=20
					height=20=20=20=20=20=20
					help=20=20=20=20=20=20=20=20
					label=20=20=20=20=20=20=20
					override=20=20=20=20
					passed=20=20=20=20=20=20
					options=20=20=20=20=20=20
					outboard
					append
					prepend
					lookup
					lookup_query
					field
					pre_filter=20=20
					left_width
					widget=20=20=20=20=20=20
					width=20=20=20=20=20=20=20
					meta=20=20=20=20=20=20=20
				/ )
		{
			next if ref $opt->{$_};
			($opt->{$_} =3D {}, next) if ! $opt->{$_};
			my $ref =3D {};
			my $string =3D $opt->{$_};
			$string =3D~ s/^\s+//gm;
			$string =3D~ s/\s+$//gm;
			while($string =3D~ m/^(.+?)=3D\s*(.+)/mg) {
				$ref->{$1} =3D $2;
			}
			$opt->{$_} =3D $ref;
		}
	}

	my $rowcount =3D 0;
	my $action =3D $opt->{action} || 'set';
	my $wizard_next   =3D $opt->{wizard_next}   || 'return';
	my $wizard_cancel =3D $opt->{wizard_cancel} || 'back';
	my $rowdiv =3D $opt->{across} || 1;
	my $span =3D $rowdiv * 2;
	my $oddspan =3D $span - 1;
	my $def =3D $opt->{default_ref} || $::Values;

	my $check       =3D $opt->{check};
	my $default     =3D $opt->{default};
	my $error       =3D $opt->{error};
	my $extra       =3D $opt->{extra};
	my $filter      =3D $opt->{filter};
	my $height      =3D $opt->{height};
	my $help        =3D $opt->{help};
	my $help_url    =3D $opt->{help_url};
	my $label       =3D $opt->{label};
	my $override    =3D $opt->{override};
	my $pre_filter  =3D $opt->{pre_filter};
	my $passed      =3D $opt->{passed};
	my $options     =3D $opt->{options};
	my $outboard    =3D $opt->{outboard};
	my $prepend     =3D $opt->{prepend};
	my $append      =3D $opt->{append};
	my $lookup      =3D $opt->{lookup};
	my $lookup_query =3D $opt->{lookup_query};
	my $database    =3D $opt->{database};
	my $field       =3D $opt->{field};
	my $widget      =3D $opt->{widget};
	my $width       =3D $opt->{width};
	my $pmeta       =3D $opt->{meta};


	#my $blabel      =3D $opt->{begin_label} || '<b>';
	#my $elabel      =3D $opt->{end_label} || '</b>';
	my $blabel      ;
	my $elabel      ;
	my $mlabel =3D '';

	if($opt->{wizard}) {
		$opt->{noexport} =3D 1;
		$opt->{next_text} =3D 'Next -->' unless $opt->{next_text};
		$opt->{cancel_text} =3D 'Cancel' unless $opt->{cancel_text};
		$opt->{back_text} =3D '<-- Back' unless $opt->{back_text};
	}
	else {
		$opt->{cancel_text} =3D 'Cancel' unless $opt->{cancel_text};
		$opt->{next_text} =3D "Ok" unless $opt->{next_text};
	}

	for(qw/ next_text cancel_text back_text/ ) {
		$opt->{$_} =3D errmsg($opt->{$_});
	}

	my $ntext;
	my $btext;
	my $ctext;
	unless ($opt->{wizard} || $opt->{nosave}) {
		$::Scratch->{$opt->{next_text}} =3D $Tag->return_to('click', 1);
	}
	else {
		if($opt->{action_click}) {
			$ntext =3D <<EOF;
mv_todo=3D$wizard_next
ui_wizard_action=3DNext
mv_click=3D$opt->{action_click}
EOF
		}
		else {
			$ntext =3D <<EOF;
mv_todo=3D$wizard_next
ui_wizard_action=3DNext
mv_click=3Dui_override_next
EOF
		}
		$::Scratch->{$opt->{next_text}} =3D $ntext;

		my $hidgo =3D $opt->{mv_cancelpage} || $opt->{hidden}{ui_return_to} || $C=
GI->{return_to};
		$hidgo =3D~ s/\0.*//s;
		$ctext =3D $::Scratch->{$opt->{cancel_text}} =3D <<EOF;
mv_form_profile=3D
ui_wizard_action=3DCancel
mv_nextpage=3D$hidgo
mv_todo=3D$wizard_cancel
EOF
		if($opt->{mv_prevpage}) {
			$btext =3D $::Scratch->{$opt->{back_text}} =3D <<EOF;
mv_form_profile=3D
ui_wizard_action=3DBack
mv_nextpage=3D$opt->{mv_prevpage}
mv_todo=3D$wizard_next
EOF
		}
		else {
			delete $opt->{back_text};
		}
	}

	for(qw/next_text back_text cancel_text/) {
		$opt->{"orig_$_"} =3D $opt->{$_};
	}

	$::Scratch->{$opt->{next_text}}   =3D $ntext if $ntext;
	$::Scratch->{$opt->{cancel_text}} =3D $ctext if $ctext;
	$::Scratch->{$opt->{back_text}}   =3D $btext if $btext;

	$opt->{next_text} =3D HTML::Entities::encode($opt->{next_text}, $ESCAPE_CH=
ARS::std);
	$opt->{back_text} =3D HTML::Entities::encode($opt->{back_text}, $ESCAPE_CH=
ARS::std);
	$opt->{cancel_text} =3D HTML::Entities::encode($opt->{cancel_text});

	$::Scratch->{$opt->{next_text}}   =3D $ntext if $ntext;
	$::Scratch->{$opt->{cancel_text}} =3D $ctext if $ctext;
	$::Scratch->{$opt->{back_text}}   =3D $btext if $btext;

	if($opt->{wizard} || $opt->{notable} and ! $table) {
		$table =3D 'mv_null';
		$Vend::Database{mv_null} =3D=20
			bless [
					{},
					undef,
					[ 'code', 'value' ],
					[ 'code' =3D> 0, 'value' =3D> 1 ],
					0,
					{ },
					], 'Vend::Table::InMemory';
	}

	my @mapdirect =3D qw/
		mv_data_decode
		mv_data_table
		mv_blob_field
		mv_blob_nick
		mv_blob_pointer
		mv_blob_label
		mv_blob_title
		left_width
		table_width
		tabbed
		tab_bgcolor_template
		tab_height
		tab_width
		tab_cellspacing
		tab_cellpadding
		panel_height
		panel_width
		panel_id
		tab_horiz_offset
		tab_vert_offset
		ui_break_before
		ui_break_before_label
		ui_data_fields
		ui_data_fields_all
		ui_data_key_name
		ui_display_only
		ui_hide_key
		ui_meta_specific
		ui_meta_view
		ui_nextpage
		ui_new_item
		ui_delete_box
		mv_update_empty
	/;

	for(grep defined $tmeta->{$_}, @mapdirect) {
		$opt->{$_} ||=3D $tmeta->{$_};
	}

	if($opt->{cgi}) {
		unshift @mapdirect, qw/
				item_id
				item_id_left
				ui_clone_id
				ui_clone_tables
				ui_sequence_edit
		/;
		for(@mapdirect) {
			next if ! defined $CGI->{$_};
			$opt->{$_} =3D $CGI->{$_};
		}
		my @hmap =3D (
			[ qr/^ui_te_check:/, $check ],
			[ qr/^ui_te_default:/, $default ],
			[ qr/^ui_te_extra:/, $extra ],
			[ qr/^ui_te_widget:/, $widget ],
			[ qr/^ui_te_passed:/, $passed ],
			[ qr/^ui_te_options:/, $options ],
			[ qr/^ui_te_outboard:/, $outboard ],
			[ qr/^ui_te_prepend:/, $prepend ],
			[ qr/^ui_te_append:/, $append ],
			[ qr/^ui_te_lookup:/, $lookup ],
			[ qr/^ui_te_database:/, $database ],
			[ qr/^ui_te_field:/, $field ],
			[ qr/^ui_te_override:/, $override ],
			[ qr/^ui_te_filter:/, $filter ],
			[ qr/^ui_te_pre_filter:/, $pre_filter ],
			[ qr/^ui_te_height:/, $height ],
			[ qr/^ui_te_width:/, $width ],
			[ qr/^ui_te_help:/, $help ],
			[ qr/^ui_te_help_url:/, $help_url ],
		);
		my @cgi =3D keys %{$CGI};
		foreach my $row (@hmap) {
			my @keys =3D grep $_ =3D~ $row->[0], @cgi;
			for(@keys) {
				/^ui_\w+:(\S+)/
					and $row->[1]->{$1} =3D $CGI->{$_};
			}
		}
		$table =3D $opt->{mv_data_table};
		$key =3D $opt->{item_id};
	}

	$opt->{table_width} =3D '60%' if ! $opt->{table_width};
	$opt->{left_width}  =3D '30%' if ! $opt->{left_width};
	if (! $opt->{inner_table_width}) {
		if($opt->{table_width} =3D~ /%/) {
			$opt->{inner_table_width} =3D '100%';
		}
		elsif ($opt->{table_width} =3D~ /^\d+$/) {
			$opt->{inner_table_width} =3D $opt->{table_width} - 2;
		}
		else {
			$opt->{inner_table_width} =3D $opt->{table_width};
		}
	}

	$opt->{color_success} =3D $::Variable->{UI_C_SUCCESS} || '#00FF00'
		if ! $opt->{color_success};
	$opt->{color_fail} =3D $::Variable->{UI_CONTRAST} || '#FF0000'
		if ! $opt->{color_fail};
	### Build the error checking
	my $error_show_var =3D 1;
	my $have_errors;
	if($opt->{ui_profile} or $check) {
		$Tag->error( { all =3D> 1 } )
			unless $CGI->{mv_form_profile} or $opt->{keep_errors};
		my $prof =3D $opt->{ui_profile} || '';
		if ($prof =3D~ s/^\*//) {
			# special notation ui_profile=3D"*whatever" means
			# use automatic checklist-related profile
			my $name =3D $prof;
			$prof =3D $::Scratch->{"profile_$name"} || '';
			if ($prof) {
				$prof =3D~ s/^\s*(\w+)[\s=3D]+required\b/$1=3Dmandatory/mg;
				for (grep /\S/, split /\n/, $prof) {
					if (/^\s*(\w+)\s*=3D(.+)$/) {
						my $k =3D $1; my $v =3D $2;
						$v =3D~ s/\s+$//;
						$v =3D~ s/^\s+//;
						$error->{$k} =3D 1;
						$error_show_var =3D 0 if $v =3D~ /\S /;
					}
				}
				$prof =3D '&calc delete $Values->{step_'
					  . $name
					  . "}; return 1\n"
					  . $prof;
				$opt->{ui_profile_success} =3D "&set=3Dstep_$name 1";
			}
		}
		my $success =3D $opt->{ui_profile_success};
		# make sure profile so far ends with a newline so we can add more
		$prof .=3D "\n" unless $prof =3D~ /\n\s*\z/;
		if(ref $check) {
			while ( my($k, $v) =3D each %$check ) {
				$error->{$k} =3D 1;
				$v =3D~ s/\s+$//;
				$v =3D~ s/^\s+//;
				$v =3D~ s/\s+$//mg;
				$v =3D~ s/^\s+//mg;
				$v =3D~ s/^required\b/mandatory/mg;
				unless ($v =3D~ /^\&/m) {
					$error_show_var =3D 0 if $v =3D~ /\S /;
					$v =3D~ s/^/$k=3D/mg;
					$v =3D~ s/\n/\n&and\n/g;
				}
				$prof .=3D "$v\n";
			}
		}
		elsif ($check) {
			for (@_ =3D grep /\S/, split /[\s,]+/, $check) {
				$error->{$_} =3D 1;
				$prof .=3D "$_=3Dmandatory\n";
			}
		}
		$opt->{hidden} =3D {} if ! $opt->{hidden};
		$opt->{hidden}{mv_form_profile} =3D 'ui_profile';
		my $fail =3D $opt->{mv_failpage} || $Global::Variable->{MV_PAGE};

		# watch out for early interpolation here!
		$::Scratch->{ui_profile} =3D <<EOF;
[perl]
#Debug("cancel=3D'$opt->{orig_cancel_text}' back=3D'$opt->{orig_back_text}'=
 click=3D\$CGI->{mv_click}");
	my \@clicks =3D split /\\0/, \$CGI->{mv_click};
=09
	for( qq{$opt->{orig_cancel_text}}, qq{$opt->{orig_back_text}}) {
#Debug("compare is '\$_'");
		next unless \$_;
		my \$cancel =3D \$_;
		for(\@clicks) {
#Debug("click is '\$_'");
			return if \$_ eq \$cancel;=20
		}
	}
	# the following should already be interpolated by the table-editor tag
	# before going into scratch ui_profile
	return <<'EOP';
$prof
&fail=3D$fail
&fatal=3D1
$success
mv_form_profile=3Dmandatory
&set=3Dmv_todo $action
EOP
[/perl]
EOF
		$blabel =3D '<span style=3D"font-weight: normal">';
		$elabel =3D '</span>';
		$mlabel =3D ($opt->{message_label} || '&nbsp;&nbsp;&nbsp;<B>Bold</B> fiel=
ds are required');
		$have_errors =3D $Tag->error( {
									all =3D> 1,
									show_var =3D> $error_show_var,
									show_error =3D> 1,
									joiner =3D> '<BR>',
									keep =3D> 1}
									);
		if($opt->{all_errors}) {
			if($have_errors) {
				$mlabel .=3D '<P>Errors:';
				$mlabel .=3D qq{<FONT COLOR=3D"$opt->{color_fail}">};
				$mlabel .=3D "<BLOCKQUOTE>$have_errors</BLOCKQUOTE></FONT>";
			}
		}
	}
	### end build of error checking

	$opt->{clear_image} =3D "bg.gif" if ! $opt->{clear_image};

	my $die =3D sub {
		::logError(@_);
		$::Scratch->{ui_error} .=3D "<BR>\n" if $::Scratch->{ui_error};
		$::Scratch->{ui_error} .=3D ::errmsg(@_);
		return undef;
	};

	my $db;
	unless($opt->{notable}) {
		$db =3D Vend::Data::database_exists_ref($table)
		or return $die->('table-editor: bad table %s', $table);
	}

	if($opt->{ui_wizard_fields}) {
		$opt->{ui_data_fields} =3D $opt->{ui_display_only} =3D $opt->{ui_wizard_f=
ields};
	}

	my $keycol;
	if($opt->{notable}) {
		$keycol =3D $opt->{ui_data_key_name};
	}
	else {
		$keycol =3D $opt->{ui_data_key_name} || $db->config('KEY');
	}

	$opt->{form_extra} =3D~ s/^\s*/ /
		if $opt->{form_extra};

	$opt->{form_name} =3D qq{ NAME=3D"$opt->{form_name}"}
		if $opt->{form_name};

	###############################################################
	# Get the field display information including breaks and labels
	###############################################################
	if( ! $opt->{ui_data_fields} and ! $opt->{ui_data_fields_all}) {
		$opt->{ui_data_fields} =3D $tmeta->{ui_data_fields} || $tmeta->{options};
	}

	$opt->{ui_data_fields} =3D~ s/\r\n/\n/g;
	$opt->{ui_data_fields} =3D~ s/\r/\n/g;

	if($opt->{ui_data_fields} =3D~ /\n\n/) {
		my @breaks;
		my @break_labels;
		my $fstring =3D "\n\n$opt->{ui_data_fields}";
		while ($fstring =3D~ s/\n+(?:\n[ \t]*=3D(.*))?\n+[ \t]*(\w[:.\w]+)/\n$2/)=
 {
			push @breaks, $2;
			push @break_labels, "$2=3D$1" if $1;
		}
		$opt->{ui_break_before} =3D join(" ", @breaks)
			if ! $opt->{ui_break_before};
		$opt->{ui_break_before_label} =3D join(",", @break_labels)
			if ! $opt->{ui_break_before_label};
	}

	$opt->{ui_data_fields} ||=3D $opt->{mv_data_fields};

	if(! $opt->{ui_data_fields}) {
		if( $opt->{notable}) {
			::logError("table_editor: no place to get fields!");
			return '';
		}
		else {
			$opt->{ui_data_fields} =3D join " ", $db->columns();
		}
	}

	$opt->{ui_data_fields} =3D~ s/[,\0\s]+/ /g;
	###############################################################

	my $linecount;

	CANONCOLS: {
		my @cols =3D split /[,\0\s]/, $opt->{ui_data_fields};
		#@cols =3D grep /:/ || $db->column_exists($_), @cols;

		$opt->{ui_data_fields} =3D join " ", @cols;

		$linecount =3D scalar @cols;
	}

	my $url =3D $Tag->area('ui');

	my $key_message;
	if($opt->{ui_new_item} and ! $opt->{notable}) {
		if( ! $db->config('_Auto_number') ) {
			$db->config('AUTO_NUMBER', '000001');
			$key =3D $db->autonumber($key);
		}
		else {
			$key =3D '';
			$opt->{mv_data_auto_number} =3D 1;
			$key_message =3D errmsg('(new key will be assigned if left blank)');
		}
	}

	my $data;
	my $exists;

	if($opt->{notable}) {
		$data =3D {};
	}
	elsif($opt->{ui_clone_id} and $db->record_exists($opt->{ui_clone_id})) {
		$data =3D $db->row_hash($opt->{ui_clone_id})
			or
			return $die->('table-editor: row_hash function failed for %s.', $key);
		$data->{$keycol} =3D $key;
	}
	elsif ($db->record_exists($key)) {
		$data =3D $db->row_hash($key);
		$exists =3D 1;
	}

	if ($opt->{reload} and $have_errors) {
		if($data) {
			for(keys %$data) {
				$data->{$_} =3D $CGI->{$_}
					if defined $CGI->{$_};
			}
		}
		else {
			$data =3D { %$CGI };
		}
	}


	my $blob_data;
	my $blob_widget;
	if($opt->{mailto} and $opt->{mv_blob_field}) {
		$opt->{hidden}{mv_blob_only} =3D 1;
		$opt->{hidden}{mv_blob_nick}
			=3D $opt->{mv_blob_nick}
			|| POSIX::strftime("%Y%m%d%H%M%S", localtime());
	}
	elsif($opt->{mv_blob_field}) {
#::logDebug("checking blob");

		my $blob_pointer;
		$blob_pointer =3D $data->{$opt->{mv_blob_pointer}}
			if $opt->{mv_blob_pointer};
		$blob_pointer ||=3D $opt->{mv_blob_nick};
=09=09=09

		DOBLOB: {

			unless ( $db->column_exists($opt->{mv_blob_field}) ) {
				push @errors, ::errmsg(
									"blob field %s not in database.",
									$opt->{mv_blob_field},
								);
				last DOBLOB;
			}

			my $bstring =3D $data->{$opt->{mv_blob_field}};

#::logDebug("blob: bstring=3D$bstring");

			my $blob;

			if(length $bstring) {
				$blob =3D $Vend::Interpolate::safe_safe->reval($bstring);
				if($@) {
					push @errors, ::errmsg("error reading blob data: %s", $@);
					last DOBLOB;
				}
#::logDebug("blob evals to " . ::uneval_it($blob));

				if(ref($blob) !~ /HASH/) {
					push @errors, ::errmsg("blob data not a storage book.");
					undef $blob;
				}
			}
			else {
				$blob =3D {};
			}
			my %wid_data;
			my %url_data;
			my @labels =3D keys %$blob;
			for my $key (@labels) {
				my $ref =3D $blob->{$_};
				my $lab =3D $ref->{$opt->{mv_blob_label} || 'name'};
				if($lab) {
					$lab =3D~ s/,/&#44/g;
					$wid_data{$lab} =3D "$key=3D$key - $lab";
					$url_data{$lab} =3D $Tag->page( {
											href =3D> $Global::Variable->{MV_PAGE},
											form =3D> "
												item_id=3D$opt->{item_id}
												mv_blob_nick=3D$key
											",
										});
					$url_data{$lab} .=3D "$key - $lab</A>";
				}
				else {
					$wid_data{$key} =3D $key;
					$url_data{$key} =3D $Tag->page( {
											href =3D> $Global::Variable->{MV_PAGE},
											form =3D> "
												item_id=3D$opt->{item_id}
												mv_blob_nick=3D$key
											",
										});
					$url_data{$key} .=3D "$key</A>";
				}
			}
#::logDebug("wid_data is " . ::uneval_it(\%wid_data));
			$opt->{mv_blob_title} =3D "Stored settings"
				if ! $opt->{mv_blob_title};
			$opt->{mv_blob_title} =3D errmsg($opt->{mv_blob_title});

			$::Scratch->{Load} =3D <<EOF;
[return-to type=3Dclick stack=3D1 page=3D"$Global::Variable->{MV_PAGE}"]
ui_nextpage=3D
[perl]Log("tried to go to $Global::Variable->{MV_PAGE}"); return[/perl]
mv_todo=3Dback
EOF
#::logDebug("blob_pointer=3D$blob_pointer blob_nick=3D$opt->{mv_blob_nick}"=
);

			my $loaded_from;
			my $lfrom_msg;
			if( $opt->{mv_blob_nick} ) {
				$lfrom_msg =3D $opt->{mv_blob_nick};
			}
			else {
				$lfrom_msg =3D errmsg("current values");
			}
			$lfrom_msg =3D errmsg("loaded from %s", $lfrom_msg);
			$loaded_from =3D <<EOF;
<I>($lfrom_msg)</I><BR>
EOF
			if(@labels) {
				$loaded_from .=3D errmsg("Load from") . ":<BLOCKQUOTE>";
				$loaded_from .=3D  join (" ", @url_data{ sort keys %url_data });
				$loaded_from .=3D "</BLOCKQUOTE>";
			}

			my $checked;
			my $set;
			if( $opt->{mv_blob_only} and $opt->{mv_blob_nick}) {
				$checked =3D ' CHECKED';
				$set 	 =3D $opt->{mv_blob_nick};
			}

			unless ($opt->{nosave}) {
				$blob_widget =3D $Tag->widget({
									name =3D> 'mv_blob_nick',
									type =3D> $opt->{ui_blob_widget} || 'combo',
									filter =3D> 'nullselect',
									override =3D> 1,
									set =3D> "$set",
									passed =3D> join (",", @wid_data{ sort keys %wid_data }) || 'defau=
lt',
									});
				my $msg1 =3D errmsg('Save to');
				my $msg2 =3D errmsg('Save here only');
				for (\$msg1, \$msg2) {
					$$_ =3D~ s/ /&nbsp;/g;
				}
				$blob_widget =3D <<EOF unless $opt->{ui_blob_hidden};
<B>$msg1:</B> $blob_widget&nbsp;
<INPUT TYPE=3Dcheckbox NAME=3Dmv_blob_only VALUE=3D1$checked>&nbsp;$msg2</S=
MALL>
EOF
			}

			$blob_widget =3D <<EOF unless $opt->{ui_blob_hidden};
<TR class=3Drnorm>
	 <td class=3Dclabel width=3D"$opt->{left_width}">
	   <SMALL>$opt->{mv_blob_title}<BR>
		$loaded_from
	 </td>
	 <td class=3Dcwidget>
	 	$blob_widget&nbsp;
	 </td>
</TR>

<tr class=3Drtitle>
<td colspan=3D$span><img src=3D"$opt->{clear_image}" width=3D1 height=3D3 a=
lt=3Dx></td>
</tr>
EOF

		if($opt->{mv_blob_nick}) {
			my @keys =3D split /::/, $opt->{mv_blob_nick};
			my $ref =3D $blob->{shift @keys};
			for(@keys) {
				my $prior =3D $ref;
				undef $ref;
				eval {
					$ref =3D $prior->{$_};
				};
				last DOBLOB unless ref $ref;
			}
			for(keys %$ref) {
				$data->{$_} =3D $ref->{$_};
			}
		}

		}
	}

#::logDebug("data is: " . ::uneval($data));
	$data =3D { $keycol =3D> $key }
		if ! $data;

	if(! $opt->{mv_data_function}) {
		$opt->{mv_data_function} =3D $exists ? 'update' : 'insert';
	}

	$opt->{mv_nextpage} =3D $Global::Variable->{MV_PAGE} if ! $opt->{mv_nextpa=
ge};
	$opt->{mv_update_empty} =3D 1 unless defined $opt->{mv_update_empty};

	my $url_base =3D $opt->{secure} ? $Vend::Cfg->{SecureURL} : $Vend::Cfg->{V=
endURL};

	$opt->{href} =3D "$url_base/ui" if ! $opt->{href};
	$opt->{href} =3D "$url_base/$opt->{href}"
		if $opt->{href} !~ m{^(https?:|)/};

	my $sidstr;
	if ($opt->{get}) {
		$opt->{method} =3D 'GET';
		$sidstr =3D '';
	} else {
		$opt->{method} =3D 'POST';
		$sidstr =3D qq{<INPUT TYPE=3Dhidden NAME=3Dmv_session_id VALUE=3D"$Vend::=
Session->{id}">
};
	}
	$opt->{enctype} =3D $opt->{file_upload} ? ' ENCTYPE=3D"multipart/form-data=
"' : '';

	my $wo =3D $opt->{widgets_only};

	my $restrict_begin;
	my $restrict_end;
	if($opt->{reparse} and ! $opt->{promiscuous}) {
		$restrict_begin =3D qq{[restrict allow=3D"$opt->{restrict_allow}"]};
		$restrict_end =3D '[/restrict]';
	}

	no strict 'subs';

	chunk 'FORM_BEGIN', 'WO', 'TOP_PORTION', <<EOF; # unless $wo;
$restrict_begin<FORM METHOD=3D$opt->{method} ACTION=3D"$opt->{href}"$opt->{=
form_name}$opt->{enctype}$opt->{form_extra}>
$sidstr<INPUT TYPE=3Dhidden NAME=3Dmv_todo VALUE=3D"$action">
<INPUT TYPE=3Dhidden NAME=3Dmv_click VALUE=3D"process_filter">
<INPUT TYPE=3Dhidden NAME=3Dmv_nextpage VALUE=3D"$opt->{mv_nextpage}">
<INPUT TYPE=3Dhidden NAME=3Dmv_data_table VALUE=3D"$table">
<INPUT TYPE=3Dhidden NAME=3Dmv_data_key VALUE=3D"$keycol">
EOF

	my @opt_set =3D (qw/
						ui_meta_specific
						ui_hide_key
						ui_meta_view
						ui_data_decode
						mv_blob_field
						mv_blob_label
						mv_blob_title
						mv_blob_pointer
						mv_update_empty
						mv_data_auto_number
						mv_data_function
				/ );

	my @cgi_set =3D ( qw/
						item_id_left
						ui_sequence_edit
					/ );

	push(@opt_set, splice(@cgi_set, 0)) if $opt->{cgi};

  OPTSET: {
  	my @o;
	for(@opt_set) {
		next unless length $opt->{$_};
		my $val =3D $opt->{$_};
		$val =3D~ s/"/&quot;/g;
		push @o, qq{<INPUT TYPE=3Dhidden NAME=3D$_ VALUE=3D"$val">\n}; # unless $=
wo;
	}
	chunk 'HIDDEN_OPT', '', 'TOP_PORTION', join("", @o);
  }

  CGISET: {
	my @o;
	for (@cgi_set) {
		next unless length $CGI->{$_};
		my $val =3D $CGI->{$_};
		$val =3D~ s/"/&quot;/g;
		push @o, qq{<INPUT TYPE=3Dhidden NAME=3D$_ VALUE=3D"$val">\n}; # unless $=
wo;
	}
	chunk 'HIDDEN_CGI', join("", @o);
  }

	if($opt->{mailto}) {
		$opt->{mailto} =3D~ s/\s+/ /g;
		$::Scratch->{mv_email_enable} =3D $opt->{mailto};
		$opt->{hidden}{mv_data_email} =3D 1;
	}

	$Vend::Session->{ui_return_stack} ||=3D [];

	if($opt->{cgi}) {
		my $r_ary =3D $Vend::Session->{ui_return_stack};

#::logDebug("ready to maybe push/pop return-to from stack, stack =3D " . ::=
uneval($r_ary));
		if($CGI::values{ui_return_stack}++) {
			push @$r_ary, $CGI::values{ui_return_to};
			$CGI::values{ui_return_to} =3D $r_ary->[0];
		}
		elsif ($CGI::values{ui_return_to}) {
			@$r_ary =3D ( $CGI::values{ui_return_to} );=20
		}
		chunk 'RETURN_TO', 'WO', $Tag->return_to(); # unless $wo;
#::logDebug("return-to stack =3D " . ::uneval($r_ary));
	}

	if(ref $opt->{hidden}) {
		my ($hk, $hv);
		my @o;
		while ( ($hk, $hv) =3D each %{$opt->{hidden}} ) {
			push @o, qq{<INPUT TYPE=3Dhidden NAME=3D"$hk" VALUE=3D"$hv">\n};
		}
		chunk 'HIDDEN', 'WO', join("", @o); # unless $wo;
	}

	my $tcount_all =3D 0;
=09
	my $tcount_top =3D 0;
	my $tcount_bot =3D 0;
	chunk ttag(), 'WO', <<EOF; # unless $wo;
<table class=3Dtouter border=3D"0" cellspacing=3D"0" cellpadding=3D"0" widt=
h=3D"$opt->{table_width}">
<tr>
  <td>

<table class=3Dtinner  width=3D"$opt->{inner_table_width}" cellspacing=3D0 =
cellmargin=3D0 width=3D"100%" cellpadding=3D"2" align=3D"center" border=3D"=
0">
EOF
	chunk ttag(), 'NO_TOP', <<EOF; # unless $opt->{no_top} or $wo;
<tr class=3Drtitle>=20
<td align=3Dright colspan=3D$span><img src=3D"$opt->{clear_image}" width=3D=
1 height=3D3 alt=3Dx></td>
</tr>
EOF

	  #### Extra buttons
      my $extra_ok =3D	$blob_widget
	  					|| $linecount > 4
						|| defined $opt->{include_form}
						|| $mlabel;
	if ($extra_ok and ! $opt->{no_top} and ! $opt->{nosave}) {
	  	if($opt->{back_text}) {
		  chunk ttag(), 'WO', <<EOF; # unless $wo;
<TR class=3Drnorm>
<td>&nbsp;</td>
<td align=3Dleft colspan=3D$oddspan class=3Dcdata>
EOF
			chunk 'WIZARD_BUTTONS_TOP', 'BOTTOM_BUTTONS', <<EOF; # if ! $opt->{botto=
m_buttons};
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{back_text}">&nbsp;<INP=
UT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}">&nbsp;<B><IN=
PUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{next_text}"></B>
<BR>
EOF
			chunk 'MLABEL', 'WO', $mlabel;
			chunk_alias 'MLABEL', 'FORM_TOP';
			chunk ttag(), <<EOF;
</TD>
</TR>

<tr class=3Drspacer>
<td colspan=3D$span><img src=3D"$opt->{clear_image}" width=3D1 height=3D3 a=
lt=3Dx></td>
</tr>
EOF
		}
		elsif ($opt->{wizard}) {
		  chunk ttag(), 'NO_TOP', <<EOF;
<TR class=3Drnorm>
<td>&nbsp;</td>
<td align=3Dleft colspan=3D$oddspan class=3Dcdata>
EOF
			chunk 'WIZARD_BUTTONS_TOP', 'BOTTOM_BUTTONS', <<EOF; # if ! $opt->{botto=
m_buttons};
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}">&nbsp;<B=
><INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{next_text}"></B>
<BR>
EOF
			chunk 'MLABEL', 'BOTTOM_BUTTONS', $mlabel;
			chunk ttag(), <<EOF;
</TD>
</TR>

<tr class=3Drspacer>
<td colspan=3D$span><img src=3D"$opt->{clear_image}" width=3D1 height=3D3 a=
lt=3Dx></td>
</tr>
EOF
		}
		else {
		  chunk ttag(), 'BOTTOM_BUTTONS', <<EOF;
<TR class=3Drnorm>
<td>&nbsp;</td>
<td align=3Dleft colspan=3D$oddspan class=3Dcdata>
EOF

		  $opt->{ok_button_style} =3D 'font-weight: bold; width: 40px; text-align=
: center'
		  	unless defined $opt->{ok_button_style};
=09=09=20=20=09
		  chunk 'OK_TOP', 'BOTTOM_BUTTONS', <<EOF;
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{next_text}" style=3D"$=
opt->{ok_button_style}">
EOF
		  chunk ttag(), 'NOCANCEL BOTTOM_BUTTONS', <<EOF; # unless $opt->{nocance=
l};
&nbsp;
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}" style=3D=
"$opt->{cancel_button_style}">
EOF

		  chunk 'RESET_TOP', '_SHOW_RESET BOTTOM_BUTTONS', <<EOF;
&nbsp;
<INPUT TYPE=3Dreset>
EOF

			chunk 'MLABEL', 'BOTTOM_BUTTONS', $mlabel;
			chunk ttag(), 'BOTTOM_BUTTONS', , <<EOF;
</TD>
</TR>

<tr class=3Drspacer>
<td colspan=3D$span><img src=3D"$opt->{clear_image}" width=3D1 height=3D3 a=
lt=3Dx></td>
</tr>
EOF
		}
	}

	chunk 'BLOB_WIDGET', $blob_widget; # unless $wo;

	  #### Extra buttons

	if($opt->{ui_new_item} and $opt->{ui_clone_tables}) {
		my @sets;
		my %seen;
		my @tables =3D split /[\s\0,]+/, $opt->{ui_clone_tables};
		for(@tables) {
			if(/:/) {
				push @sets, $_;
			}
			s/:.*//;
		}

		my %tab_checked;
		for(@tables, @sets) {
			$tab_checked{$_} =3D 1 if s/\*$//;
		}

		@tables =3D grep ! $seen{$_}++ && defined $Vend::Cfg->{Database}{$_}, @ta=
bles;

		my $tab =3D '';
		my $set .=3D <<'EOF';
[flag type=3Dwrite table=3D"_TABLES_"]
[perl tables=3D"_TABLES_"]
	delete $::Scratch->{clone_tables};
	return if ! $CGI->{ui_clone_id};
	return if ! $CGI->{ui_clone_tables};
	my $id =3D $CGI->{ui_clone_id};

	my $out =3D "Cloning id=3D$id...";

	my $new =3D  $CGI->{$CGI->{mv_data_key}}
		or do {
				$out .=3D ("clone $id: no mv_data_key '$CGI->{mv_data_key}'");
				$::Scratch->{ui_message} =3D $out;
				return;
		};

	if($new =3D~ /\0/) {
		$new =3D~ s/\0/,/g;
		Log("cannot clone multiple keys '$new'.");
		return;
	}

	my %possible;
	my @possible =3D qw/_TABLES_/;
	@possible{@possible} =3D @possible;
	my @tables =3D grep /\S/, split /[\s,\0]+/, $CGI->{ui_clone_tables};
	my @sets =3D grep /:/, @tables;
	@tables =3D grep $_ !~ /:/, @tables;
	for(@tables) {
		next unless $possible{$_};
		my $db =3D database_exists_ref($_);
		next unless $db;
		my $new =3D=20
		my $res =3D $db->clone_row($id, $new);
		if($res) {
			$out .=3D "cloned $id to to $new in table $_<BR>\n";
		}
		else {
			$out .=3D "FAILED clone of $id to to $new in table $_<BR>\n";
		}
	}
	for(@sets) {
		my ($t, $col) =3D split /:/, $_;
		my $db =3D database_exists_ref($t) or next;
		my $res =3D $db->clone_set($col, $id, $new);
		if($res) {
			$out .=3D "cloned $col=3D$id to to $col=3D$new in table $t<BR>\n";
		}
		else {
			$out .=3D "FAILED clone of $col=3D$id to to $col=3D$new in table $t<BR>\=
n";
		}
	}
	$::Scratch->{ui_message} =3D $out;
	return;
[/perl]
EOF
		my $tabform =3D '';
		@tables =3D grep $Tag->if_mm( { table =3D> "$_=3Di" } ), @tables;

		for(@tables) {
			my $db =3D Vend::Data::database_exists_ref($_)
				or next;
			next unless $db->record_exists($opt->{ui_clone_id});
			my $checked =3D $tab_checked{$_} ? ' CHECKED' : '';
			$tabform .=3D <<EOF;
<INPUT TYPE=3DCHECKBOX NAME=3Dui_clone_tables VALUE=3D"$_"$checked> clone t=
o <b>$_</B><BR>
EOF
		}
		for(@sets) {
			my ($t, $col) =3D split /:/, $_;
			my $checked =3D $tab_checked{$_} ? ' CHECKED' : '';
			$tabform .=3D <<EOF;
<INPUT TYPE=3DCHECKBOX NAME=3Dui_clone_tables VALUE=3D"$_"$checked> clone e=
ntries of <b>$t</B> matching on <B>$col</B><BR>
EOF
		}

		my $tabs =3D join " ", @tables;
		$set =3D~ s/_TABLES_/$tabs/g;
		$::Scratch->{clone_tables} =3D $set;
		chunk ttag(), <<EOF; # unless $wo;
<tr class=3Drtitle>
<td colspan=3D$span>
EOF
		chunk 'CLONE_TABLES', <<EOF;
$tabform<INPUT TYPE=3Dhidden NAME=3Dmv_check VALUE=3D"clone_tables">
<INPUT TYPE=3Dhidden NAME=3Dui_clone_id VALUE=3D"$opt->{ui_clone_id}">
EOF
		chunk ttag(), <<EOF; # unless $wo;
</td>
</tr>
EOF
	}

	my %break;
	my %break_label;
	if($opt->{ui_break_before}) {
		my @tmp =3D grep /\S/, split /[\s,\0]+/, $opt->{ui_break_before};
		@break{@tmp} =3D @tmp;
		if($opt->{ui_break_before_label}) {
			@tmp =3D grep /\S/, split /\s*[,\0]\s*/, $opt->{ui_break_before_label};
			for(@tmp) {
				my ($br, $lab) =3D split /\s*=3D\s*/, $_;
				$break_label{$br} =3D $lab;
			}
		}
	}
	if(!$db and ! $opt->{notable}) {
		return "<TR><TD>Broken table '$table'</TD></TR>";
	}

	my $passed_fields =3D $opt->{ui_data_fields};

	my @extra_cols;
	my %email_cols;
	my %ok_col;
	my @cols;
	my @dbcols;
	my %display_only;

	if($opt->{notable}) {
		@cols =3D split /[\s,\0]+/, $passed_fields;
	}
	else {

	while($passed_fields =3D~ s/(\w+[.:]+\S+)//) {
		push @extra_cols, $1;
	}

	my @do =3D grep /\S/, split /[\0,\s]+/, $opt->{ui_display_only};
	for(@do) {
		$email_cols{$_} =3D 1 if $opt->{mailto};
		$display_only{$_} =3D 1;
		push @extra_cols, $_;
	}

		@dbcols  =3D split /\s+/, $Tag->db_columns( {
										name	=3D> $table,
										columns	=3D> $passed_fields,
										passed_order =3D> 1,
									});

	if($opt->{ui_data_fields}) {
		for(@dbcols, @extra_cols) {
			unless (/^(\w+)([.:]+)(\S+)/) {
				$ok_col{$_} =3D 1;
				next;
			}
			my $t =3D $1;
			my $s =3D $2;
			my $c =3D $3;
			if($s eq '.') {
				$c =3D $t;
				$t =3D $table;
			}
			else {
				$c =3D~ s/\..*//;
			}
			next unless $Tag->db_columns( { name	=3D> $t, columns	=3D> $c, });
			$ok_col{$_} =3D 1;
		}
	}
	@cols =3D grep $ok_col{$_}, split /\s+/, $opt->{ui_data_fields};
	}

	$keycol =3D $cols[0] if ! $keycol;

	if($opt->{defaults}) {
			if($opt->{force_defaults}) {
			$default->{$_} =3D $def->{$_} for @cols;
			}
			elsif($opt->{wizard}) {
			for(@cols) {
				$default->{$_} =3D $def->{$_} if defined $def->{$_};
			}
		}
			else {
			for(@cols) {
				next if defined $default->{$_};
				next unless defined $def->{$_};
				$default->{$_} =3D $def->{$_};
			}
		}
	}

	my $super =3D $Tag->if_mm('super');

	my $refkey =3D $key;

	my @data_enable =3D ($opt->{mv_blob_pointer}, $opt->{mv_blob_field});
	my @ext_enable;

	# Init the cell stuff
	my %td_extra;
	my %td_default =3D (
			widget_cell_class	=3D> 'cwidget',
			label_cell_class	=3D> 'clabel',
			data_cell_class	=3D> 'cdata',
			help_cell_class	=3D> 'chelp',
	);

	for my $ctype (qw/label data widget help/) {
		$td_extra{$ctype} =3D '';
		for my $ptype (qw/class style align valign width/) {
			my $parm =3D $ctype . '_cell_' . $ptype;
			if(defined $opt->{$parm}) {
				$td_extra{$ctype} .=3D qq{ $ptype=3D"$opt->{$parm}"};
			}
			elsif ($td_default{$parm}) {
				$td_extra{$ctype} .=3D qq{ $ptype=3D"$td_default{$parm}"};
			}
		}
		if(my $thing =3D $opt->{$ctype . "_cell_extra"}) {
			$td_extra{$ctype} .=3D " $thing";
		}
	}

	if($opt->{left_width} and ! $opt->{label_cell_width}) {
		$td_extra{label} .=3D qq{ width=3D"$opt->{left_width}"};
	}

	my $show_meta;
	if($super and ! $opt->{no_meta}) {
		$show_meta =3D defined $def->{ui_meta_force}
					?  $def->{ui_meta_force}
					: $::Variable->{UI_META_LINK};
	}

	if($show_meta) {
		if(! $opt->{row_template} and ! $opt->{simple_row}) {
			$opt->{meta_prepend} =3D '<br><font size=3D1>'
				unless defined $opt->{meta_prepend};

			$opt->{meta_append} =3D '</font>'
				unless defined $opt->{meta_append};
		}
		else {
			$opt->{meta_prepend} ||=3D '';
			$opt->{meta_append} ||=3D '';
		}
		$opt->{meta_anchor} ||=3D errmsg('meta');
		$opt->{meta_anchor_specific} ||=3D errmsg('item-specific meta');
		$opt->{meta_extra} =3D " $opt->{meta_extra}"
			if $opt->{meta_extra};
		$opt->{meta_extra} ||=3D "";
		$opt->{meta_extra} .=3D qq{ class=3D"$opt->{meta_class}"}
			if $opt->{meta_class};
		$opt->{meta_extra} .=3D qq{ class=3D"$opt->{meta_style}"}
			if $opt->{meta_style};
	}

 	my $row_template =3D $opt->{row_template};
=09
	if(! $row_template) {
		if($opt->{simple_row}) {
			$opt->{help_anchor} ||=3D 'help';
			$row_template =3D <<EOF;
   <td$td_extra{label}>=20
     $blabel\$LABEL\$$elabel
   </td>
   <td$td_extra{widget}>\$WIDGET\${HELP_EITHER}&nbsp;<a href=3D"\$HELP_URL\=
$" title=3D"\$HELP\$">$opt->{help_anchor}</a>{/HELP_EITHER}&nbsp;{META_URL}=
<A HREF=3D"\$META_URL\$">$opt->{meta_anchor}</A>{/META_URL}
   </td>
EOF
		}
		else {
			$row_template =3D <<EOF;
   <td$td_extra{label}>=20
     $blabel\$LABEL\$$elabel~META~
   </td>
   <td$td_extra{data}>
     <table cellspacing=3D0 cellmargin=3D0 width=3D"100%">
       <tr>=20
         <td$td_extra{widget}>
           \$WIDGET\$
         </td>
         <td$td_extra{help}>~TKEY~<i>\$HELP\$</i>{HELP_URL}<BR><A HREF=3D"\=
$HELP_URL\$">help</A>{/HELP_URL}</FONT></td>
       </tr>
     </table>
   </td>
EOF
		}
	}

	$row_template =3D~ s/~OPT:(\w+)~/$opt->{$1}/g;
	$row_template =3D~ s/~BLABEL~/$blabel/g;
	$row_template =3D~ s/~ELABEL~/$elabel/g;
	$row_template =3D~ s/~([A-Z]+)_EXTRA~/$td_extra{lc $1}/g;

	my %serialize;
	my %serial_data;

	if(my $jsc =3D $opt->{js_changed}) {
		$jsc =3D~ /^\w+$/
			and $jsc =3D qq{onChange=3D"$jsc} . q{('$$KEY$$','$$COL$$');"};
		foreach my $c (@cols) {
			next if $extra->{$c} =3D~ /\bonchange\s*=3D/i;
			my $tpl =3D $jsc;
			$tpl .=3D $extra->{$c} if length $extra->{$c};
			$tpl =3D~ s/\$\$KEY\$\$/$key/g;
			$tpl =3D~ s/\$\$COL\$\$/$c/g;
			if ($extra->{$c} and $extra->{$c} =3D~ /\bonchange\s*=3D/i) {
				$tpl =3D~ s/onChange=3D"//;
				$tpl =3D~ s/"\s*$/;/;
				$extra->{$c} =3D~ s/\b(onchange\s*=3D\s*["'])/$1$tpl/i;
			}
			else {
				$extra->{$c} =3D $tpl;
			}
		}
	}

	my %link_row;
	my %link_before;
	if($opt->{link_table} and $key) {
		my @ltable;
		my @lfields;
		my @lkey;
		my @lview;
		my @llab;
		my @ltpl;
		my @lbefore;
		my @lsort;
		my $tcount =3D 1;
		if(ref($opt->{link_table}) eq 'ARRAY') {
			@ltable  =3D @{$opt->{link_table}};
			@lfields =3D @{$opt->{link_fields}};
			@lview   =3D @{$opt->{link_view}};
			@lkey    =3D @{$opt->{link_key}};
			@llab    =3D @{$opt->{link_label}};
			@ltpl    =3D @{$opt->{link_template}};
			@lbefore =3D @{$opt->{link_before}};
			@lsort   =3D @{$opt->{link_sort}};
		}
		else {
			@ltable  =3D $opt->{link_table};
			@lfields =3D $opt->{link_fields};
			@lview   =3D $opt->{link_view};
			@lkey    =3D $opt->{link_key};
			@llab    =3D $opt->{link_label};
			@ltpl    =3D $opt->{link_template};
			@lbefore =3D $opt->{link_before};
			@lsort   =3D $opt->{link_sort};
		}
		while(my $lt =3D shift @ltable) {
			my $lf =3D shift @lfields;
			my $lv =3D shift @lview;
			my $lk =3D shift @lkey;
			my $ll =3D shift @lkey;
			my $lb =3D shift @lbefore;
			my $ls =3D shift @lsort;

			my $rcount =3D 0;

			$ll ||=3D errmsg("Settings in table %s linked by %s", $lt, $lk);

			my $tpl =3D $row_template;
			my $ldb =3D database_exists_ref($lt)
				or do {
					logError("Bad table editor link table: %s", $lt);
					next;
				};

			my $lmeta =3D $Tag->meta_record($lt, $lv);
			$lf ||=3D $lmeta->{spread_fields};

			my $l_pkey =3D $ldb->config('KEY');

			my @cf =3D grep /\S/, split /[\s,\0]+/, $lf;
			@cf =3D grep $_ ne $l_pkey, @cf;
			$lf =3D join " ", @cf;
			my $lextra =3D $opt->{link_extra} || '';
			$lextra =3D " $lextra" if $lextra;
			my $labside =3D <<EOF;
<input type=3Dhidden name=3D"mv_data_table__$tcount" value=3D"$lt">
<input type=3Dhidden name=3D"mv_data_fields__$tcount" value=3D"$lf">
<input type=3Dhidden name=3D"mv_data_multiple__$tcount" value=3D"1">
<input type=3Dhidden name=3D"mv_data_key__$tcount" value=3D"$l_pkey">
$ll
EOF

			my @lout =3D q{<table cellspacing=3D0 cellpadding=3D1>};
			push @lout, qq{<tr><td$lextra>$l_pkey</td>};
			push @lout, $Tag->row_edit({ table =3D> $lt, columns =3D> $lf });
			push @lout, '</tr>';

			my $tname =3D $ldb->name();
			my $lfor =3D $key;
			$lfor =3D $ldb->quote($key, $lk);
			my $q =3D "SELECT $l_pkey FROM $tname WHERE $lk =3D $lfor";
			$q .=3D " ORDER BY $ls" if $ls;
			my $ary =3D $ldb->query($q);
			for(@$ary) {
				my $rk =3D $_->[0];
				my $pp =3D $rcount ? "${rcount}_" : '';
				my $hid =3D qq{<input type=3Dhidden name=3D"$pp${l_pkey}__$tcount" valu=
e=3D"};
				$hid .=3D HTML::Entities::encode($rk);
				$hid .=3D qq{">};
				push @lout, qq{<tr><td$lextra>$rk$hid</td>};
				my %o =3D (
					table =3D> $lt,
					key =3D> $_->[0],
					extra =3D> $opt->{link_extra},
					pointer =3D> $rcount,
					stacker =3D> $tcount,
					columns =3D> $lf,
					extra =3D> $opt->{link_extra},
				);
				$rcount++;
				push @lout, $Tag->row_edit(\%o);
				push @lout, "</tr>";
			}
			my %o =3D (
				table =3D> $lt,
				blank =3D> 1,
				extra =3D> $opt->{link_extra},
				pointer =3D> 999999,
				stacker =3D> $tcount,
				columns =3D> $lf,
				extra =3D> $opt->{link_extra},
			);
			push @lout, qq{<tr><td$lextra>};
			push @lout, qq{<input size=3D8 name=3D"999999_${l_pkey}__$tcount" value=
=3D"">};
			push @lout, '</td>';
			push @lout, $Tag->row_edit(\%o);
			push @lout, '</tr>';
			push @lout, "</table>";
			$tpl =3D~ s{\$LABEL\$}{$labside}g;
			$tpl =3D~ s{\$WIDGET\$}{join "", @lout}ge;
			my $murl =3D '';
			if($show_meta) {
				$murl =3D $Tag->page({
							href =3D> 'admin/db_metaconfig_spread',
							form =3D> qq(
									ui_table=3D$lt
									ui_view=3D$lv
								),
							});
				$murl .=3D errmsg('meta');
				$murl .=3D '</a>';
			}
			$tpl =3D~ s{\~META\~}{$murl}g;
			$tpl =3D~ s{\$HELP\$}{}g;
			$tpl =3D~ s{\~TKEY\~}{}g;
			$tpl =3D~ s!{HELP_URL}.*?{/HELP_URL}!!gs;
			$link_row{$lt} =3D $tpl;
			if($lb) {
				$link_before{$lb} =3D $lt;
			}
			my $mde_key =3D "mv_data_enable__$tcount";
			$::Scratch->{$mde_key} =3D "$lt:" . join(",", $l_pkey, @cf) . ':';
			$tcount++;
		}
	}

	if($opt->{tabbed}) {
		chunk ttag(), qq{<tr><td colspan=3D$span>\n};
	}

	foreach my $col (@cols) {
		if($link_before{$col}) {
			col_chunk "SPREAD_$link_before{$col}", delete $link_row{$link_before{$co=
l}};
		}
		my $t;
		my $c;
		my $k;
		my $tkey_message;
		if($col eq $keycol) {
			if($opt->{ui_hide_key}) {
				my $kval =3D $key || $override->{$col} || $default->{$col};
				col_chunk $col, <<EOF;
	<INPUT TYPE=3Dhidden NAME=3D"$col" VALUE=3D"$kval">
EOF
				next;
			}
			elsif ($opt->{ui_new_item}) {
				$tkey_message =3D $key_message;
			}
		}

		my $w =3D '';
		my $do =3D $display_only{$col};
=09=09
		my $currval;
		my $serialize;

		if($col =3D~ /(\w+):+([^:]+)(?::+(\S+))?/) {
			$t =3D $1;
			$c =3D $2;
			$c =3D~ /(.+?)\.\w.*/
				and $col =3D "$t:$1"
					and $serialize =3D $c;
			$k =3D $3 || undef;
			push @ext_enable, ("$t:$c" . $k ? ":$k" : '')
				unless $do;
		}
		else {
			$t =3D $table;
			$c =3D $col;
			$c =3D~ /(.+?)\.\w.*/
				and $col =3D $1
					and $serialize =3D $c;
			push @data_enable, $col
				unless $do and ! $opt->{mailto};
		}

		my $type;
		my $overridden;

		$currval =3D $data->{$col} if defined $data->{$col};
		if ($opt->{force_defaults} or defined $override->{$c} ) {
			$currval =3D $override->{$c};
			$overridden =3D 1;
#::logDebug("hit override for $col,currval=3D$currval");
		}
		elsif (defined $CGI->{"ui_preload:$t:$c"} ) {
			$currval =3D delete $CGI->{"ui_preload:$t:$c"};
			$overridden =3D 1;
#::logDebug("hit preload for $col,currval=3D$currval");
		}
		elsif( ($do && ! $currval) or $col =3D~ /:/) {
			if(defined $k) {
				my $check =3D $k;
				undef $k;
				for( $override, $data, $default) {
					next unless defined $_->{$check};
					$k =3D $_->{$check};
					last;
				}
			}
			else {
				$k =3D defined $key ? $key : $refkey;
			}
			$currval =3D tag_data($t, $c, $k) if defined $k;
#::logDebug("hit display_only for $col, t=3D$t, c=3D$c, k=3D$k, currval=3D$=
currval");
		}
		elsif (defined $default->{$c} and ! length($data->{$c}) ) {
			$currval =3D $default->{$c};
#::logDebug("hit preload for $col,currval=3D$currval");
		}
		else {
#::logDebug("hit data->col for $col, t=3D$t, c=3D$c, k=3D$k, currval=3D$cur=
rval");
			$currval =3D length($data->{$col}) ? $data->{$col} : '';
			$overridden =3D 1;
		}

		my $namecol;
		if($serialize) {
#Debug("serialize=3D$serialize");
			if($serialize{$col}) {
				push @{$serialize{$col}}, $serialize;
			}
			else {
				my $sd;
				if($col =3D~ /:/) {
					my ($tt, $tc) =3D split /:+/, $col;
					$sd =3D tag_data($tt, $tc, $k);
				}
				else {
					$sd =3D $data->{$col} || $def->{$col};
				}
#Debug("serial_data=3D$sd");
				$serial_data{$col} =3D $sd;
				$opt->{hidden}{$col} =3D $data->{$col};
				$serialize{$col} =3D [$serialize];
			}
			$c =3D~ /\.(.*)/;
			my $hk =3D $1;
#Debug("fetching serial_data for $col hk=3D$hk data=3D$serial_data{$col}");
			$currval =3D dotted_hash($serial_data{$col}, $hk);
#Debug("fetched hk=3D$hk value=3D$currval");
			$overridden =3D 1;
			$namecol =3D $c =3D $serialize;
		}

		$namecol =3D $col unless $namecol;

		$type =3D 'value' if $do and ! ($opt->{wizard} || ! $opt->{mailto});

		if (! length $currval and defined $default->{$c}) {
			$currval =3D $default->{$c};
		}

		my $template =3D $row_template;
		if($error->{$c}) {
			my $parm =3D {
					name =3D> $c,
					std_label =3D> '$LABEL$',
					required =3D> 1,
					};
			if($opt->{all_errors}) {
				$parm->{keep} =3D 1;
				$parm->{text} =3D <<EOF;
<FONT COLOR=3D"$opt->{color_fail}">\$LABEL\$</FONT><!--%s-->
[else]{REQUIRED <B>}{LABEL}{REQUIRED </B>}[/else]
EOF
			}
			$template =3D~ s/\$LABEL\$/$Tag->error($parm)/eg;
		}

		my $meta =3D '';
		my $meta_url;
		my $meta_url_specific;
		if($show_meta) {
			# Get global variables
			my $base =3D $::Variable->{UI_BASE}
					 || $Global::Variable->{UI_BASE} || 'admin';
			my $page =3D $Global::Variable->{MV_PAGE};
			my $id =3D $t . "::$c";
			$id =3D $opt->{ui_meta_view} . "::$id"
				if $opt->{ui_meta_view} and $opt->{ui_meta_view} ne 'metaconfig';

			my $return =3D <<EOF;
ui_return_to=3D$page
ui_return_to=3Ditem_id=3D$opt->{item_id}
ui_return_to=3Dui_meta_view=3D$opt->{ui_meta_view}
ui_return_to=3Dmv_return_table=3D$t
mv_return_table=3D$table
ui_return_stack=3D$CGI->{ui_return_stack}
EOF

			$meta_url =3D $Tag->area({
								href =3D> "$base/meta_editor",
								form =3D> qq{
											item_id=3D$id
											$return
										}
							});
			my $meta_specific =3D '';
			if($opt->{ui_meta_specific}) {
				$meta_url_specific =3D $Tag->area({
										href =3D> "$base/meta_editor",
										form =3D> qq{
													item_id=3D${t}::${c}::$key
													$return
												}
										});
				$meta_specific =3D <<EOF;
<br><a href=3D"$meta_url_specific"$opt->{meta_extra}>$opt->{meta_anchor_spe=
cific}</A>
EOF
			}
=09=09=09=09=09=09=09=09
			$opt->{meta_append} =3D '</FONT>'
				unless defined $opt->{meta_append};
			$meta =3D <<EOF;
$opt->{meta_prepend}<a href=3D"$meta_url"$opt->{meta_extra}>$opt->{meta_anc=
hor}</A>
$meta_specific$opt->{meta_append}
EOF
		}

		$template =3D~ s/~TKEY~/$tkey_message || ''/eg;
#::logDebug("col=3D$c currval=3D$currval widget=3D$widget->{$c} label=3D$la=
bel->{$c} (type=3D$type)");
		my $display =3D display($t, $c, $key, {
										applylocale =3D> 1,
										arbitrary =3D> $opt->{ui_meta_view},
										column =3D> $c,
										default =3D> $currval,
										extra =3D> $extra->{$c},
										fallback =3D> 1,
										field =3D> $field->{$c},
										filter =3D> $filter->{$c},
										height =3D> $height->{$c},
										help =3D> $help->{$c},
										help_url =3D> $help_url->{$c},
										label =3D> $label->{$c},
										key =3D> $key,
										meta =3D> $pmeta->{$c},
										meta_url =3D> $meta_url,
										meta_url_specific =3D> $meta_url_specific,
										name =3D> $namecol,
										override =3D> $overridden,
										passed =3D> $passed->{$c},
										options =3D> $options->{$c},
										outboard =3D> $outboard->{$c},
										append =3D> $append->{$c},
										prepend =3D> $prepend->{$c},
										lookup =3D> $lookup->{$c},
										lookup_query =3D> $lookup_query->{$c},
										db =3D> $database->{$c},
										pre_filter =3D> $pre_filter->{$c},
										table =3D> $t,
										type =3D> $widget->{$c} || $type,
										width =3D> $width->{$c},
										template =3D> $template,
									});
#::logDebug("finished display of col=3D$c");

		# don't use template if we have only a hidden HTML form variable
		if ($display =3D~ /^\s*<input\s[^>]*type\s*=3D\W*hidden\b[^>]*>\s*$/i) {
			col_chunk $c, $display . "\n";
			next;
		}

		if($show_meta and $display =3D~ /\~META\~/) {
			$display =3D~ s/\~META\~/$meta/g;
		}

		$display =3D~ s/\~ERROR\~/$Tag->error({ name =3D> $c, keep =3D> 1 })/eg;
=20=20=20=20=20=20=20=20
		my $update_ctl;
		if (! $wo and $break{$namecol}) {
			push @titles, $break_label{$namecol};
			if(@columns =3D=3D 0 and @titles =3D=3D 1) {
				# do nothing
			}
			else {
				$update_ctl =3D 1;
			}

			while($rowcount % $rowdiv) {
				$w .=3D '<TD>&nbsp;</td><TD>&nbsp;</td>';
				$rowcount++;
			}
			$w .=3D "</TR>\n";
			unless ($opt->{tabbed}) {
				$w .=3D <<EOF if $break{$namecol};
	<TR class=3Drbreak>
		<TD COLSPAN=3D$span class=3Dcbreak>$break_label{$namecol}<IMG SRC=3D"$opt=
->{clear_image}" WIDTH=3D1 HEIGHT=3D1 alt=3Dx></TD>
	</TR>
EOF
			}
			$rowcount =3D 0;
		}
		$w .=3D "<tr class=3Drnorm>\n" unless $rowcount++ % $rowdiv;
		$w .=3D $display;
		$w .=3D "</TR>\n" unless $rowcount % $rowdiv;
		col_chunk $c, $w;
		$ctl_index++ if $update_ctl;
	}

	for(sort keys %link_row) {
		col_chunk "SPREAD_$_", delete $link_row{$_};
	}

	my $firstout =3D scalar(@out);

	if($opt->{tabbed}) {
		chunk ttag(), qq{</td></tr>\n};
	}

	while($rowcount % $rowdiv) {
		chunk ttag(), '<TD>&nbsp;</td><TD>&nbsp;</td>'; # unless $wo;
		$rowcount++;
	}

	$::Scratch->{mv_data_enable} =3D '';
	if($opt->{auto_secure}) {
		$::Scratch->{mv_data_enable} .=3D "$table:" . join(",", @data_enable) . '=
:';
		$::Scratch->{mv_data_enable_key} =3D $opt->{item_id};
	}
	if(@ext_enable) {
		$::Scratch->{mv_data_enable} .=3D " " . join(" ", @ext_enable) . " ";
	}
#Debug("setting mv_data_enable to $::Scratch->{mv_data_enable}");
	my @serial =3D keys %serialize;
	my @serial_fields;
	my @o;
	for (@serial) {
#Debug("$_ serial_data=3D$serial_data{$_}");
		$serial_data{$_} =3D uneval($serial_data{$_})
			if is_hash($serial_data{$_});
		$serial_data{$_} =3D~ s/\&/&amp;/g;
		$serial_data{$_} =3D~ s/"/&quot;/g;
		push @o, qq{<INPUT TYPE=3Dhidden NAME=3D"$_" VALUE=3D"$serial_data{$_}">}=
; # unless $wo;
		push @serial_fields, @{$serialize{$_}};
	}

	if(! $wo and @serial_fields) {
		push @o, qq{<INPUT TYPE=3Dhidden NAME=3D"ui_serial_fields" VALUE=3D"};
		push @o, join " ", @serial_fields;
		push @o, qq{">};
		chunk 'SERIAL_FIELDS', join("", @o);
	}

	###
	### Here the user can include some extra stuff in the form....
	###
	if($opt->{include_form}) {
		chunk 'INCLUDE_FORM', <<EOF; # if ! $wo;
<tr class=3Drnorm>
<td colspan=3D$span>$opt->{include_form}</td>
</tr>
EOF
	}
	### END USER INCLUDE

	unless ($opt->{mailto} and $opt->{mv_blob_only}) {
		@cols =3D grep ! $display_only{$_}, @cols;
	}
	$passed_fields =3D join " ", @cols;

	chunk 'MV_DATA_FIELDS', <<EOF; # unless $wo;
<INPUT TYPE=3Dhidden NAME=3Dmv_data_fields VALUE=3D"$passed_fields">
EOF

	chunk ttag(), <<EOF;
<tr class=3Drspacer>
<td colspan=3D$span ><img src=3D"$opt->{clear_image}" height=3D3 alt=3Dx></=
td>
</tr>
EOF

  SAVEWIDGETS: {
  	last SAVEWIDGETS if $wo || $opt->{nosave};=20
		chunk ttag(), <<EOF;
<TR class=3Drnorm>
<td>&nbsp;</td>
<td align=3Dleft colspan=3D$oddspan class=3Dcdata>
EOF
	  	if($opt->{back_text}) {

			chunk 'BOTTOM_BUTTONS', <<EOF;
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{back_text}">&nbsp;<INP=
UT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}">&nbsp;<B><IN=
PUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{next_text}"></B>
EOF
		}
		elsif($opt->{wizard}) {
			chunk 'BOTTOM_BUTTONS', <<EOF;
<TR class=3Drnorm>
<td>&nbsp;</td>
<td align=3Dleft colspan=3D$oddspan class=3Dcdata>
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}">&nbsp;<B=
><INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{next_text}"></B>
EOF
		}
		else {
			chunk 'OK_BOTTOM', <<EOF;
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{next_text}" style=3D"$=
opt->{ok_button_style}">
EOF

			chunk 'CANCEL_BOTTOM', 'NOCANCEL', <<EOF;
&nbsp;<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}" st=
yle=3D"$opt->{cancel_button_style}">
EOF

			chunk 'RESET_BOTTOM', qq{&nbsp;<INPUT TYPE=3Dreset>}
				if $opt->{show_reset};
			chunk_alias 'BOTTOM_BUTTONS', qw/OK_BOTTOM CANCEL_BOTTOM RESET_BOTTOM/;
		}

	if(! $opt->{notable} and $Tag->if_mm('tables', "$table=3Dx") and ! $db->co=
nfig('LARGE') ) {
		my $checked =3D ' CHECKED';
		$checked =3D ''
			if defined $opt->{mv_auto_export} and ! $opt->{mv_auto_export};
		my $autoexpstr =3D errmsg('Auto-export');=09=09
		chunk 'AUTO_EXPORT', 'NOEXPORT NOSAVE', <<EOF; # unless $opt->{noexport} =
or $opt->{nosave};
<small>
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
	<INPUT TYPE=3Dcheckbox NAME=3Dmv_auto_export VALUE=3D"$table"$checked>&nbs=
p;$autoexpstr
EOF

	}

	if($exists and ! $opt->{nodelete} and $Tag->if_mm('tables', "$table=3Dd"))=
 {
		my $extra =3D $Tag->return_to( { type =3D> 'click', tablehack =3D> 1 });
		my $page =3D $CGI->{ui_return_to};
		$page =3D~ s/\0.*//s;
		my $url =3D $Tag->area( {
					href =3D> $page,
					form =3D> qq!
						deleterecords=3D1
						ui_delete_id=3D$key
						mv_data_table=3D$table
						mv_click=3Ddb_maintenance
						mv_action=3Dback
						$extra
					!,
					});
		my $delstr =3D errmsg('Delete');
		my $delmsg =3D errmsg('Are you sure you want to delete %s?',$key);
		chunk 'DELETE_BUTTON', 'NOSAVE', <<EOF; # if ! $opt->{nosave};
<BR><BR><A
onClick=3D"return confirm('$delmsg')"
HREF=3D"$url"><IMG SRC=3D"delete.gif" ALT=3D"Delete $key" BORDER=3D0></A> $=
delstr
EOF

	}
	chunk ttag(), <<EOF;
</small>
</td>
</tr>
EOF
  } # end SAVEWIDGETS

	my $message =3D '';

#	if($opt->{bottom_errors}) {
#		my $err =3D $Tag->error( {
#									show_var =3D> $error_show_var,
#									show_error =3D> 1,
#									joiner =3D> '<BR>',
#								}
#								);
#		push @errors, $err if $err;
#	}

	if(@errors) {
		$message .=3D '<P>Errors:';
		$message .=3D qq{<FONT COLOR=3D"$opt->{color_fail}">};
		$message .=3D '<BLOCKQUOTE>';
		$message .=3D join "<BR>", @errors;
		$message .=3D '</BLOCKQUOTE></FONT>';
	}
	if(@messages) {
		$message .=3D '<P>Messages:';
		$message .=3D qq{<FONT COLOR=3D"$opt->{color_success}">};
		$message .=3D '<BLOCKQUOTE>';
		$message .=3D join "<BR>", @messages;
		$message .=3D '</BLOCKQUOTE></FONT>';
	}
	$Tag->error( { all =3D> 1 } );

	chunk ttag(), 'NO_BOTTOM _MESSAGE', <<EOF;
<tr class=3Drtitle>
	<td colspan=3D$span>
EOF

	chunk 'MESSAGE_TEXT', 'NO_BOTTOM', $message; # unless $wo or ($opt->{no_bo=
ttom} and ! $message);

	chunk ttag(), 'NO_BOTTOM _MESSAGE', <<EOF;
	</td>
</tr>
EOF
	chunk ttag(), <<EOF; # unless $wo;
</table>
</td></tr></table>
EOF

	chunk 'FORM_BOTTOM', <<EOF;
</form>$restrict_end
EOF

	my %ehash =3D (
	);
	for(qw/
		BOTTOM_BUTTONS
		NOCANCEL
		NOEXPORT
		NOSAVE
		NO_BOTTOM
		NO_TOP
		WO
		SHOW_RESET
		/)
	{
		$ehash{$_} =3D $opt->{lc $_} ? 1 : 0;
	}

	$ehash{MESSAGE} =3D length($message) ? 1 : 0;

	resolve_exclude(\%ehash);

	if($wo) {
		return (map { @$_ } @controls) if wantarray;
		return join "", map { @$_ } @controls;
	}
show_times("end table editor call item_id=3D$key") if $Global::ShowTimes;

	my @put;
	for(my $i =3D 0; $i < $firstout; $i++) {
#::logDebug("$out[$i] content length=3D" . length($outhash{$out[$i]} ));
		push @put, $outhash{$out[$i]};
	}

	if($opt->{tabbed}) {
::logDebug("In tabbed display...controls=3D" . scalar(@controls) . ", title=
s=3D" . scalar(@titles));
		my @tabcont;
		for(@controls) {
			push @tabcont, join "", map { $outhash{$_} } @$_;
		}
		push @put, tabbed_display(\@titles,\@tabcont,$opt);
	}
	else {
		for my $c (@controls) {
			for (@$c) {
				push @put, $outhash{$_};
			}
		}
	}

	for(my $i =3D $firstout; $i < @out; $i++) {
#::logDebug("$out[$i] content length=3D" . length($outhash{$out[$i]} ));
		push @put, $outhash{$out[$i]};
	}
	return join "", @put;
}

1;