[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,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} || ' <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/,/,/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/ / /g;
}
$blob_widget =3D <<EOF unless $opt->{ui_blob_hidden};
<B>$msg1:</B> $blob_widget
<INPUT TYPE=3Dcheckbox NAME=3Dmv_blob_only VALUE=3D1$checked> $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
</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/"/"/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/"/"/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> </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}"> <INP=
UT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}"> <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> </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}"> <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> </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};
<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;
<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} <a href=3D"\$HELP_URL\=
$" title=3D"\$HELP\$">$opt->{help_anchor}</a>{/HELP_EITHER} {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> </td><TD> </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> </td><TD> </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/\&/&/g;
$serial_data{$_} =3D~ s/"/"/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> </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}"> <INP=
UT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}"> <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> </td>
<td align=3Dleft colspan=3D$oddspan class=3Dcdata>
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}"> <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;
<INPUT TYPE=3Dsubmit NAME=3Dmv_click VALUE=3D"$opt->{cancel_text}" st=
yle=3D"$opt->{cancel_button_style}">
EOF
chunk 'RESET_BOTTOM', qq{ <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>
<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;