[interchange-cvs] interchange - heins modified code/UI_Tag/table_editor_tpl.coretag
interchange-core@interchange.redhat.com
interchange-core@interchange.redhat.com
Thu Apr 4 16:47:01 2002
User: heins
Date: 2002-04-04 21:46:39 GMT
Added: code/UI_Tag table_editor_tpl.coretag
Log:
* Add templated version of table-editor which may eventually takke
over from the other version (much more testing needed).
Allows templated table editor for better control of form
presentation.
A default matching the current table-editor is provided if
no template is given.
Example:
[table-editor-tpl cgi=1]
[restrict]
[editors]
<FORM METHOD="[editor-param method]" ACTION="[editor-param href]"
[editor-param form_name]
[editor-param enctype]
[editor-param form_extra]
>
<INPUT TYPE=hidden NAME=mv_todo VALUE="[editor-param action]">
<INPUT TYPE=hidden NAME=mv_click VALUE="process_filter">
[editor-param tpl_sidstr]
[editor-param tpl_clone]
[editor-param tpl_hidden]
[editor-param tpl_return_to]
<table class=touter cellspacing=0 cellpadding=0 width="[editor-param table_width]">
<tr>
<td>
[columns]
[column-list]
<tr class=rnorm>
<td class=clabel width="[editor-param left_width]">
[editor-param label_prepend][column-param label][editor-param label_append][column-param meta]
</td>
<td class=cdata>
<table cellspacing=0 cellmargin=0 width="100%">
<tr>
<td class=cwidget>
[column-param widget]
</td>
<td class=chelp>[column-param tkey]
[if-column-param help]
<i>[column-param help]</i>
[/if-column-param]
[if-column-param help_url]
<BR><A HREF="[column-param help_url]">help</A>
[/if-column-param]
</td>
</tr>
</table>
</td>
</tr>
[/column-list]
[/columns]
<tr class=rtitle>
<td align=right colspan="[editor-param calc_span]"><img src="[editor-param clear_image]" width=1 height=3 alt=x></td>
</tr>
[editor-param tpl_bottom_buttons]
<tr class=rspacer>
<td colspan="[editor-param calc_span]"><img src="[editor-param clear_image]" height=3 alt=x></td>
</tr>
</table>
</td>
</tr>
</table>
</form>
[/editors]
[/restrict]
[/table-editor-tpl]
Revision Changes Path
1.1 interchange/code/UI_Tag/table_editor_tpl.coretag
rev 1.1, prev_rev 1.0
Index: table_editor_tpl.coretag
===================================================================
UserTag table-editor-tpl Order mv_data_table item_id
UserTag table-editor-tpl addAttr
UserTag table-editor-tpl hasEndTag
UserTag table-editor-tpl AttrAlias clone ui_clone_id
UserTag table-editor-tpl AttrAlias table mv_data_table
UserTag table-editor-tpl AttrAlias fields ui_data_fields
UserTag table-editor-tpl AttrAlias mv_data_fields ui_data_fields
UserTag table-editor-tpl AttrAlias key item_id
UserTag table-editor-tpl AttrAlias view ui_meta_view
UserTag table-editor-tpl AttrAlias profile ui_profile
UserTag table-editor-tpl AttrAlias email_fields ui_display_only
#UserTag table-editor Documentation <<EOD
#=head1 NAME
#
#[table-editor-tpl]
#
#=head1 SYNOPSIS
#
# [table-editor-tpl
# table=ic_table
# cgi=1*
# item-id="key"
# across=n*
# noexport=1*
#
# wizard=1*
# next_text='Next -->'*
# cancel_text='Cancel'*
# back_text='<-- Back'*
#
# hidden.formvarname="value"
#
# item_id_left="keys remaining"
# mv_blob_field=column*
# mv_blob_nick=name*
# mv_blob_pointer="current name"*
# mv_blob_label="Label text"
# mv_blob_title="Title HTML"
#
# ui_break_before="field1 field2"
# ui_break_before_label="field1=Label 1, field2=Label 2"
# ui_data_fields="field1 field2 fieldn ..."*
# ui_data_fields_all=1*
# ui_display_only="no_set_field"*
# ui_hide_key=1*
# ui_meta_specific=1*
# ui_meta_view="viewname"
# ui_nextpage="next_destination"
# ui_prevpage="back_destination"
# ui_return_to="cancel_destination"
# ui_new_item=1*
# ui_sequence_edit=1*
# ui_clone_id="key"
# ui_clone_tables="table1 table2 ..."
# ui_delete_box=1*
# mv_update_empty=0*
#
# widget.field="select|text|any ic widget"
# label.field="Field Label"
# help.field="Help text"
# help-url.field="http://url/to/more/help"
# default.field="preset value"*
# override.field="forced value"*
# filter.field="filter1 filter2"
# pre-filter.field="filter1 filter2"
# error.field=1*
# height.field=N
# width.field=N
# passed.field="val1=Label 1, val2=Label 2"
# lookup.field="lookup_field"
# database.field="table"
# field.field="column"
# outboard.field="key"
# append.field="HTML"
# prepend.field="HTML"
#
# ]
#
#=head1 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=foo]
#
#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=1
# ui_wizard_fields="foo bar"
# mv_nextpage=wizard2
# mv_prevpage=wizard_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.
#
#EOD
UserTag table-editor-tpl Routine <<EOR
my $Default_template = <<'EOT';
[restrict]
[editors]
<FORM METHOD="[editor-param method]" ACTION="[editor-param href]"
[editor-param form_name]
[editor-param enctype]
[editor-param form_extra]
>
[editor-param tpl_sidstr]
<INPUT TYPE=hidden NAME=mv_todo VALUE="[editor-param action]">
<INPUT TYPE=hidden NAME=mv_click VALUE="process_filter">
[editor-param tpl_hidden]
[editor-param tpl_return_to]
<table class=touter cellspacing=0 cellpadding=0 width="[editor-param table_width]">
<tr>
<td>
[if-editor-param !no_top]
<table class=tinner width="[editor-param inner_table_width]" cellspacing=0 cellmargin=0 width="100%" cellpadding=2 align=center border=0>
<tr class=rtitle>
<td align=right colspan="[editor-param calc_span]"><img src="[editor-param clear_image]" width=1 height=3 alt=x></td>
</tr>
[editor-param tpl_top_buttons]
[editor-param tpl_blob_widget]
[/if-editor-param]
[editor-param tpl_clone]
[columns]
[column-list]
<tr class=rnorm>
<td class=clabel width="[editor-param left_width]">
[editor-param label_prepend][column-param label][editor-param label_append][column-param meta]
</td>
<td class=cdata>
<table cellspacing=0 cellmargin=0 width="100%">
<tr>
<td class=cwidget>
[column-param widget]
</td>
<td class=chelp>[column-param tkey]
[if-column-param help]
<i>[column-param help]</i>
[/if-column-param]
[if-column-param help_url]
<BR><A HREF="[column-param help_url]">help</A>
[/if-column-param]
</td>
</tr>
</table>
</td>
</tr>
[/column-list]
[/columns]
<tr class=rtitle>
<td align=right colspan="[editor-param calc_span]"><img src="[editor-param clear_image]" width=1 height=3 alt=x></td>
</tr>
[if-editor-param tpl_include_form]
[editor-param tpl_include_form]
<td align=right colspan="[editor-param calc_span]"><img src="[editor-param clear_image]" width=1 height=3 alt=x></td>
[/if-editor-param]
[editor-param tpl_bottom_buttons]
[if-editor-param tpl_errors]
<tr class=rspacer>
<td colspan="[editor-param calc_span]">
Errors:
<blockquote>
[editor-param tpl_errors]
</blockquote>
</td>
</tr>
[/if-editor-param]
[if-editor-param tpl_messages]
<tr class=rspacer>
<td colspan="[editor-param calc_span]">
Errors:
<blockquote>
[editor-param tpl_errors]
</blockquote>
</td>
</tr>
[/if-editor-param]
<tr class=rspacer>
<td colspan="[editor-param calc_span]"><img src="[editor-param clear_image]" height=3 alt=x></td>
</tr>
</table>
</td>
</tr>
</table>
</form>
[/editors]
[/restrict]
EOT
sub editor_region {
my ($opt, $opt_out, $hidden) = @_;
my @hidden;
while( my($k, $v) = each %$hidden) {
HTML::Entities::encode($k);
HTML::Entities::encode($v);
push @hidden, qq{<input type="hidden" name="$k" value="$v">};
}
$opt_out->{tpl_hidden} = join "\n", @hidden;
return ['editors', 'editor', [ $opt_out ] ];
}
sub column_region {
my ($opt, $opt_out, $controls) = @_;
return ['columns', 'column', $controls];
}
sub run_templates {
my ($opt, $to_run, $bref) = @_;
#::logDebug("te_array=" . ::uneval(\@_));
my %todo = ( editor => 1, columns => 1 );
my $region;
my $prefix;
my $ary;
my @things = @$to_run;
while( $region = shift @things ) {
$prefix = shift @things;
$ary = shift @things;
delete $todo{$region};
::logDebug("run_template region=$region prefix=$prefix ary=$ary from=$opt->{from_session}");
$region =~ s/[-_]/[-_]/g;
next unless $$bref =~ m{\[$region\](.*?)\[/$region\]}is;
my $run = $1;
if( $run !~ /\S/ or (! $ary and $run !~ /no[-_]match\]/i) ) {
$$bref =~ s{\[$region\](.*?)\[/$region\]}{}sgi;
next;
}
$opt->{prefix} = $prefix;
$opt->{object} = {
mv_results => $ary,
matches => scalar(@$ary),
mv_matchlimit => $opt->{ml} || 100,
};
$$bref =~ s{\[$region\](.*?)\[/$region\]}
{Vend::Interpolate::region($opt, $1)}eisg;
}
for(keys %todo) {
$$bref =~ s,\[$region\](.*?)\[/$region\],,igs;
}
return $$bref;
}
sub {
my ($table, $key, $opt, $template) = @_;
show_times("begin table editor call item_id=$key") if $Global::ShowTimes;
package Vend::Interpolate;
use vars qw/$Values $Scratch $Db $Tag $Config $CGI $Variable $safe_safe/;
my %hidden;
if(ref($opt->{all_opts}) eq 'HASH') {
my $o = $opt->{all_opts};
for (keys %$o ) {
$opt->{$_} = $o->{$_};
}
}
#Debug("options now=" . ::uneval($opt));
init_calc() if ! $Vend::Calc_initialized;
my @messages;
my @errors;
my %opt_out;
#Debug("labels=" . uneval($opt->{label}));
FORMATS: {
no strict 'refs';
my $ref;
for(qw/
default
error
extra
filter
height
help
label
override
passed
options
outboard
append
prepend
lookup
lookup_query
field
pre_filter
widget
width
meta
/ )
{
next if ref $opt->{$_};
($opt->{$_} = {}, next) if ! $opt->{$_};
my $ref = {};
my $string = $opt->{$_};
$string =~ s/^\s+//gm;
$string =~ s/\s+$//gm;
while($string =~ m/^(.+?)=\s*(.+)/mg) {
$ref->{$1} = $2;
}
$opt->{$_} = $ref;
}
}
my $rowcount = 0;
$opt->{action} ||= 'set';
$opt_out{action} = $opt->{action};
my $wizard_next = $opt->{wizard_next} || 'return';
my $wizard_cancel = $opt->{wizard_cancel} || 'back';
## Calculate the spans for across option
my $rowdiv = $opt->{across} || 1;
my $span = $rowdiv * 2;
my $oddspan = $span - 1;
$opt_out{calc_span} = $span;
$opt_out{calc_oddspan} = $oddspan;
my $def = $opt->{default_ref} || $::Values;
#::logDebug("view=$opt->{ui_meta_view}, default_ref: " . uneval($def));
$opt->{table_width} = '60%' if ! $opt->{table_width};
$opt->{left_width} = '30%' if ! $opt->{left_width};
if (! $opt->{inner_table_width}) {
if($opt->{table_width} =~ /%/) {
$opt->{inner_table_width} = '100%';
}
elsif ($opt->{table_width} =~ /^\d+$/) {
$opt->{inner_table_width} = $opt->{table_width} - 2;
}
else {
$opt->{inner_table_width} = $opt->{table_width};
}
}
my $check = $opt->{check};
my $default = $opt->{default};
my $error = $opt->{error};
my $extra = $opt->{extra};
my $filter = $opt->{filter};
my $height = $opt->{height};
my $help = $opt->{help};
my $help_url = $opt->{help_url};
my $label = $opt->{label};
my $override = $opt->{override};
my $pre_filter = $opt->{pre_filter};
my $passed = $opt->{passed};
my $options = $opt->{options};
my $outboard = $opt->{outboard};
my $prepend = $opt->{prepend};
my $append = $opt->{append};
my $lookup = $opt->{lookup};
my $lookup_query = $opt->{lookup_query};
my $database = $opt->{database};
my $field = $opt->{field};
my $widget = $opt->{widget};
my $width = $opt->{width};
my $pmeta = $opt->{meta};
#::logDebug("widget=" . ::uneval_it($widget) );
#::logDebug("label=" . ::uneval_it($label) );
my $blabel = $opt->{label_prepend} || '<span style="font-weight: normal">';
my $elabel = $opt->{label_append} || '</span>';
my $mlabel = '';
if($opt->{wizard}) {
$opt->{noexport} = 1;
$opt->{next_text} = 'Next -->' unless $opt->{next_text};
$opt->{cancel_text} = 'Cancel' unless $opt->{cancel_text};
$opt->{back_text} = '<-- Back' unless $opt->{back_text};
}
else {
$opt->{cancel_text} = 'Cancel' unless $opt->{cancel_text};
$opt->{next_text} = "Ok" unless $opt->{next_text};
}
for(qw/ next_text cancel_text back_text/ ) {
$opt->{$_} = errmsg($opt->{$_});
}
my $ntext;
my $btext;
my $ctext;
unless ($opt->{wizard} || $opt->{nosave}) {
$Scratch->{$opt->{next_text}} = $Tag->return_to('click', 1);
}
else {
if($opt->{action_click}) {
$ntext = <<EOF;
mv_todo=$wizard_next
ui_wizard_action=Next
mv_click=$opt->{action_click}
EOF
}
else {
$ntext = <<EOF;
mv_todo=$wizard_next
ui_wizard_action=Next
mv_click=ui_override_next
EOF
}
$Scratch->{$opt->{next_text}} = $ntext;
my $hidgo = $opt->{mv_cancelpage} || $opt->{hidden}{ui_return_to} || $CGI->{return_to};
$hidgo =~ s/\0.*//s;
$ctext = $Scratch->{$opt->{cancel_text}} = <<EOF;
mv_form_profile=
ui_wizard_action=Cancel
mv_nextpage=$hidgo
mv_todo=$wizard_cancel
EOF
if($opt->{mv_prevpage}) {
$btext = $Scratch->{$opt->{back_text}} = <<EOF;
mv_form_profile=
ui_wizard_action=Back
mv_nextpage=$opt->{mv_prevpage}
mv_todo=$wizard_next
EOF
}
else {
delete $opt->{back_text};
}
}
for(qw/next_text back_text cancel_text/) {
$opt->{"orig_$_"} = $opt->{$_};
}
$Scratch->{$opt->{next_text}} = $ntext if $ntext;
$Scratch->{$opt->{cancel_text}} = $ctext if $ctext;
$Scratch->{$opt->{back_text}} = $btext if $btext;
$opt->{next_text} = HTML::Entities::encode($opt->{next_text}, $ESCAPE_CHARS::std);
$opt->{back_text} = HTML::Entities::encode($opt->{back_text}, $ESCAPE_CHARS::std);
$opt->{cancel_text} = HTML::Entities::encode($opt->{cancel_text});
$Scratch->{$opt->{next_text}} = $ntext if $ntext;
$Scratch->{$opt->{cancel_text}} = $ctext if $ctext;
$Scratch->{$opt->{back_text}} = $btext if $btext;
if($opt->{wizard} || $opt->{notable} and ! $table) {
$table = 'mv_null';
$Vend::Database{mv_null} =
bless [
{},
undef,
[ 'code', 'value' ],
[ 'code' => 0, 'value' => 1 ],
0,
{ },
], 'Vend::Table::InMemory';
}
my @mapdirect = 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
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
defaults
cgi_defaults
/;
$table = $CGI->{mv_data_table} if $CGI->{mv_data_table} and ! $table;
my $tmeta = UI::Primitive::meta_record($table, $opt->{ui_meta_view}) || {};
for(grep defined $tmeta->{$_}, @mapdirect) {
$opt->{$_} ||= $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->{$_} = $CGI->{$_};
}
my @hmap = (
[ 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 = keys %{$CGI};
foreach my $row (@hmap) {
my @keys = grep $_ =~ $row->[0], @cgi;
for(@keys) {
#::logDebug("found key $_");
/^ui_\w+:(\S+)/
and $row->[1]->{$1} = $CGI->{$_};
#::logDebug("set $1=$_");
}
}
$table = $opt->{mv_data_table};
$key = $opt->{item_id};
}
$hidden{mv_data_table} = $table;
$opt->{color_success} = $Variable->{UI_C_SUCCESS} || '#00FF00'
if ! $opt->{color_success};
$opt->{color_fail} = $Variable->{UI_CONTRAST} || '#FF0000'
if ! $opt->{color_fail};
### Build the error checking
my $error_show_var = 1;
my $have_errors;
if($opt->{ui_profile} or $check) {
$Tag->error( { all => 1 } )
unless $CGI->{mv_form_profile} or $opt->{keep_errors};
my $prof = $opt->{ui_profile} || '';
if ($prof =~ s/^\*//) {
# special notation ui_profile="*whatever" means
# use automatic checklist-related profile
my $name = $prof;
$prof = $Scratch->{"profile_$name"} || '';
if ($prof) {
$prof =~ s/^\s*(\w+)[\s=]+required\b/$1=mandatory/mg;
for (grep /\S/, split /\n/, $prof) {
if (/^\s*(\w+)\s*=(.+)$/) {
my $k = $1; my $v = $2;
$v =~ s/\s+$//;
$v =~ s/^\s+//;
$error->{$k} = 1;
$error_show_var = 0 if $v =~ /\S /;
}
}
$prof = '&calc delete \\$Values->{step_' . $name . "}\n" . $prof;
$opt->{ui_profile_success} = "&set=step_$name 1";
}
}
my $success = $opt->{ui_profile_success};
if(ref $check) {
while ( my($k, $v) = each %$check ) {
$error->{$k} = 1;
$v =~ s/\s+$//;
$v =~ s/^\s+//;
$v =~ s/\s+$//mg;
$v =~ s/^\s+//mg;
$v =~ s/^required\b/mandatory/mg;
unless ($v =~ /^\&/m) {
$error_show_var = 0 if $v =~ /\S /;
$v =~ s/^/$k=/mg;
$v =~ s/\n/\n&and\n/g;
}
$prof .= "$v\n";
}
}
elsif ($check) {
for (@_ = grep /\S/, split /[\s,]+/, $check) {
$error->{$_} = 1;
$prof .= "$_=mandatory\n";
}
}
$opt->{hidden} = {} if ! $opt->{hidden};
$opt->{hidden}{mv_form_profile} = 'ui_profile';
my $fail = $opt->{mv_failpage} || $Global::Variable->{MV_PAGE};
$Scratch->{ui_profile} = <<EOF;
[perl]
#Debug("cancel='$opt->{orig_cancel_text}' back='$opt->{orig_back_text}' click=\$CGI->{mv_click}");
my \@clicks = split /\\0/, \$CGI->{mv_click};
my \$fail = '$fail';
for( qq{$opt->{orig_cancel_text}}, qq{$opt->{orig_back_text}}) {
#Debug("compare is '\$_'");
next unless \$_;
my \$cancel = \$_;
for(\@clicks) {
#Debug("click is '\$_'");
return if \$_ eq \$cancel;
}
}
return <<EOP;
$prof
&fail=$fail
&fatal=1
$success
mv_form_profile=mandatory
&set=mv_todo $opt->{action}
EOP
[/perl]
EOF
$mlabel = ($opt->{message_label} || ' <B>Bold</B> fields are required');
$have_errors = $Tag->error( {
all => 1,
show_var => $error_show_var,
show_error => 1,
joiner => '<BR>',
keep => 1}
);
if($opt->{all_errors}) {
if($have_errors) {
$mlabel .= '<P>Errors:';
$mlabel .= qq{<FONT COLOR="$opt->{color_fail}">};
$mlabel .= "<BLOCKQUOTE>$have_errors</BLOCKQUOTE></FONT>";
}
}
}
### end build of error checking
$opt->{clear_image} = "bg.gif" if ! $opt->{clear_image};
#::logDebug("table-editor opt: " . ::uneval($opt));
my $die = sub {
::logError(@_);
$Scratch->{ui_error} .= "<BR>\n" if $Scratch->{ui_error};
$Scratch->{ui_error} .= ::errmsg(@_);
return undef;
};
my $db;
unless($opt->{notable}) {
$db = Vend::Data::database_exists_ref($table)
or return $die->('table-editor: bad table %s', $table);
}
if($opt->{ui_wizard_fields}) {
$opt->{ui_data_fields} = $opt->{ui_display_only} = $opt->{ui_wizard_fields};
}
my $keycol;
if($opt->{notable}) {
$keycol = $opt->{ui_data_key_name};
}
else {
$keycol = $opt->{ui_data_key_name} || $db->config('KEY');
}
$hidden{mv_data_key} = $keycol;
if ($opt->{form_extra}) {
$opt_out{form_extra} = $opt->{form_extra};
$opt_out{form_extra} =~ s/^\s*/ /;
}
$opt_out{form_name} = qq{ NAME="$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} = $tmeta->{ui_data_fields} || $tmeta->{options};
}
$opt->{ui_data_fields} =~ s/\r\n/\n/g;
$opt->{ui_data_fields} =~ s/\r/\n/g;
#::logDebug("ui_data_fields=$opt->{ui_data_fields}");
if($opt->{ui_data_fields} =~ /\n\n/) {
#::logDebug("Found break fields");
my @breaks;
my @break_labels;
while ($opt->{ui_data_fields} =~ s/\n+(?:\n[ \t]*=(.*))?\n+[ \t]*(\w[:.\w]+)/\n$2/) {
push @breaks, $2;
push @break_labels, "$2=$1" if $1;
}
$opt->{ui_break_before} = join(" ", @breaks)
if ! $opt->{ui_break_before};
#::logDebug("break_before=$opt->{ui_break_before}");
$opt->{ui_break_before_label} = join(",", @break_labels)
if ! $opt->{ui_break_before_label};
#::logDebug("break_before_label=$opt->{ui_break_before_label}");
}
$opt->{ui_data_fields} ||= $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} = join " ", $db->columns();
}
}
$opt->{ui_data_fields} =~ s/[,\0\s]+/ /g;
###############################################################
my $linecount;
CANONCOLS: {
my @cols = split /[,\0\s]/, $opt->{ui_data_fields};
#@cols = grep /:/ || $db->column_exists($_), @cols;
$opt->{ui_data_fields} = join " ", @cols;
$linecount = scalar @cols;
}
my $url = $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 = $db->autonumber($key);
}
else {
$key = '';
$opt->{mv_data_auto_number} = 1;
$key_message = '(new key will be assigned if left blank)';
}
}
my $data;
my $exists;
if($opt->{notable}) {
$data = {};
}
elsif($opt->{ui_clone_id} and $db->record_exists($opt->{ui_clone_id})) {
$data = $db->row_hash($opt->{ui_clone_id})
or
return $die->('table-editor: row_hash function failed for %s.', $key);
$data->{$keycol} = $key;
}
elsif ($db->record_exists($key)) {
$data = $db->row_hash($key);
$exists = 1;
}
if ($opt->{reload} and $have_errors) {
if($data) {
for(keys %$data) {
$data->{$_} = $CGI->{$_}
if defined $CGI->{$_};
}
}
else {
$data = { %$CGI };
}
}
my $blob_data;
my $blob_widget;
if($opt->{mailto} and $opt->{mv_blob_field}) {
$opt->{hidden}{mv_blob_only} = 1;
$opt->{hidden}{mv_blob_nick}
= $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 = $data->{$opt->{mv_blob_pointer}}
if $opt->{mv_blob_pointer};
$blob_pointer ||= $opt->{mv_blob_nick};
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 = $data->{$opt->{mv_blob_field}};
#::logDebug("blob: bstring=$bstring");
my $blob;
if(length $bstring) {
$blob = $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 = {};
}
my %wid_data;
my %url_data;
my @labels = keys %$blob;
for my $key (@labels) {
my $ref = $blob->{$_};
my $lab = $ref->{$opt->{mv_blob_label} || 'name'};
if($lab) {
$lab =~ s/,/,/g;
$wid_data{$lab} = "$key=$key - $lab";
$url_data{$lab} = $Tag->page( {
href => $Global::Variable->{MV_PAGE},
form => "
item_id=$opt->{item_id}
mv_blob_nick=$key
",
});
$url_data{$lab} .= "$key - $lab</A>";
}
else {
$wid_data{$key} = $key;
$url_data{$key} = $Tag->page( {
href => $Global::Variable->{MV_PAGE},
form => "
item_id=$opt->{item_id}
mv_blob_nick=$key
",
});
$url_data{$key} .= "$key</A>";
}
}
#::logDebug("wid_data is " . ::uneval_it(\%wid_data));
$opt->{mv_blob_title} = "Stored settings"
if ! $opt->{mv_blob_title};
$opt->{mv_blob_title} = errmsg($opt->{mv_blob_title});
$Scratch->{Load} = <<EOF;
[return-to type=click stack=1 page="$Global::Variable->{MV_PAGE}"]
ui_nextpage=
[perl]Log("tried to go to $Global::Variable->{MV_PAGE}"); return[/perl]
mv_todo=back
EOF
#::logDebug("blob_pointer=$blob_pointer blob_nick=$opt->{mv_blob_nick}");
my $loaded_from;
my $lfrom_msg;
if( $opt->{mv_blob_nick} ) {
$lfrom_msg = $opt->{mv_blob_nick};
}
else {
$lfrom_msg = errmsg("current values");
}
$lfrom_msg = errmsg("loaded from %s", $lfrom_msg);
$loaded_from = <<EOF;
<I>($lfrom_msg)</I><BR>
EOF
if(@labels) {
$loaded_from .= errmsg("Load from") . ":<BLOCKQUOTE>";
$loaded_from .= join (" ", @url_data{ sort keys %url_data });
$loaded_from .= "</BLOCKQUOTE>";
}
my $checked;
my $set;
if( $opt->{mv_blob_only} and $opt->{mv_blob_nick}) {
$checked = ' CHECKED';
$set = $opt->{mv_blob_nick};
}
unless ($opt->{nosave}) {
$blob_widget = $Tag->widget({
name => 'mv_blob_nick',
type => $opt->{ui_blob_widget} || 'combo',
filter => 'nullselect',
override => 1,
set => "$set",
passed => join (",", @wid_data{ sort keys %wid_data }) || 'default',
});
my $msg1 = errmsg('Save to');
my $msg2 = errmsg('Save here only');
for (\$msg1, \$msg2) {
$$_ =~ s/ / /g;
}
$blob_widget = <<EOF unless $opt->{ui_blob_hidden};
<B>$msg1:</B> $blob_widget
<INPUT TYPE=checkbox NAME=mv_blob_only VALUE=1$checked> $msg2</SMALL>
EOF
}
$blob_widget = <<EOF unless $opt->{ui_blob_hidden};
<TR class=rnorm>
<td class=clabel width="$opt->{left_width}">
<SMALL>$opt->{mv_blob_title}<BR>
$loaded_from
</td>
<td class=cwidget>
$blob_widget
</td>
</TR>
<tr class=rtitle>
<td colspan=$span><img src="$opt->{clear_image}" width=1 height=3 alt=x></td>
</tr>
EOF
if($opt->{mv_blob_nick}) {
my @keys = split /::/, $opt->{mv_blob_nick};
my $ref = $blob->{shift @keys};
for(@keys) {
my $prior = $ref;
undef $ref;
eval {
$ref = $prior->{$_};
};
last DOBLOB unless ref $ref;
}
for(keys %$ref) {
$data->{$_} = $ref->{$_};
}
}
}
}
#::logDebug("data is: " . ::uneval($data));
$data = { $keycol => $key }
if ! $data;
if(! $opt->{mv_data_function}) {
$opt->{mv_data_function} = $exists ? 'update' : 'insert';
}
$opt->{mv_nextpage} = $Global::Variable->{MV_PAGE} if ! $opt->{mv_nextpage};
$opt->{mv_update_empty} = 1 unless defined $opt->{mv_update_empty};
my $url_base = $opt->{secure} ? $Config->{SecureURL} : $Config->{VendURL};
#Debug("Urlbase=$url_base");
$opt->{href} = "$url_base/ui" if ! $opt->{href};
$opt->{href} = "$url_base/$opt->{href}"
if $opt->{href} !~ m{^(https?:|)/};
#Debug("href=$opt->{href}");
my $sidstr;
if ($opt->{get}) {
$opt->{method} = 'GET';
$sidstr = '';
}
else {
$opt->{method} = 'POST';
$sidstr = qq{<INPUT TYPE=hidden NAME=mv_session_id VALUE="$Vend::Session->{id}">
};
}
$opt_out{href} = $opt->{href};
$opt_out{method} = $opt->{method};
$opt_out{tpl_sidstr} = $sidstr;
$opt_out{enctype} = $opt->{file_upload} ? ' ENCTYPE="multipart/form-data"' : '';
my %out_opt;
my @opt_set = (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_nextpage
mv_data_auto_number
mv_data_function
/ );
my @cgi_set = ( qw/
item_id_left
ui_sequence_edit
/ );
push(@opt_set, splice(@cgi_set, 0)) if $opt->{cgi};
for(@opt_set) {
next unless length $opt->{$_};
$hidden{$_} = $opt->{$_};
}
for (@cgi_set) {
next unless length $CGI->{$_};
$hidden{$_} = $CGI->{$_};
}
if($opt->{mailto}) {
$opt->{mailto} =~ s/\s+/ /g;
$Scratch->{mv_email_enable} = $opt->{mailto};
$hidden{mv_data_email} = 1;
}
$Vend::Session->{ui_return_stack} ||= [];
if($opt->{cgi}) {
my $r_ary = $Vend::Session->{ui_return_stack};
#::logDebug("ready to maybe push/pop return-to from stack, stack = " . ::uneval($r_ary));
if($CGI::values{ui_return_stack}++) {
push @$r_ary, $CGI::values{ui_return_to};
$CGI::values{ui_return_to} = $r_ary->[0];
}
elsif ($CGI::values{ui_return_to}) {
@$r_ary = ( $CGI::values{ui_return_to} );
}
$opt_out{tpl_return_to} = $Tag->return_to();
#::logDebug("return-to stack = " . ::uneval($r_ary));
}
if(ref $opt->{hidden}) {
my ($hk, $hv);
while ( ($hk, $hv) = each %{$opt->{hidden}} ) {
$hidden{$hk} = $hv;
}
}
#### Extra buttons
my $extra_ok = $blob_widget
|| $linecount > 4
|| defined $opt->{include_form}
|| $mlabel;
if ($extra_ok and ! $opt->{no_top} and ! $opt->{nosave}) {
my @out;
if($opt->{back_text}) {
push @out, <<EOF;
<TR class=rnorm>
<td> </td>
<td align=left colspan=$oddspan class=cdata>
EOF
push @out, <<EOF if ! $opt->{bottom_buttons};
<INPUT TYPE=submit NAME=mv_click VALUE="$opt->{back_text}"> <INPUT TYPE=submit NAME=mv_click VALUE="$opt->{cancel_text}"> <B><INPUT TYPE=submit NAME=mv_click VALUE="$opt->{next_text}"></B>
<BR>
EOF
push @out, <<EOF;
$mlabel
</TD>
</TR>
<tr class=rspacer>
<td colspan=$span><img src="$opt->{clear_image}" width=1 height=3 alt=x></td>
</tr>
EOF
}
elsif ($opt->{wizard}) {
push @out, <<EOF;
<TR class=rnorm>
<td> </td>
<td align=left colspan=$oddspan class=cdata>
EOF
push @out, <<EOF if ! $opt->{bottom_buttons};
<INPUT TYPE=submit NAME=mv_click VALUE="$opt->{cancel_text}"> <B><INPUT TYPE=submit NAME=mv_click VALUE="$opt->{next_text}"></B>
<BR>
EOF
push @out, <<EOF;
$mlabel
</TD>
</TR>
<tr class=rspacer>
<td colspan=$span><img src="$opt->{clear_image}" width=1 height=3 alt=x></td>
</tr>
EOF
}
else {
push @out, <<EOF;
<TR class=rnorm>
<td> </td>
<td align=left colspan=$oddspan class=cdata>
<B><INPUT TYPE=submit NAME=mv_click VALUE="$opt->{next_text}">
</B>
EOF
push @out, <<EOF unless $opt->{nocancel};
<INPUT TYPE=submit NAME=mv_click VALUE="$opt->{cancel_text}">$mlabel
EOF
push @out, <<EOF if $opt->{show_reset};
<INPUT TYPE=reset>
EOF
push @out, <<EOF;
$mlabel
</TD>
</TR>
<tr class=rspacer>
<td colspan=$span><img src="$opt->{clear_image}" width=1 height=3 alt=x></td>
</tr>
EOF
}
$opt_out{tpl_top_buttons} = join "", @out;
}
$opt_out{tpl_blob_widget} = $blob_widget;
#### Extra buttons
if($opt->{ui_new_item} and $opt->{ui_clone_tables}) {
my @sets;
my %seen;
my @tables = split /[\s\0,]+/, $opt->{ui_clone_tables};
for(@tables) {
if(/:/) {
push @sets, $_;
}
s/:.*//;
}
my %tab_checked;
for(@tables, @sets) {
$tab_checked{$_} = 1 if s/\*$//;
}
@tables = grep ! $seen{$_}++ && defined $Config->{Database}{$_}, @tables;
my $tab = '';
my $set .= <<'EOF';
[flag type=write table="_TABLES_"]
[perl tables="_TABLES_"]
delete $Scratch->{clone_tables};
return if ! $CGI->{ui_clone_id};
return if ! $CGI->{ui_clone_tables};
my $id = $CGI->{ui_clone_id};
my $out = "Cloning id=$id...";
my $new = $CGI->{$CGI->{mv_data_key}}
or do {
$out .= ("clone $id: no mv_data_key '$CGI->{mv_data_key}'");
$Scratch->{ui_message} = $out;
return;
};
if($new =~ /\0/) {
$new =~ s/\0/,/g;
Log("cannot clone multiple keys '$new'.");
return;
}
my %possible;
my @possible = qw/_TABLES_/;
@possible{@possible} = @possible;
my @tables = grep /\S/, split /[\s,\0]+/, $CGI->{ui_clone_tables};
my @sets = grep /:/, @tables;
@tables = grep $_ !~ /:/, @tables;
for(@tables) {
next unless $possible{$_};
my $db = $Db{$_};
next unless $db;
my $new =
my $res = $db->clone_row($id, $new);
if($res) {
$out .= "cloned $id to to $new in table $_<BR>\n";
}
else {
$out .= "FAILED clone of $id to to $new in table $_<BR>\n";
}
}
for(@sets) {
my ($t, $col) = split /:/, $_;
my $db = $Db{$t} or next;
my $res = $db->clone_set($col, $id, $new);
if($res) {
$out .= "cloned $col=$id to to $col=$new in table $t<BR>\n";
}
else {
$out .= "FAILED clone of $col=$id to to $col=$new in table $t<BR>\n";
}
}
$Scratch->{ui_message} = $out;
return;
[/perl]
EOF
my $tabform = '';
@tables = grep $Tag->if_mm( { table => "$_=i" } ), @tables;
for(@tables) {
my $db = Vend::Data::database_exists_ref($_)
or next;
next unless $db->record_exists($opt->{ui_clone_id});
my $checked = $tab_checked{$_} ? ' CHECKED' : '';
$tabform .= <<EOF;
<INPUT TYPE=CHECKBOX NAME=ui_clone_tables VALUE="$_"$checked> clone to <b>$_</B><BR>
EOF
}
for(@sets) {
my ($t, $col) = split /:/, $_;
my $checked = $tab_checked{$_} ? ' CHECKED' : '';
$tabform .= <<EOF;
<INPUT TYPE=CHECKBOX NAME=ui_clone_tables VALUE="$_"$checked> clone entries of <b>$t</B> matching on <B>$col</B><BR>
EOF
}
my $tabs = join " ", @tables;
$set =~ s/_TABLES_/$tabs/g;
$Scratch->{clone_tables} = $set;
$opt_out{tpl_clone} = <<EOF;
<tr class=rtitle>
<td colspan=$span>
$tabform<INPUT TYPE=hidden NAME=mv_check VALUE="clone_tables">
<INPUT TYPE=hidden NAME=ui_clone_id VALUE="$opt->{ui_clone_id}">
</td>
</tr>
EOF
}
my %break;
my %break_label;
if($opt->{ui_break_before}) {
#::logDebug("Have a break_before");
my @tmp = grep /\S/, split /[\s,\0]+/, $opt->{ui_break_before};
@break{@tmp} = @tmp;
if($opt->{ui_break_before_label}) {
@tmp = grep /\S/, split /\s*[,\0]\s*/, $opt->{ui_break_before_label};
for(@tmp) {
my ($br, $lab) = split /\s*=\s*/, $_;
$break_label{$br} = $lab;
}
}
}
if(!$db and ! $opt->{notable}) {
return "<TR><TD>Broken table '$table'</TD></TR>";
}
my $passed_fields = $opt->{ui_data_fields};
#::logDebug("extra=" . ::uneval($extra));
my @extra_cols;
my %email_cols;
my %ok_col;
my @cols;
my @dbcols;
my %display_only;
if($opt->{notable}) {
@cols = split /[\s,\0]+/, $passed_fields;
}
else {
while($passed_fields =~ s/(\w+[.:]+\S+)//) {
push @extra_cols, $1;
}
my @do = grep /\S/, split /[\0,\s]+/, $opt->{ui_display_only};
for(@do) {
$email_cols{$_} = 1 if $opt->{mailto};
$display_only{$_} = 1;
push @extra_cols, $_;
}
@dbcols = split /\s+/, $Tag->db_columns( {
name => $table,
columns => $passed_fields,
passed_order => 1,
});
if($opt->{ui_data_fields}) {
for(@dbcols, @extra_cols) {
unless (/^(\w+)([.:]+)(\S+)/) {
$ok_col{$_} = 1;
next;
}
my $t = $1;
my $s = $2;
my $c = $3;
if($s eq '.') {
$c = $t;
$t = $table;
}
else {
$c =~ s/\..*//;
}
next unless $Tag->db_columns( { name => $t, columns => $c, });
$ok_col{$_} = 1;
}
}
@cols = grep $ok_col{$_}, split /\s+/, $opt->{ui_data_fields};
}
$keycol = $cols[0] if ! $keycol;
if($opt->{defaults}) {
if($opt->{cgi_defaults}) {
$default->{$_} = $CGI->{$_} for @cols;
}
elsif($opt->{force_defaults}) {
$default->{$_} = $def->{$_} for @cols;
}
elsif($opt->{wizard}) {
for(@cols) {
$default->{$_} = $def->{$_} if defined $def->{$_};
}
}
else {
for(@cols) {
next if defined $default->{$_};
next unless defined $def->{$_};
$default->{$_} = $def->{$_};
}
}
}
my $super = $Tag->if_mm('super');
my $refkey = $key;
my @data_enable = ($opt->{mv_blob_pointer}, $opt->{mv_blob_field});
my @ext_enable;
my %serialize;
my %serial_data;
my @controls;
if(my $jsc = $opt->{js_changed}) {
$jsc =~ /^\w+$/
and $jsc = qq{onChange="$jsc} . q{('$$KEY$$','$$COL$$');"};
foreach my $c (@cols) {
next if $extra->{$c} =~ /\bonchange\s*=/i;
my $tpl = $jsc;
$tpl .= $extra->{$c} if length $extra->{$c};
$tpl =~ s/\$\$KEY\$\$/$key/g;
$tpl =~ s/\$\$COL\$\$/$c/g;
if ($extra->{$c} and $extra->{$c} =~ /\bonchange\s*=/i) {
$tpl =~ s/onChange="//;
$tpl =~ s/"\s*$/;/;
$extra->{$c} =~ s/\b(onchange\s*=\s*["'])/$1$tpl/i;
}
else {
$extra->{$c} = $tpl;
}
}
}
foreach my $col (@cols) {
my $t;
my $c;
my $k;
my $tkey_message;
my $ref = {};
if($col eq $keycol) {
if($opt->{ui_hide_key}) {
my $kval = $key || $override->{$col} || $default->{$col};
$hidden{$col} = $kval;
next;
}
elsif ($opt->{ui_new_item}) {
$tkey_message = $key_message;
}
}
my $do = $display_only{$col};
my $currval;
my $serialize;
if($col =~ /(\w+):+([^:]+)(?::+(\S+))?/) {
$t = $1;
$c = $2;
$c =~ /(.+?)\.\w.*/
and $col = "$t:$1"
and $serialize = $c;
$k = $3 || undef;
push @ext_enable, ("$t:$c" . $k ? ":$k" : '')
unless $do;
}
else {
$t = $table;
$c = $col;
$c =~ /(.+?)\.\w.*/
and $col = $1
and $serialize = $c;
push @data_enable, $col
unless $do and ! $opt->{mailto};
}
my $type;
my $overridden;
$currval = $data->{$col} if defined $data->{$col};
if ($opt->{force_defaults} or defined $override->{$c} ) {
$currval = $override->{$c};
$overridden = 1;
#::logDebug("hit override for $col,currval=$currval");
}
elsif (defined $CGI->{"ui_preload:$t:$c"} ) {
$currval = delete $CGI->{"ui_preload:$t:$c"};
$overridden = 1;
#::logDebug("hit preload for $col,currval=$currval");
}
elsif( ($do && ! $currval) or $col =~ /:/) {
if(defined $k) {
my $check = $k;
undef $k;
for( $override, $data, $default) {
next unless defined $_->{$check};
$k = $_->{$check};
last;
}
}
else {
$k = defined $key ? $key : $refkey;
}
$currval = tag_data($t, $c, $k) if defined $k;
#::logDebug("hit display_only for $col, t=$t, c=$c, k=$k, currval=$currval");
}
elsif (defined $default->{$c} and ! length($data->{$c}) ) {
$currval = $default->{$c};
#::logDebug("hit preload for $col,currval=$currval");
}
else {
#::logDebug("hit data->col for $col, t=$t, c=$c, k=$k, currval=$currval");
$currval = length($data->{$col}) ? $data->{$col} : '';
$overridden = 1;
}
my $namecol;
if($serialize) {
#Debug("serialize=$serialize");
if($serialize{$col}) {
push @{$serialize{$col}}, $serialize;
}
else {
my $sd;
if($col =~ /:/) {
my ($tt, $tc) = split /:+/, $col;
$sd = tag_data($tt, $tc, $k);
}
else {
$sd = $data->{$col} || $def->{$col};
}
#Debug("serial_data=$sd");
$serial_data{$col} = $sd;
$opt->{hidden}{$col} = $data->{$col};
$serialize{$col} = [$serialize];
}
$c =~ /\.(.*)/;
my $hk = $1;
#Debug("fetching serial_data for $col hk=$hk data=$serial_data{$col}");
$currval = dotted_hash($serial_data{$col}, $hk);
#Debug("fetched hk=$hk value=$currval");
$overridden = 1;
$namecol = $c = $serialize;
}
$namecol = $col unless $namecol;
$type = 'value' if $do and ! ($opt->{wizard} || ! $opt->{mailto});
if (! length $currval and defined $default->{$c}) {
$currval = $default->{$c};
}
my $meta = '';
if($error->{$c}) {
my $parm = {
name => $c,
std_label => '$LABEL$',
required => 1,
};
if($opt->{all_errors}) {
$parm->{keep} = 1;
$parm->{text} = <<EOF;
<FONT COLOR="$opt->{color_fail}">\$LABEL\$</FONT><!--%s-->
[else]{REQUIRED <B>}{LABEL}{REQUIRED </B>}[/else]
EOF
}
$ref->{label} = $Tag->error($parm);
}
#::logDebug("col=$c currval=$currval widget=$widget->{$c} label=$label->{$c} (type=$type)");
my ($drw, $drl, $drh, $drhu) = $Tag->display({
applylocale => 1,
arbitrary => $opt->{ui_meta_view},
column => $c,
default => $currval,
extra => $extra->{$c},
fallback => 1,
field => $field->{$c},
filter => $filter->{$c},
height => $height->{$c},
help => $help->{$c},
help_url => $help_url->{$c},
label => $label->{$c},
key => $key,
meta => $pmeta->{$c},
name => $namecol,
override => $overridden,
passed => $passed->{$c},
options => $options->{$c},
outboard => $outboard->{$c},
append => $append->{$c},
prepend => $prepend->{$c},
lookup => $lookup->{$c},
lookup_query => $lookup_query->{$c},
db => $database->{$c},
pre_filter => $pre_filter->{$c},
table => $t,
type => $widget->{$c} || $type,
width => $width->{$c},
template => $template,
});
$ref->{widget} = $drw;
$ref->{label} ||= $drl; ## May have been set previously
$ref->{help} = $drh;
$ref->{help_url} = $drhu;
#::logDebug("finished display of col=$c");
if($super and ! $opt->{no_meta} and ($Variable->{UI_META_LINK} || $def->{ui_meta_force}) ) {
$meta .= '<BR><FONT SIZE=1>';
# Get global variables
my $base = $Tag->var('UI_BASE', 1);
my $page = $Tag->var('MV_PAGE', 1);
my $id = $t . "::$c";
$id = $opt->{ui_meta_view} . "::$id"
if $opt->{ui_meta_view} and $opt->{ui_meta_view} ne 'metaconfig';
my $return = <<EOF;
ui_return_to=$page
ui_return_to=item_id=$opt->{item_id}
ui_return_to=ui_meta_view=$opt->{ui_meta_view}
ui_return_to=mv_return_table=$t
mv_return_table=$table
ui_return_stack=$CGI->{ui_return_stack}
EOF
$meta .= $Tag->page(
{ href => "$base/meta_editor",
form => qq{
item_id=$id
$return
}
});
$meta .= 'meta</A>';
$meta .= '<br>' . $Tag->page(
{ href => "$base/meta_editor",
form => qq{
item_id=${t}::${c}::$key
$return
}
}) . 'item-specific meta</A></FONT>'
if $opt->{ui_meta_specific};
$meta .= '</FONT>';
$ref->{meta} = $meta;
}
$ref->{error} = $Tag->error({ name => $c, keep => 1 });
if ($break{$namecol}) {
my $w = '';
while($rowcount % $rowdiv) {
$w .= '<TD> </td><TD> </td>';
$rowcount++;
}
$w .= "</TR>\n";
$w .= <<EOF if $break{$namecol};
<TR class=rbreak>
<TD COLSPAN=$span class=cbreak>$break_label{$namecol}<IMG SRC="$opt->{clear_image}" WIDTH=1 HEIGHT=1 alt=x></TD>
</TR>
EOF
$rowcount = 0;
$ref->{break} = $w;
}
push @controls, $ref;
}
$Scratch->{mv_data_enable} = '';
if($opt->{auto_secure}) {
$Scratch->{mv_data_enable} .= "$table:" . join(",", @data_enable) . ':';
$Scratch->{mv_data_enable_key} = $opt->{item_id};
}
if(@ext_enable) {
$Scratch->{mv_data_enable} .= " " . join(" ", @ext_enable) . " ";
}
#Debug("setting mv_data_enable to $Scratch->{mv_data_enable}");
my @serial = keys %serialize;
my @serial_fields;
for (@serial) {
#Debug("$_ serial_data=$serial_data{$_}");
$serial_data{$_} = uneval($serial_data{$_})
if is_hash($serial_data{$_});
$hidden{$_} = $serial_data{$_};
push @serial_fields, @{$serialize{$_}};
}
if(@serial_fields) {
$hidden{ui_serial_fields} = join " ", @serial_fields;
}
###
### Here the user can include some extra stuff in the form....
###
$opt_out{tpl_include_form} = <<EOF if $opt->{include_form};
<tr class=rnorm>
<td colspan=$span>$opt->{include_form}</td>
</tr>
EOF
### END USER INCLUDE
unless ($opt->{mailto} and $opt->{mv_blob_only}) {
@cols = grep ! $display_only{$_}, @cols;
}
$passed_fields = join " ", @cols;
$hidden{mv_data_fields} = $passed_fields;
SAVEWIDGETS: {
last SAVEWIDGETS if $opt->{nosave};
my @out;
if($opt->{back_text}) {
push @out, <<EOF;
<TR class=rnorm>
<td> </td>
<td align=left colspan=$oddspan class=cdata>
<INPUT TYPE=submit NAME=mv_click VALUE="$opt->{back_text}"> <INPUT TYPE=submit NAME=mv_click VALUE="$opt->{cancel_text}"> <B><INPUT TYPE=submit NAME=mv_click VALUE="$opt->{next_text}"></B>
EOF
}
elsif($opt->{wizard}) {
push @out, <<EOF;
<TR class=rnorm>
<td> </td>
<td align=left colspan=$oddspan class=cdata>
<INPUT TYPE=submit NAME=mv_click VALUE="$opt->{cancel_text}"> <B><INPUT TYPE=submit NAME=mv_click VALUE="$opt->{next_text}"></B>
EOF
}
else {
push @out, qq{<TR class=rnorm>
<td> </td>
<td align=left colspan=$oddspan class=cdata>
<B><INPUT TYPE=submit NAME=mv_click VALUE="$opt->{next_text}"></B>};
push @out,
qq{ <INPUT TYPE=submit NAME=mv_click VALUE="$opt->{cancel_text}">}
unless $opt->{nocancel};
push @out, qq{ <INPUT TYPE=reset>}
if $opt->{show_reset};
}
if(! $opt->{notable} and $Tag->if_mm('tables', "$table=x") and ! $db->config('LARGE') ) {
my $checked = ' CHECKED';
$checked = ''
if defined $opt->{mv_auto_export} and ! $opt->{mv_auto_export};
my $autoexpstr = errmsg('Auto-export');
push @out, <<EOF unless $opt->{noexport} or $opt->{nosave};
<small>
<INPUT TYPE=checkbox NAME=mv_auto_export VALUE="$table"$checked> $autoexpstr
EOF
}
if($exists and ! $opt->{nodelete} and $Tag->if_mm('tables', "$table=d")) {
my $extra = $Tag->return_to( { type => 'click', tablehack => 1 });
my $page = $CGI->{ui_return_to};
$page =~ s/\0.*//s;
my $url = $Tag->area( {
href => $page,
form => qq!
deleterecords=1
ui_delete_id=$key
mv_data_table=$table
mv_click=db_maintenance
mv_action=back
$extra
!,
});
push @out, <<EOF if ! $opt->{nosave};
<BR><BR><A
onClick="return confirm('Are you sure you want to delete $key?')"
HREF="$url"><IMG SRC="delete.gif" ALT="Delete $key" BORDER=0></A> Delete
EOF
}
push @out, <<EOF;
</small>
</td>
</tr>
EOF
$opt_out{tpl_bottom_buttons} = join "", @out;
} # end SAVEWIDGETS
my $message = '';
if($opt->{bottom_errors}) {
my $err = $Tag->error( {
show_var => $error_show_var,
show_error => 1,
joiner => '<BR>',
}
);
push @errors, $err if $err;
}
$opt->{color_fail} ||= 'red';
$opt->{color_success} ||= 'green';
if(@errors) {
# $message .= '<P>Errors:';
# $message .= qq{<FONT COLOR="$opt->{color_fail}">};
# $message .= '<BLOCKQUOTE>';
# $message .= join "<BR>", @errors;
# $message .= '</BLOCKQUOTE></FONT>';
my $join = $opt->{error_joiner} || '<BR>';
$opt_out{tpl_errors} = join $join, @errors;
}
if(@messages) {
# $message .= '<P>Messages:';
# $message .= qq{<FONT COLOR="$opt->{color_success}">};
# $message .= '<BLOCKQUOTE>';
# $message .= join "<BR>", @messages;
# $message .= '</BLOCKQUOTE></FONT>';
my $join = $opt->{message_joiner} || '<BR>';
$opt_out{tpl_messages} = join $join, @messages;
}
$Tag->error( { all => 1 } ) unless $opt->{no_error_clear};
my $eregion = editor_region($opt, \%opt_out, \%hidden);
my $cregion = column_region($opt, \%opt_out, \@controls);
$template ||= $Default_template;
show_times("end table editor format item_id=$key") if $Global::ShowTimes;
my $result = run_templates( $opt, [ @$eregion, @$cregion ], \$template);
show_times("end table editor region display item_id=$key") if $Global::ShowTimes;
return $result;
}
EOR