Fix nesting problem in PayPal affecting b_state
[interchange.git] / code / UI_Tag / flex_select.coretag
1 # Copyright 2002-2007 Interchange Development Group and others
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.  See the LICENSE file for details.
7
8 # $Id: flex_select.coretag,v 1.18 2009-05-01 16:02:50 mheins Exp $
9
10 UserTag flex-select Order      table
11 UserTag flex-select addAttr
12 UserTag flex-select attrAlias  ml height
13 UserTag flex-select hasEndTag
14 UserTag flex-select Version    $Revision: 1.18 $
15 UserTag flex-select Routine    <<EOR
16 use vars qw/$CGI $Tmp $Tag/;
17 my @fs_more = qw/
18         help_name
19         icon_name
20         page_banner
21         page_title
22         ui_break_before
23         ui_description_fields
24         ui_flex_description
25         ui_flex_key
26         ui_show_fields
27         ui_sort_field
28         ui_sort_option
29 /;
30 sub flex_select_init {
31         my ($table, $opt) = @_;
32
33         my @warnings;
34         my @errors;
35
36 #::logDebug("Entering flex_select init");
37         if($CGI->{mv_more_ip}) {
38                 for(@fs_more) {
39                         $CGI->{$_} = $::Values->{$_};
40                 }
41         }
42
43         if($CGI->{mv_return_table}) {
44                 my $rt = delete $CGI->{mv_return_table};
45                 $rt =~ s/^\0+//;
46                 $rt =~ s/\0.*//;
47                 $CGI->{mv_data_table} = $rt if $rt;
48         }
49
50         my $bounce_url;
51         $::Scratch->{ui_class} = $CGI->{ui_class}
52                 if $CGI->{ui_class} &&  $CGI->{ui_class} =~ /^\w+$/;
53
54         if($opt->{sql_query}) {
55                 my $spec;
56                 eval {
57                         ($table) = Vend::Scan::sql_statement($opt->{sql_query}, { table_only => 1});
58                 };
59                 if($@) {
60                         $Tag->error( {
61                                                 set => errmsg(
62                                                                         "flex-select -- bad query %s: %s",
63                                                                         $opt->{sql_query},
64                                                                         $@,
65                                                                 ),
66                                                 name => 'flex_select',
67                                                 });
68                         return undef;
69                 }
70         }
71
72         if($table =~ s/\.(txt|asc)$/_$1/) {
73                 $table =~ s:.*/::;
74         }
75         my $db = database_exists_ref($table);
76
77         $Tmp->{flex_select} ||= {};
78         my $ts = $Tmp->{flex_select}{$table} = {};
79
80         if(! $db) {
81                 $Tag->error({
82                                                 name => 'flex_select',
83                                                 set =>  errmsg('no %s database', $table),
84                                         });
85                 my $url = $Tag->area( {
86                                                         href => $::Variable->{UI_ERROR_PAGE} || 'admin/error',
87                                                         secure => $::Variable->{UI_SECURE},
88                                                 });
89 #::logDebug("delivering error url=$url");
90                 $Tag->deliver( { location => $url });
91                 return;
92         }
93
94         if( $::Variable->{UI_LARGE_TABLE} =~ /\b$table\b/ or $db->config('LARGE') ) {
95                 $ts->{large} = 1;
96         }
97
98         if( $db->config('COMPOSITE_KEY') ) {
99                 $ts->{multikey} = 1;
100                 $ts->{key_columns} = $db->config('_Key_columns');
101         }
102
103         DELETE: {
104                 last DELETE unless $CGI->{item_id};
105                 last DELETE unless delete $CGI->{deleterecords};
106                 unless ($Tag->if_mm('tables', '=d')) {
107                         $Tag->error({
108                                                         name => 'flex_select',
109                                                         set => errmsg("no permission to delete records"),
110                                                 });
111                         last DELETE;
112                 };
113
114                 $Vend::Cfg->{NoSearch} = '';
115
116                 my @ids = split /\0/, $CGI->{item_id};
117                 for(grep $_, @ids) {
118                         if($db->delete_record($_)) {
119                                 push @warnings, errmsg("Deleted record %s", $_);
120                         }
121                         else {
122                                 push @errors, $db->errstr();
123                         }
124                 }
125         }
126
127         SEQUENCE: {
128                 my $dest = $CGI->{ui_sequence_destination} || '__UI_BASE__/flex_editor';
129 #::logDebug("Entering flex_select sequence edit stuff");
130                 last SEQUENCE unless $CGI->{ui_sequence_edit};
131 #::logDebug("doing flex_select sequence edit stuff");
132                 my $doit;
133                 if($CGI->{item_id_left} =~ s/^(.*?)[\0]//) {
134                         $CGI->{ui_sequence_edit} = 1;
135                         $CGI->{item_id} = $1;
136                         $doit = 1;
137                 }
138                 elsif ($CGI->{item_id_left}) {
139                         $CGI->{item_id} = delete $CGI->{item_id_left};
140                         delete $CGI->{ui_sequence_edit};
141                         $doit = 1;
142                 }
143                 else {
144                         delete $CGI->{item_id};
145                         delete $CGI->{ui_sequence_edit};
146                 }
147                 last SEQUENCE unless $doit;
148                 my $url = $Tag->area( {
149                                                                         href => $dest,
150                                                                         form => qq{
151                                                                                 mv_data_table=$CGI->{mv_data_table}
152                                                                                 item_id=$CGI->{item_id}
153                                                                                 item_id_left=$CGI->{item_id_left}
154                                                                                 ui_sequence_edit=$CGI->{ui_sequence_edit}
155                                                                         },
156                                                                 });
157 #::logDebug("flex_select sequence developed URL=$url");
158                 $Tag->deliver( { location => $url } );
159                 return;
160         }
161
162         $ts->{table_meta} = $Tag->meta_record($table, $CGI->{ui_meta_view}) || {};
163         my $tm = $ts->{table_meta};
164         
165         my $extra;
166         if($tm->{name}) {
167                 $extra .= "<b>$tm->{name}</br>";
168         }
169         if($ts->{help_url}) {
170                 $extra .= qq{&nbsp;&nbsp;&nbsp;<small><a href="$ts->{help_url}">};
171                 $extra .= errmsg('help');
172                 $extra .= "</a></small>";
173         }
174         if($ts->{help}) {
175                 $extra .= "<blockquote>$ts->{help}</blockquote>";
176         }
177         $::Scratch->{page_banner} ||= $::Scratch->{page_title};
178         $::Scratch->{page_banner} .= $extra;
179
180         for(@errors) {
181                 $Tag->error({ name => 'flex_select', set => $_ });
182         }
183         for(@warnings) {
184                 $Tag->warnings($_);
185         }
186         return;
187 }
188
189 sub {
190         my ($table, $opt, $body) = @_;
191
192 #::logDebug("Entering flex_select");
193         my $CGI = \%CGI::values;
194
195         $table ||= $CGI->{mv_data_table};
196
197         ## Do the initialization
198         if($opt->{init}) {
199                 return flex_select_init($table, $opt);
200         }
201
202         my $filter;
203         if(ref($opt->{filter}) eq 'HASH') {
204                 $filter = $opt->{filter};
205         }
206         $filter ||= {};
207
208         my $spec;
209         my $stmt;
210         my $q;
211         if($opt->{sql_query}) {
212                 $q = $opt->{sql_query};
213                 if($CGI->{ui_sort_field} =~ s/^(\w+)(:[rfn]+)?$/$1/) {
214                         my $field = $1;
215                         my $opt = $2 || $CGI->{ui_sort_option};
216                         $field .= ' DESC', $CGI->{ui_sort_option} = 'r' if $opt =~ /r/i;
217                         $q =~ s/
218                                                 \s+ORDER\s+BY
219                                                 \s+(\w+(\s+desc\w*)?)
220                                                 (\s*,\s*\w+(\s+desc\w*)?)*
221                                                 (\s*$|\s+LIMIT\s+\d+(?:\s*,\s*\d+)?)
222                                    / ORDER BY $field$5/ix
223                         or
224                                 $q =~ s/(\s+LIMIT\s+\d+(?:\s*,\s*\d+)?)/ ORDER BY $field$1/ix
225                                 or $q .= " ORDER BY $field";
226                 }
227
228                 eval {
229                         ($spec) = Vend::Scan::sql_statement($q);
230                 };
231                 if($@ || ! $spec->{rt}) {
232                         $Tag->error( {
233                                                 set => errmsg("flex-select -- bad query %s: %s", $q, $@),
234                                                 name => 'flex_select',
235                                                 });
236                         return undef;
237                 }
238                 $table = $spec->{rt}->[0];
239         }
240
241         my $ref = dbref($table)
242                 or do {
243                         my $msg = errmsg("%s: table '%s' does not exist", 'flex_select', $table);
244                         logError($msg);
245                         $Tag->error({ name => 'flex_select', set => $msg });
246                         return undef;
247                 };
248         my $ts = $Tmp->{flex_select}{$table} ||= {};
249         my $meta = $ts->{table_meta} ||= $Tag->meta_record($table, $CGI->{ui_meta_view});
250
251 #::logDebug("flex_select table=$table");
252         if($meta->{sql_query}) {
253                 $q = $meta->{sql_query};
254                 if($CGI->{ui_sort_field} =~ s/^(\w+)(:[rfn]+)?$/$1/) {
255                         my $field = $1;
256                         my $opt = $2 || $CGI->{ui_sort_option};
257                         $field .= ' DESC', $CGI->{ui_sort_option} = 'r' if $opt =~ /r/i;
258                         $q =~ s/
259                                                 \s+ORDER\s+BY
260                                                 \s+(\w+(\s+desc\w*)?)
261                                                 (\s*,\s*\w+(\s+desc\w*)?)*
262                                                 (\s*$|\s+LIMIT\s+\d+(?:\s*,\s*\d+)?)
263                                    / ORDER BY $field$5/ix
264                         or
265                                 $q =~ s/(\s+LIMIT\s+\d+(?:\s*,\s*\d+)?)/ ORDER BY $field$1/ix
266                                 or $q .= " ORDER BY $field";
267                 }
268
269                 eval {
270                         ($spec) = Vend::Scan::sql_statement($q);
271                 };
272                 if($@ or ! $spec->{rt}) {
273                         $Tag->error( {
274                                                 set => errmsg("flex-select -- bad query %s: %s", $q, $@),
275                                                 name => 'flex_select',
276                                                 });
277                         return undef;
278                 }
279                 $table = $spec->{rt}->[0];
280         }
281
282         if( $table ne $ref->config('name')) {
283                 ## Probably transient database
284                 $CGI->{mv_data_table_real} = $table = $ref->config('name');
285         }
286
287         my @labels;          ## Locally set labels in ui_show_fields
288         my @views;           ## Locally set view data in ui_show_fields
289         my @filter_show;     ## Locally set filters in ui_show_fields
290         my @calcs;           ## Data calculation code (if any) from fs_data_calc
291         my @redirect;        ## A column with a different metadata from standard
292         my @extras;          ## A column with a different metadata from standard
293         my @style;           ## Style for data cell, only have to read once
294         my @link_page;       ## Locally set filters in ui_show_fields
295         my @link_parm;       ## Locally set filters in ui_show_fields
296         my @link_parm_extra; ## Locally set filters in ui_show_fields
297         my @link_anchor;     ## Locally set filters in ui_show_fields
298         my $filters_done;    ## Tells us we are done with filters
299
300         if(my $show = $CGI->{ui_show_fields} ||= $meta->{ui_show_fields} || $meta->{field}) {
301                 my $i = 0;
302                 if($show =~ s/[\r\n]+/\n/g) {
303                         $show =~ s/^\s+//;
304                         $show =~ s/\s+$//;
305                         my @f = split /\n/, $show;
306                         my @c;
307                         for(@f) {
308                                 s/^\s+//;
309                                 s/\s+$//;
310                                 if(s/\s*\((.+)\)\s*$//)  {
311                                         $filter_show[$i] = $1;
312                                 }
313                                 
314                                 if(/^(\w+)-(\w+)$/) {
315                                         push @c, $1;
316                                         $redirect[$i] = $2;
317                                 }
318                                 elsif(/^(\w+)(?:-([^=]+))?(?:=(.*))?/) {
319                                         push @c, $1;
320                                         $views[$i] = $2 if $2;
321                                         $labels[$i] = $3;
322                                 }
323                                 else {
324                                         push @c, $_;
325                                 }
326                                 $i++;
327                         }
328                         $show = join ",", @c;
329                 }
330                 else {
331                         $show =~ s/(\w+)(?:\((.*?)\))?/ ($filter_show[$i++] = $2), $1/eg;
332                         $show =~ s/[\0,\s]+/,/g;
333                 }
334                 $CGI->{ui_description_fields} = $show;
335                 $filters_done = 1;
336         }
337
338         if($spec) {
339 #::logDebug("flex_select spec=$spec");
340                 if($spec->{rf} and $spec->{rf}[0] ne '*') {
341                         my @c;
342                         my $header;
343                         for(my $i = 0; $i < @{$spec->{rf}}; $i++) {
344                                 if($spec->{hf}[$i]) {
345                                         $header++;
346                                         push @c, $spec->{rf}[$i] . '=' . $spec->{hf}[$i];
347                                 }
348                                 else {
349                                         push @c, $spec->{rf}[$i];
350                                 }
351                         }
352                         if($header) {
353                                 $CGI->{ui_show_fields} = join "\n", @c;
354                         }
355                         else {
356                                 $CGI->{ui_show_fields} = join " ", @c;
357                         }
358                 }
359                 if($spec->{tf} and $spec->{tf}[0]) {
360                         $CGI->{ui_sort_field} = join ",", @{$spec->{tf}};
361                         $CGI->{ui_sort_option} = join ",", @{$spec->{to}};
362                 }
363                 $CGI->{ui_list_size} = $spec->{ml} if $spec->{ml};
364         }
365
366         $meta ||= {};
367
368         if($CGI->{ui_flex_key}) {
369                 $ts->{keypos} = $CGI->{ui_flex_key};
370         }
371         else {
372                 $ts->{keypos} = $ref->config('KEY_INDEX');
373         }
374
375         $ts->{keyname} = $ref->config('KEY');
376         $ts->{owner_field} = $ref->config('OWNER_FIELD') || $::Scratch->{ui_owner};
377
378         if($CGI->{ui_exact_record}) {
379 #::logDebug("found exact record input");
380                 undef $CGI->{mv_like_field};
381                 my $id = $CGI->{mv_like_spec};
382                 $id =~ s/\0.*//s;
383                 my $url = $Tag->area({
384                                                                 href => 'admin/flex_editor',
385                                                                 form => qq{
386                                                                         mv_data_table=$CGI->{mv_data_table}
387                                                                         item_id=$id
388                                                                         ui_meta_view=$CGI->{ui_meta_view}
389                                                                 },
390                                                         });
391
392                 $Tag->deliver({ location => $url });
393 #::logDebug("deliver=$url");
394                 return;
395         }
396
397         my $sf;
398         if($sf = $CGI->{ui_sort_field} and $sf =~ s/^(\w+)([,\s\0]+.*)?$/$1/) {
399                 my $fmeta;
400                 $fmeta = $Tag->meta_record("${table}::$sf", $CGI->{ui_meta_view})
401                         and do {
402                                 $CGI->{ui_more_alpha} = $fmeta->{ui_more_alpha}
403                                         if length($fmeta->{ui_more_alpha});
404                                 if (! $CGI->{ui_sort_option} and length($fmeta->{ui_sort_option}) ) {
405                                         my $o = $fmeta->{ui_sort_option};
406                                         if($CGI->{ui_sort_option} =~ /r/) {
407                                                 $o =~ s/^([^r]+)$/$1r/
408                                                         or $o =~ s/r//;
409                                         }
410                                         $CGI->{ui_sort_option} = $o;
411                                 }
412                         };
413         }
414
415         for(qw/ui_more_alpha ui_more_decade ui_meta_specific/) {
416                 $CGI->{$_} = $meta->{$_} unless defined $CGI->{$_};
417         }
418         $Vend::Cfg->{NoSearch} = '';
419         my $out_message = '';
420         my $ui_text_qualification = $CGI->{ui_text_qualification};
421
422         if ($ui_text_qualification and $CGI->{ui_text_qualification} =~ /[<!=>\^]/ ) {
423                 if($ts->{owner_field}) {
424                         $CGI->{ui_text_qualification} = <<EOF;
425 co=1
426 st=db
427 sf=$ts->{owner_field}
428 se=$Vend::username
429 op=eq
430 nu=0
431 os=0
432 su=0
433 bs=0
434 EOF
435                 }
436                 else {
437                         $CGI->{ui_text_qualification} = "co=1\n";
438                 }
439
440                 my @entries = split /\s+(and|or)\s+/i,  $ui_text_qualification;
441                 my $or;
442                 for(@entries) {
443                         if(/^or$/i) {
444                                 $or = 1;
445                                 $CGI->{ui_text_qualification} .= "os=1\n";
446                                 next;
447                         }
448                         elsif(/^and$/i) {
449                                 $or = 0;
450                                 $CGI->{ui_text_qualification} .= "os=0\n";
451                                 next;
452                         }
453                         my ($f, $op, $s) = split /\s*([<=!>\^]+)\s*/, $_, 2;
454                         $op = "eq" if $op eq "==";
455                         $op = "rm" if $op eq "=";
456                         if($op eq '^') {
457                                 $op = 'rm';
458                                 $CGI->{ui_text_qualification} .= "bs=1\nsu=1\n";
459                         }
460                         else {
461                                 $CGI->{ui_text_qualification} .= "bs=0\nsu=0\n";
462                         }
463                         my $ms = defined $CGI->{mv_min_string} ? $CGI->{mv_min_string} : 1;
464                         if(length($s) > $ms) {
465                                 $CGI->{ui_text_qualification} .= "se=$s\nsf=$f\nop=$op\n";
466                         }
467                         else {
468                                 $CGI->{ui_text_qualification} .= "se=.\nsf=$f\nop=rn\n";
469                         }
470                         if($op =~ /[<>]/ and $s =~ /^[\d.]+$/) {
471                                 $CGI->{ui_text_qualification} .= "nu=1\n";
472                         }
473                         else {
474                                 $CGI->{ui_text_qualification} .= "nu=0\n";
475                         }
476                 }
477                 if(defined $or) {
478                         $CGI->{ui_text_qualification} .= $or ? "os=1\n" : "os=0\n";
479                 }
480
481                 $out_message = errmsg('Entries matching "%s"', $ui_text_qualification);
482         }
483         elsif ($ui_text_qualification) {
484                 $CGI->{ui_text_qualification} = "se=$CGI->{ui_text_qualification}";
485                 $out_message = errmsg('Entries matching "%s"', $ui_text_qualification);
486                 if($ts->{owner_field}) {
487                         $CGI->{ui_text_qualification} = <<EOF;
488 co=1
489 sf=$ts->{owner_field}
490 se=$Vend::username
491 op=eq
492 sf=:*
493 se=$CGI->{ui_text_qualification}
494 EOF
495                 }
496         }
497         elsif ( $CGI->{mv_like_field} ) {
498                 my @f = split /\0/, $CGI->{mv_like_field};
499                 my @s = split /\0/, $CGI->{mv_like_spec};
500                 my @q = 'ra=yes';
501                 my $found;
502                 for(my $i = 0; $i < @f; $i++) {
503                         next unless length $s[$i];
504                         $found++;
505                         push @q, "lf=$f[$i]";
506                         push @q, "ls=$s[$i]";
507                 }
508                 if($found) {
509                         $CGI->{ui_text_qualification} = join "\n", @q;
510                         my @out;
511                         for(@q) {
512                                 my $thing = $_;
513                                 $thing =~ s/^ls=/mv_like_spec=/;
514                                 $thing =~ s/^lf=/mv_like_field=/;
515                                 push @out, $thing; 
516                         }
517                         $ts->{like_recall} = join "\n", @out;
518                 }
519                 else       { $CGI->{ui_text_qualification} = "" }
520         }
521         elsif($ts->{owner_field}) {
522                 $CGI->{ui_text_qualification} = <<EOF;
523 co=1
524 sf=$ts->{owner_field}
525 se=$Vend::username
526 op=eq
527 EOF
528         }
529         elsif ($ts->{large}) {
530                 my $keylabel = $Tag->display({
531                                                         table => $table,
532                                                         name => 'item_id',
533                                                         column => $ts->{keyname},
534                                                         template => 1,
535                                                 });
536                 $ts->{like_spec} = $CGI->{mv_more_ip} ? 0 : 1;
537                 $CGI->{ui_text_qualification} = "";
538         }
539         else {
540                 $CGI->{ui_text_qualification} = "ra=yes";
541         }
542
543         if($meta->{ui_sort_combined} =~ /\S/) {
544                 $meta->{ui_sort_field} = $meta->{ui_sort_combined};
545                 $meta->{ui_sort_option} = '';
546         }
547
548         $CGI->{ui_sort_field}   ||= $meta->{ui_sort_field}
549                                                         ||  $meta->{lookup}
550                                                         ||  $ts->{keyname};
551         $CGI->{ui_sort_option}  ||= $meta->{ui_sort_option};
552         $CGI->{ui_sort_option}  =~ s/[\0,\s]+//g;
553         $CGI->{ui_list_size} = $opt->{height} || $meta->{height}
554                 if ! $CGI->{ui_list_size};
555
556         if(! $CGI->{ui_show_fields} ) {
557                 $CGI->{ui_show_fields} = 
558                         $CGI->{ui_description_fields}
559                                 = join ",", $ref->columns();
560         }
561         else {
562                 my $i = 0;
563                 my $show = $CGI->{ui_show_fields};
564                 if($filters_done) {
565                         # do nothing
566                 }
567                 else {
568                         if($show =~ s/[\r\n]+/\n/g) {
569                                 $show =~ s/^\s+//;
570                                 $show =~ s/\s+$//;
571                                 my @f = split /\n/, $show;
572                                 my @c;
573                                 for(@f) {
574                                         s/^\s+//;
575                                         s/\s+$//;
576                                         if(s/\s*\((.+)\)\s*$//)  {
577                                                 $filter_show[$i] = $1;
578                                         }
579                                         
580                                         if(/^(\w+)-(\w+)$/) {
581                                                 push @c, $1;
582                                                 $redirect[$i] = $2;
583                                         }
584                                         elsif(/^(\w+)(?:-([^=]+))?(?:=(.*))?/) {
585                                                 push @c, $1;
586                                                 $views[$i] = $2 if $2;
587                                                 $labels[$i] = $3;
588                                         }
589                                         else {
590                                                 push @c, $_;
591                                         }
592                                         $i++;
593                                 }
594                                 $show = join ",", @c;
595                         }
596                         else {
597                                 $show =~ s/(\w+)(?:\((.*?)\))?/ ($filter_show[$i++] = $2), $1/eg;
598                                 $show =~ s/[\0,\s]+/,/g;
599                         }
600                         $CGI->{ui_description_fields} = $show;
601                 }
602         }
603
604         my @cols = split /,/, $CGI->{ui_description_fields};
605
606         @cols = grep $ref->column_exists($_), @cols
607                 unless $spec;
608
609         my %limit_field;
610
611         $CGI->{ui_limit_fields} =~ s/[\0,\s]+/ /g;
612         $CGI->{ui_limit_fields} =~ s/^\s+//;
613         $CGI->{ui_limit_fields} =~ s/\s+$//;
614
615         my (@limit_field) = split " ", $CGI->{ui_limit_fields};
616
617         if(@limit_field) {
618                 @limit_field{@limit_field} = ();
619                 @cols = grep ! exists($limit_field{$_}), @cols;
620         }
621
622         unshift(@cols, $ts->{keyname})
623                 if $cols[0] ne $ts->{keyname};
624
625         $CGI->{ui_description_fields} = join ",", @cols;
626
627         unless ($CGI->{ui_sort_option}) { 
628                  $CGI->{ui_sort_option} = 'n'
629                                 if $ref->numeric($CGI->{ui_sort_field}); 
630         } 
631
632         my $fi = $CGI->{mv_data_table_real} || $CGI->{mv_data_table};
633         $ts->{sparams} = ($ts->{like_spec} || $spec) ? '' : <<EOF;
634
635         fi=$fi
636         st=db
637         $CGI->{ui_text_qualification}
638         su=1
639         ma=$CGI->{ui_more_alpha}
640         md=$CGI->{ui_more_decade}
641         ml=$CGI->{ui_list_size}
642         tf=$CGI->{ui_sort_field}
643         to=$CGI->{ui_sort_option}
644         rf=$CGI->{ui_description_fields}
645         nh=1
646
647 EOF
648         $::Scratch->{page_banner} .= $out_message;
649         $::Scratch->{page_title} .= $out_message;
650
651         my %output;
652 ### Header determination
653
654         my @refkeys = grep ref($opt->{$_}) eq 'HASH', keys %$opt;
655
656         my %default = (
657                 data_cell_class   => '',
658                 data_cell_style   => '',
659                 data_row_class_even   => 'rownorm',
660                 data_row_class_odd   => 'rowalt',
661                 data_row_style_even   => '',
662                 data_row_style_odd   => '',
663                 form_method => 'GET',
664                 explicit_edit => '',
665                 explicit_edit_page => '',
666                 explicit_edit_form => '',
667                 explicit_edit_anchor => '',
668                 no_code_link => '',
669                 group_image   => 'smindex.gif',
670                 group_class   => 'rhead',
671                 group_spacing   => 2,
672                 group_padding   => 0,
673                 group_width   => '100%',
674                 header_link_class   => 'rhead',
675                 header_cell_class   => 'rhead',
676                 header_cell_style   => '',
677                 header_row_class   => 'rhead',
678                 header_row_style   => '',
679                 mv_action => 'back',
680                 meta_image => errmsg('meta.png'),
681                 label => "flex_select_$table",
682                 no_checkbox => 0,
683                 radio_box => 0,
684                 user_merge => 0,
685                 check_uncheck_all => 0,
686                 number_list => 0,
687                 table_border  => 0,
688                 table_class   => 'rseparator',
689                 table_padding => 0,
690                 table_spacing => 1,
691                 table_style   => '',
692                 table_width   => '100%',
693         );
694
695         for(keys %default) {
696                 next if defined $opt->{$_};
697                 if(length $meta->{$_}) {
698                         $opt->{$_} = $meta->{$_};
699                 }
700                 else {
701                         $opt->{$_} = $default{$_};
702                 }
703         }
704
705         $opt->{ui_style} = 1 unless defined $opt->{ui_style};
706         $opt->{no_checkbox} = 1 if $ts->{multikey};
707
708         my $show_meta;
709         my $meta_anchor;
710         if($Tag->if_mm('super') and ! $opt->{no_meta}) {
711                 $show_meta = defined $::Values->{ui_meta_force}
712                                         ? $::Values->{ui_meta_force}
713                                         : $::Variable->{UI_META_SELECT};
714                 if($opt->{meta_image}) {
715                         $meta_anchor = qq{<img src="$opt->{meta_image}" border=0>};
716                 }
717                 else {
718                         $meta_anchor = 'M';
719                 }
720         }
721
722         $opt->{form_name} ||= "fs_$table";
723
724         $output{TOP_OF_TABLE} = <<EOF;
725 <table width="$opt->{table_width}" border="$opt->{table_border}" cellpadding="$opt->{table_padding}" cellspacing="$opt->{table_spacing}" class="$opt->{table_class}">
726 EOF
727
728         my $cwp = $Global::Variable->{MV_PAGE};
729         $opt->{form_href} ||= $CGI->{ui_searchpage} || $cwp;
730         $opt->{form_extra} ||= '';
731         $opt->{form_extra} .= qq{ name="$opt->{form_name}"} if $opt->{form_name};
732         $opt->{form_extra} =~ s/^\s*/ /;
733         my $action = $Tag->process({href => $opt->{form_href}});
734
735         $output{TOP_OF_FORM} = <<EOF;
736 <form action="$action" method="$opt->{form_method}"$opt->{form_extra}>
737 <input type=hidden name=mv_data_table    value="$table">
738 <input type=hidden name=mv_action        value="$opt->{mv_action}">
739 <input type=hidden name=mv_click         value="warn_me_main_form">
740 <input type=hidden name=mv_form_profile  value="$opt->{mv_form_profile}">
741 <input type=hidden name=mv_session_id    value="$Vend::SessionID">
742 EOF
743
744         ### What the heck is going on here?
745         if($CGI->{ui_meta_view}) {
746                 $output{TOP_OF_FORM} .= <<EOF;
747 <input type=hidden name=ui_meta_view         value="$CGI->{ui_meta_view}">
748 EOF
749                 $output{TOP_OF_FORM} .= $Tag->return_to();
750         }
751         else {
752                 $output{TOP_OF_FORM} .= <<EOF;
753         <!-- got no return-to -->
754 <input type=hidden name=ui_meta_specific value="$CGI->{ui_meta_specific}">
755 <input type=hidden name=ui_page_title    value="$CGI->{ui_page_title}">
756 <input type=hidden name=ui_page_banner   value="$CGI->{ui_page_banner}">
757 <input type=hidden name=ui_limit_fields  value="$CGI->{ui_limit_fields}">
758 <input type=hidden name=ui_show_fields   value="$CGI->{ui_show_fields}">
759 <input type=hidden name=ui_return_to     value="$cwp">
760 <input type=hidden name=ui_return_to     value="mv_data_table=$table">
761 EOF
762         }
763
764         my $cc = $ts->{column_meta} ||= {};
765         my $mview = $CGI->{ui_meta_view};
766
767         my $cmeta = sub {
768                 my $col = shift;
769                 return $cc->{$col} if $cc->{$col};
770                 my $m = $Tag->meta_record("${table}::$col", $mview);
771                 for(@refkeys) {
772                         $m->{$_} = $opt->{$_}{$col} if exists $opt->{$_}{$col};
773                 }
774                 $cc->{$col} = $m;
775                 return $m;
776         };
777
778         my $header_cell_style = sub {
779                                 my $col = shift;
780                                 my $m = $cmeta->($col);
781 #::logDebug("meta for header=" . ::uneval($m));
782                                 my $stuff = '';
783                                 for(qw/ class style align valign /) {
784                                         my $tag = "header_cell_$_";
785                                         my $thing;
786                                         if(ref $opt->{$tag}) {
787                                                 $thing = $opt->{$tag}{$col} || $m->{$tag} || $opt->{"all_$tag"}
788                                                         or next;
789                                         }
790                                         else {
791                                                 $thing = $m->{$tag} || $opt->{$tag}
792                                                         or next;
793                                         }
794                                         encode_entities($thing);
795                                         $stuff .= qq{ $_="$thing"};
796                                 }
797                                 return $stuff;
798                         };
799
800         my $data_cell_style = sub {
801                                 my $col = shift;
802                                 my $m = $cmeta->($col);
803                                 my $stuff = '';
804                                 for(qw/ class style align valign /) {
805                                         my $tag = "data_cell_$_";
806                                         my $thing;
807                                         if(ref $opt->{$tag}) {
808                                                 $thing = $opt->{$tag}{$col} || $m->{$tag} || $opt->{"all_$tag"}
809                                                         or next;
810                                         }
811                                         else {
812                                                 $thing = $m->{$tag} || $opt->{$tag}
813                                                         or next;
814                                         }
815                                         encode_entities($thing);
816                                         $stuff .= qq{ $_="$thing"};
817                                 }
818                                 return $stuff;
819                         };
820
821         my @head;
822         my $rc = $opt->{header_row_class};
823         push @head, "<tr ";
824         push @head, qq( class=$opt->{header_row_class}) if $opt->{header_row_class};
825         push @head, qq( style=$opt->{header_row_style}) if $opt->{header_row_style};
826         push @head, ">\n";
827         if(! $opt->{no_checkbox}) {
828                 push @head, "   <td class=rhead>&nbsp;</td>" 
829         }
830         if($opt->{radio_box}) {
831                 push @head, "   <td class=rhead>&nbsp;</td>" 
832         }
833         if($opt->{number_list}) {
834                 push @head, "   <td class=rhead align=right>#&nbsp;</td>" ;
835         }
836         if($opt->{explicit_edit}) {
837                 push @head, "   <td class=rhead>&nbsp;</td>" 
838         }
839
840         my $return = <<EOF;
841 ui_return_to=$cwp
842 ui_return_to=ui_meta_view=$opt->{ui_meta_view}
843 ui_return_to=mv_return_table=$table
844 mv_return_table=$table
845 ui_return_stack=$CGI->{ui_return_stack}
846 start_at=extended.ui_more_alpha
847 EOF
848
849         my %mkey;
850         if($ts->{multikey}) {
851                 for(@{$ts->{key_columns}}) {
852                         $mkey{$_} = 1;
853                 }
854         }
855
856         my @mcol;
857
858         my $idx = 0;
859         foreach my $col (@cols) {
860                 my $mcol = $col;
861                 if($redirect[$idx]) {
862                         $mcol .= "-$redirect[$idx]";
863                 }
864                 my $td_extra = $header_cell_style->($mcol);
865
866                 ## $cc is set in header_cell_class 
867                 my $m = $cc->{$mcol};
868
869                 if($mkey{$col}) {
870                         push @mcol, $idx - 1;
871                 }
872
873                 push @head, <<EOF;
874 <td$td_extra>
875 <table align="left" class="$opt->{group_class}" cellspacing=$opt->{group_spacing} cellpadding=$opt->{group_padding} width="$opt->{group_width}">
876     <tr>
877 EOF
878                 unless($opt->{no_group} || $m->{fs_no_group}) {
879                         my $u = $Tag->area({
880                                                                 href => 'admin/flex_group',
881                                                                 form => qq(
882                                                                                         mv_data_table=$table
883                                                                                         ui_meta_view=$mview
884                                                                                         from_page=$Global::Variable->{MV_PAGE}
885                                                                                         mv_arg=$col
886                                                                                 ),
887                                                         });
888                         my $msg = errmsg('Select group by %s', $col);
889
890                         push @head, <<EOF;
891       <td align="right" valign="center" width=1>
892                 <a href="$u" title="$msg"><img src="$opt->{group_image}" border=0></a>
893       </td>
894 EOF
895
896                 }
897
898                 my $o = '';
899                 my $msg;
900                 my $rmsg;
901                 if($o = $m->{ui_sort_option}) {
902                         my @m;
903                         $msg = "sort by %s (%s)";
904
905                         if($CGI->{ui_sort_field} eq $col) {
906                                 if($CGI->{ui_sort_option} =~ /r/) {
907                                         $o =~ s/r//;
908                                 }
909                                 else {
910                                         $o .= "r";
911                                 }
912                         }
913                         push @m, errmsg('reverse') if $o =~ /r/;
914                         push @m, errmsg('case insensitive') if $o =~ /f/;
915                         push @m, errmsg('numeric') if $o =~ /n/;
916                         $rmsg = join ", ", @m;
917                 }
918                 else {
919                         if ($CGI->{ui_sort_field} eq $col and $CGI->{ui_sort_option} !~ /r/) {
920                                 $o .= 'r';
921                                 $msg = "sort by %s (%s)";
922                                 $rmsg = errmsg('reverse');
923                         }
924                         else {
925                                 $msg = "sort by %s";
926                         }
927                         $o .= 'n' if $ref->numeric($col);
928                 }
929                 my $sort_msg = errmsg($msg, $col, $rmsg);
930                 my $url = $Tag->area( {
931                                                                 href => $cwp,
932                                                                 form => qq(
933                                                                         $ts->{like_recall}
934                                                                         ui_text_qualification=$ui_text_qualification
935                                                                         mv_data_table=$table
936                                                                         ui_meta_view=$mview
937                                                                         ui_sort_field=$col
938                                                                         ui_sort_option=$o
939                                                                         ui_more_alpha=$m->{ui_more_alpha}
940                                                                 ),
941                                                         });
942
943                 my $lab = $labels[$idx] || $m->{label} || $col;
944
945                 # Set up some stuff for the data cells;
946                 $style[$idx] = $data_cell_style->($mcol);
947
948                 $filter_show[$idx] = $filter->{$mcol} if $filter->{$mcol};
949                 $filter_show[$idx] ||= $m->{fs_display_filter} || 'encode_entities';
950                 $filter_show[$idx] .= ' encode_entities'
951                          unless $filter_show[$idx] =~ /\b(?:encode_)?entities\b/;
952                 $style[$idx] .= " $1" while $filter_show[$idx] =~ s/(v?align=\w+)//i;
953
954                 if($views[$idx]) {
955                         my ($page, $parm, $l) = split /:/, $views[$idx];
956                         $m->{fs_link_page} = $page;
957
958                         $parm ||= 'item_id';
959                         my @p = split /[\s,\0]+/, $parm;
960                         my $arg = shift @p;
961                         $m->{fs_link_parm} = $arg;
962                         $m->{fs_link_parm_extra} = join ",", @p;
963                         $m->{fs_link_anchor} = $l;
964                 }
965
966                 if($m->{fs_link_page}) {
967                         $link_page[$idx]                = $m->{fs_link_page};
968                         $link_parm[$idx]                = $m->{fs_link_parm};
969                         if($m->{fs_link_parm_extra}) {
970                                 my @p = grep /\S/, split /[\s,\0]+/, $m->{fs_link_parm_extra};
971                                 $link_parm_extra[$idx]  = \@p;
972                         }
973                         $link_anchor[$idx]      = $m->{fs_link_anchor};
974                 }
975
976                 if(my $prog = $m->{fs_data_calc}) {
977 #::logDebug("looking at calcs=$prog");
978                         $prog =~ s/^\s+//;
979                         $prog =~ s/\s+$//;
980                         if($prog =~ /^\w+$/) {
981                                 $calcs[$idx] = $Vend::Cfg->{Sub}{$prog} || $Global::GlobalSub->{$prog};
982                         }
983                         else {
984                                 $prog =~ s/^\[(calc|perl)(.*?)\]//;
985                                 $prog =~ s{\[/(calc|perl)\]$}{};
986                                 $calcs[$idx] = $prog;
987                         }
988                         if($m->{fs_data_tables}) {
989                                 tag_perl($m->{fs_data_tables}, {});
990                         }
991                 }
992
993                 push @head, <<EOF;
994           <td$td_extra>
995                 <a href="$url" class=$opt->{header_link_class} title="$sort_msg">$lab</a>
996       </td>
997 EOF
998
999                 if($show_meta) {
1000                         my $u = $Tag->area({ href=>'admin/meta_editor',
1001                                                                  form => qq(
1002                                                                  item_id=${table}::$mcol
1003                                                                  ui_meta_view=$mview
1004                                                                  $return),
1005                                                                 });
1006                         my $tit = errmsg(
1007                                                         "Edit header meta information for %s::%s",
1008                                                         $table,
1009                                                         $col,
1010                                                 );
1011                         push @head, <<EOF;
1012 <td width=1>
1013 <a href="$u" title="$tit">$meta_anchor</a>
1014 </td>
1015 EOF
1016
1017                 }
1018
1019                 push @head, <<EOF;
1020     </tr>
1021     </table>    
1022         </td>
1023 EOF
1024
1025                 $idx++;
1026         }
1027         push @head, "</tr>";
1028
1029         shift @mcol;
1030
1031         my $ncols = $idx;
1032         $ncols++ if $opt->{explicit_edit};
1033         $ncols++ if $opt->{number_list};
1034         $ncols++ if $opt->{radio_box};
1035         $ncols++ unless $opt->{no_checkbox};
1036
1037         $output{HEADER_AREA} = join "", @head;
1038 ### Row output
1039
1040         my $cb_width = $opt->{checkbox_width} || '30';
1041         my $cb_name = $opt->{checkbox_name} || 'item_id';
1042         my $rb_name = $opt->{radiobox_name} || 'item_radio';
1043         my $edit_page = $opt->{edit_page} || 'admin/flex_editor';
1044         my $edit_parm = $opt->{edit_parm} || 'item_id';
1045         my $edit_extra = <<EOF;
1046 mv_data_table=$table
1047 ui_page_title=$CGI->{ui_page_title}
1048 ui_meta_view=$mview
1049 ui_page_banner=$CGI->{ui_page_banner}
1050 ui_meta_specific=$CGI->{ui_meta_specific}
1051 EOF
1052
1053         
1054         my @rows;
1055
1056         if($ts->{like_spec}) {
1057                 ## Do nothing
1058         }
1059         elsif($body =~ /\S/) {
1060                 my $o = { 
1061                                         label           => $opt->{label},
1062                                         list_prefix     => 'flex',
1063                                         prefix          => 'flex',
1064                                         more            => 1,
1065                                         search          => $ts->{sparams},
1066                                 };
1067                 push @rows, tag_loop_list($o);
1068         }
1069         else {
1070                 my $ary;
1071                 my $search;
1072                 my $params;
1073                 my $c;
1074 #::logDebug("MM=$CGI->{MM}($CGI::values{MM}) mv_more_matches=$CGI->{mv_more_matches}($CGI::values{mv_more_matches})");
1075                 if($CGI->{mv_more_ip}) {
1076                         $search = $::Instance->{SearchObject}{$opt->{label}};
1077                         $search ||= $::Instance->{SearchObject}{''};
1078                         $search ||= perform_search();
1079                         $ary = [ splice(
1080                                                 @{$search->{mv_results}},
1081                                                 $search->{mv_first_match},
1082                                                 $search->{mv_matchlimit},
1083                                                 )] ;
1084 #::logDebug("search first_match=$search->{mv_first_match} length=$search->{mv_matchlimit}");
1085 #::logDebug("Found search=" . ::uneval($search));
1086                 }
1087                 elsif($q) {
1088                         my $db = dbref($table);
1089                         my $o = {
1090                                 ma              => $CGI->{ui_more_alpha},
1091                                 md              => $CGI->{ui_more_decade},
1092                                 ml              => $CGI->{ui_list_size},
1093                                 more    => 1,
1094                                 table   => $fi,
1095                                 query   => $q,
1096                         };
1097                         $ary = $db->query($o);
1098                 }
1099                 else {
1100 #::logDebug("In new search");
1101                         $params = escape_scan($ts->{sparams});
1102                         $c = { mv_search_immediate => 1, mv_search_label => $opt->{label} };
1103                         Vend::Scan::find_search_params($c, $params);
1104                         $search = Vend::Scan::perform_search($c);
1105                         $ary = $search->{mv_results};
1106                 }
1107
1108                 finish_search($search) if $search;
1109                 
1110                 $search ||= {};
1111
1112                 if($CGI->{ui_return_to} and ! $CGI->{ui_return_stack}) {
1113                         $edit_extra .= $Tag->return_to('formlink');     
1114                 }
1115                 else {
1116                         $edit_extra .= "ui_return_to=$cwp";
1117                 }
1118
1119                 my $edit_anchor;
1120                 my $ee_extra;
1121                 if($opt->{explicit_edit}) {
1122                         $edit_anchor = $opt->{explicit_edit_anchor} || errmsg('edit record');
1123                         $edit_anchor =~ s/ /&nbsp;/g;
1124                         $ee_extra = '';
1125                         for(qw/ class style width align valign /) {
1126                                 my $v = $opt->{"explicit_edit_$_"}
1127                                         or next;
1128                                 $ee_extra .= qq{ $_="$v"};
1129                         }
1130                         $ee_extra ||= ' width=30';
1131                 }
1132 #::logDebug("explicit_edit=$opt->{explicit_edit} no_code_link=$opt->{no_code_link}");
1133                 my $j = $search->{mv_first_match} || 0;
1134                 foreach my $line (@$ary) {
1135                         my $code = shift (@$line);
1136                         my $ecode = encode_entities($code);
1137                         my $rc = $j++ % 2
1138                                         ? $opt->{data_row_class_even}
1139                                         : $opt->{data_row_class_odd};
1140                         my $out = qq{<tr class="$rc">\n};
1141
1142                         my $code_pre; my $code_post;
1143                         my $ep_string = '';
1144                         if($opt->{no_code_link} and ! $opt->{explicit_edit}) {
1145                                 $code_pre = $code_post = '';
1146                         }
1147                         else {
1148                                 my @what;
1149                                 push @what, "$edit_parm=$code";
1150                                 if($ts->{multikey}) {
1151                                         unshift @what, 'ui_multi_key=1';
1152                                         for(@mcol) {
1153                                                 push @what, "$edit_parm=$line->[$_]";
1154                                         }
1155
1156                                 }
1157
1158                                 $ep_string = join "\n", @what, $edit_extra;
1159
1160                                 my $edit_url = $Tag->area({
1161                                                                         href => $edit_page,
1162                                                                         form => $ep_string,
1163                                                                 });
1164                                 my $msg = errmsg('edit %s', $ecode);
1165                                 $code_pre = qq{<a href="$edit_url" title="$msg">};
1166                                 $code_post = qq{</a>};
1167                         }
1168
1169                         unless($opt->{no_checkbox}) {
1170                                 $out .= <<EOF;
1171 <td width="$cb_width"><input type=checkbox name=$cb_name value="$ecode"></td>
1172 EOF
1173                         }
1174                         if($opt->{radio_box}) {
1175                                 $out .= <<EOF;
1176 <td width="$cb_width"><input type=radio name=$rb_name value="$ecode"></td>
1177 EOF
1178                         }
1179
1180                         if($opt->{number_list}) {
1181                                 $out .= qq{<td align=right>&nbsp;$j&nbsp;</td>};
1182                         }
1183
1184                         if($opt->{explicit_edit}) {
1185                                 my $form = $opt->{explicit_edit_form} || '';
1186                                 if($form) {
1187                                         $form .= $ecode;
1188                                 }
1189                                 my $url = $Tag->area({
1190                                                                         href => $opt->{explicit_edit_page} || $edit_page,
1191                                                                         form => $form || $ep_string,
1192                                                                 });
1193                                 my $msg = errmsg('process %s', $ecode);
1194                                 my $pre = qq{<a href="$url" title="$msg">};
1195                                 $out .= qq{<td$ee_extra>&nbsp;$pre$edit_anchor$code_post&nbsp;</td>};
1196                         }
1197
1198 #::logDebug("keyname=$ts->{keyname}");
1199                         $out .= "<td" . $data_cell_style->($ts->{keyname}) . ">";
1200                         $ecode = '';
1201                         if ($calcs[0]) {
1202                                 my %item;
1203                                 @item{@cols} = ($code, @$line);
1204                                 if(ref($calcs[0]) eq 'CODE') {
1205                                         $ecode = $calcs[0]->(\%item);
1206                                 }
1207                                 else {
1208                                         $Vend::Interpolate::item = \%item;
1209                                         $ecode = tag_calc($calcs[0]);
1210                                 }
1211                         }
1212                         if ($filter_show[0]) {
1213                                 $ecode = $code unless $ecode;
1214                                 $ecode = $Tag->filter($filter_show[0], $ecode, $cols[0]);
1215                                 $ecode =~ s/\[/&#91;/g;
1216                         }
1217                         $ecode = encode_entities($code) unless $ecode;
1218                         $out .= "$code_pre$ecode$code_post</td>";
1219                         my $i = 1;
1220                         for my $v (@$line) {
1221                                 my $extra = $style[$i];
1222                                 my $pre = '';
1223                                 my $post = '';
1224                                 my $lab;
1225
1226                                 if($link_page[$i]) {
1227                                         my $opt = { $link_parm[$i] => $v, form => 'auto' };
1228                                         if(my $p = $link_parm_extra[$i]) {
1229                                                 for(@$p) {
1230                                                         $opt->{$_} = $CGI->{$_};
1231                                                 }
1232                                         }
1233                                         $opt->{href} = $link_page[$i];
1234
1235                                         $lab = $link_anchor[$i];
1236                                         $lab =~ s/^\s+//;
1237                                         my $url = $Tag->area($opt);
1238                                         my $ev = encode_entities($v);
1239                                         $pre = qq{<a href="$url" title="$ev">};
1240                                         $post = '</a>';
1241                                 }
1242
1243                                 if($calcs[$i]) {
1244 #::logDebug("found a calc");
1245                                         my %item;
1246                                         @item{@cols} = ($code, @$line);
1247                                         if(ref($calcs[$i]) eq 'CODE') {
1248                                                 $lab = $calcs[$i]->(\%item);
1249                                         }
1250                                         else {
1251                                                 $Vend::Interpolate::item = \%item;
1252                                                 $lab = tag_calc($calcs[$i]);
1253                                         }
1254                                 }
1255
1256                                 $lab ||= $v;
1257
1258                                 $lab = $Tag->filter($filter_show[$i], $lab, $cols[$i]);
1259
1260                                 $lab =~ s/\[/&#91;/g;
1261                                 $out .= "<td$extra>$pre$lab$post</td>";
1262
1263                                 $i++;
1264                         }
1265                         $out .= "</tr>\n";
1266                         push @rows, $out;
1267                 }
1268
1269                 unless(@rows) {
1270                         my $nomsg = errmsg('No records');
1271                         push @rows, qq{<tr><td colspan=$ncols><blockquote>$nomsg.</blockquote></td></tr>};
1272                 }
1273                 else {
1274                         my $mmsg = errmsg($opt->{more_message} ||= 'More rows');
1275                         $opt->{more_list} ||= <<EOF;
1276 <tr>
1277 <td colspan={NCOLS} align=center>
1278 $mmsg: [decade-next][/decade-next] [more] [decade-prev][/decade-prev]
1279 </td>
1280 </tr>
1281 EOF
1282                         $opt->{more_list} =~ s/\{NCOLS\}/$ncols/g;
1283                         my $override = { mv_data_table => $table, ui_meta_view => $mview };
1284                         my @forms;
1285                         my @formparms = qw/ mv_data_table ui_meta_view ui_meta_specific /;
1286                         for(@formparms) {
1287                                 my $thing = $override->{$_} || $CGI->{$_};
1288                                 next unless length $thing;
1289                                 push @forms, "$_=$thing";
1290                         }
1291                         my $o = {
1292                                 object => $search,
1293                                 label => $opt->{label},
1294                                 form => join("\n", @forms),
1295                         };
1296                         $output{MORE_LIST} = tag_more_list(
1297                                                                                 $opt->{next_anchor},
1298                                                                                 $opt->{prev_anchor},
1299                                                                                 $opt->{page_anchor},
1300                                                                                 $opt->{more_border},
1301                                                                                 $opt->{more_border_selected},
1302                                                                                 $o,
1303                                                                                 $opt->{more_list},
1304                                                                         );
1305                 }
1306         }
1307
1308         $output{BOTTOM_OF_TABLE} = '</table>';
1309         $output{BOTTOM_OF_FORM} = '</form>';
1310         my $calc_sequence = <<'EOF';
1311 ui_sequence_edit=[calc]
1312         $CGI->{item_id_left} = $CGI->{item_id};
1313         $CGI->{item_id_left} =~ s/\0+/,/g;
1314         if($CGI->{item_id_left} =~ s/^(.*?),//) {
1315                 $CGI->{item_id} = $1;
1316                 return 1;
1317         }
1318         else {
1319                 delete $CGI->{item_id_left};
1320                 return '';
1321         }
1322 [/calc]
1323 EOF
1324         $calc_sequence .= "mv_nextpage=$edit_page\nmv_todo=return";
1325         my $ebutton = $Tag->button(     
1326                                                         {
1327                                                                 text => errmsg('Edit checked records in sequence'),
1328                                                                 extra => $opt->{edit_button_extra} || ' class=s2',
1329                                                         },
1330                                                         $calc_sequence,
1331                                                 );
1332         my $mbutton = '';
1333         my $dbutton = '';
1334         if($Tag->if_mm({ function => 'tables', table => "$table=d"}) ) {
1335                 $opt->{confirm} ||= "Are you sure you want to delete the checked records?";
1336                 my $dtext = qq{
1337 [flag type=write table=$table]
1338 deleterecords=1
1339 mv_click=db_maintenance};
1340                 $dbutton = '&nbsp;';
1341                 $dbutton .= $Tag->button(       
1342                                                         {
1343                                                                 text => errmsg('Delete checked records'),
1344                                                                 extra => $opt->{edit_button_extra} || ' class=s2',
1345                                                                 confirm => errmsg($opt->{confirm}),
1346                                                         },
1347                                                         $dtext,
1348                                                 );
1349                 
1350                 if($opt->{user_merge}) {
1351                         $opt->{confirm_merge} ||= "Are you sure you want to merge the checked users?";
1352                         $mbutton = '&nbsp;';
1353                         $mbutton .= $Tag->button(       
1354                                                                 {
1355                                                                         text => errmsg('Merge checked users'),
1356                                                                         extra => $opt->{merge_button_extra} || ' class=s2',
1357                                                                         confirm => errmsg($opt->{confirm_merge}),
1358                                                                 },
1359                                                                 '[user-merge]',
1360                                                         );
1361                                 
1362                 }
1363         }
1364         my $cboxes = '';
1365
1366         if($meta->{check_uncheck_all}) {
1367                 my $uc_msg = errmsg('Uncheck all');
1368                 my $ch_msg = errmsg('Check all');
1369                 $ch_msg =~ s/\s/&nbsp;/g;
1370                 $uc_msg =~ s/\s/&nbsp;/g;
1371                 $cboxes = <<EOF;
1372 <a href="javascript:checkAll(document.$opt->{form_name}, '$cb_name')">
1373 $ch_msg
1374 </a>&nbsp;&nbsp;
1375 <a href="javascript:checkAll(document.$opt->{form_name}, '$cb_name', 1)">
1376 $uc_msg
1377 </a>&nbsp;&nbsp;
1378 EOF
1379                 $cboxes =~ s/\n//g;
1380         }
1381
1382         if(! $opt->{no_checkbox} and ! $ts->{like_spec}) {
1383                 unless($opt->{no_top} || $opt->{bottom_buttons}) {
1384                         $output{TOP_BUTTONS} = $cboxes;
1385                         $output{TOP_BUTTONS} .= $ebutton;
1386                         if($mbutton) {
1387                                 $output{TOP_BUTTONS} .= '&nbsp;' x 4;
1388                                 $output{TOP_BUTTONS} .= $mbutton;
1389                         }
1390                         if($dbutton) {
1391                                 $output{TOP_BUTTONS} .= '&nbsp;' x 4;
1392                                 $output{TOP_BUTTONS} .= $dbutton;
1393                         }
1394                 }
1395
1396                 unless($opt->{no_bottom} || $opt->{top_buttons}) {
1397                         $output{BOTTOM_BUTTONS} = $cboxes;
1398                         $output{BOTTOM_BUTTONS} .= $ebutton;
1399                         if($mbutton) {
1400                                 $output{BOTTOM_BUTTONS} .= '&nbsp;' x 4;
1401                                 $output{BOTTOM_BUTTONS} .= $mbutton;
1402                         }
1403                         if($dbutton) {
1404                                 $output{BOTTOM_BUTTONS} .= '&nbsp;' x 4;
1405                                 $output{BOTTOM_BUTTONS} .= $dbutton;
1406                         }
1407                 }
1408         }
1409
1410         my %map = qw/
1411                         TOP_OF_FORM                     top_of_form
1412                         BOTTOM_OF_FORM          bottom_of_form
1413                         HIDDEN_FIELDS       hidden_fields
1414                         TOP_BUTTONS         top_buttons
1415                         BOTTOM_BUTTONS          bottom_buttons
1416                         EXTRA_BUTTONS           extra_buttons
1417                 /;
1418
1419         my @areas = qw/
1420                                         TOP_OF_TABLE
1421                                         TOP_OF_FORM
1422                                         HIDDEN_FIELDS
1423                                         TOP_BUTTONS 
1424                                         HEADER_AREA
1425                                         MAIN_BODY
1426                                         MORE_LIST
1427                                         BOTTOM_BUTTONS
1428                                         EXTRA_BUTTONS
1429                                         BOTTOM_OF_FORM
1430                                         BOTTOM_OF_TABLE
1431                                 /;
1432         if($ts->{like_spec}) {
1433                 push @rows, <<EOF;
1434         <tr>
1435         <td>&nbsp;</td>
1436         <td colspan="$ncols" align=left>
1437         [L]Check the box for exact record and enter the record id/key.[/L]
1438         [L]Or enter a query by example to select a set of records.[/L]
1439         [L]Each input will match on the <i>beginning</i> text in the field.[/L]
1440         <p>
1441         <small><input type=checkbox name=ui_exact_record value=1 class=s3> Edit exact record in key column</small>
1442         <br>
1443         &nbsp;
1444         </td>
1445         </tr>
1446         <tr>
1447         <td>&nbsp;</td>
1448         [loop list="[cgi ui_description_fields]"]
1449         <td>
1450                 <input type=hidden name=mv_like_field value="[loop-code]">
1451                 <input type=text name=mv_like_spec size=10>
1452         </td>
1453         [/loop]
1454         </tr>
1455         <tr>
1456         <td>&nbsp;</td>
1457         <td colspan="$ncols" align=left>
1458         &nbsp;
1459         <br>
1460         &nbsp;
1461         <br>
1462         <input type=submit value="[L]Find[/L]">
1463         </td>
1464         </tr>
1465 EOF
1466         }
1467
1468         $output{MAIN_BODY} = join "", @rows;
1469
1470         my @out;
1471         for(@areas) {
1472                 next unless $output{$_};
1473                 if($opt->{ui_style} and $map{$_}) {
1474                         my $op = $map{$_};
1475                         $Tag->output_to($op, { name => $op }, $output{$_} );
1476                 }
1477                 else {
1478                         push @out, $output{$_};
1479                 }
1480         }
1481         return join "", @out;
1482 }
1483 EOR