1 # Copyright 2002-2007 Interchange Development Group and others
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.
8 # $Id: flex_select.coretag,v 1.18 2009-05-01 16:02:50 mheins Exp $
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/;
30 sub flex_select_init {
31 my ($table, $opt) = @_;
36 #::logDebug("Entering flex_select init");
37 if($CGI->{mv_more_ip}) {
39 $CGI->{$_} = $::Values->{$_};
43 if($CGI->{mv_return_table}) {
44 my $rt = delete $CGI->{mv_return_table};
47 $CGI->{mv_data_table} = $rt if $rt;
51 $::Scratch->{ui_class} = $CGI->{ui_class}
52 if $CGI->{ui_class} && $CGI->{ui_class} =~ /^\w+$/;
54 if($opt->{sql_query}) {
57 ($table) = Vend::Scan::sql_statement($opt->{sql_query}, { table_only => 1});
62 "flex-select -- bad query %s: %s",
66 name => 'flex_select',
72 if($table =~ s/\.(txt|asc)$/_$1/) {
75 my $db = database_exists_ref($table);
77 $Tmp->{flex_select} ||= {};
78 my $ts = $Tmp->{flex_select}{$table} = {};
82 name => 'flex_select',
83 set => errmsg('no %s database', $table),
85 my $url = $Tag->area( {
86 href => $::Variable->{UI_ERROR_PAGE} || 'admin/error',
87 secure => $::Variable->{UI_SECURE},
89 #::logDebug("delivering error url=$url");
90 $Tag->deliver( { location => $url });
94 if( $::Variable->{UI_LARGE_TABLE} =~ /\b$table\b/ or $db->config('LARGE') ) {
98 if( $db->config('COMPOSITE_KEY') ) {
100 $ts->{key_columns} = $db->config('_Key_columns');
104 last DELETE unless $CGI->{item_id};
105 last DELETE unless delete $CGI->{deleterecords};
106 unless ($Tag->if_mm('tables', '=d')) {
108 name => 'flex_select',
109 set => errmsg("no permission to delete records"),
114 $Vend::Cfg->{NoSearch} = '';
116 my @ids = split /\0/, $CGI->{item_id};
118 if($db->delete_record($_)) {
119 push @warnings, errmsg("Deleted record %s", $_);
122 push @errors, $db->errstr();
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");
133 if($CGI->{item_id_left} =~ s/^(.*?)[\0]//) {
134 $CGI->{ui_sequence_edit} = 1;
135 $CGI->{item_id} = $1;
138 elsif ($CGI->{item_id_left}) {
139 $CGI->{item_id} = delete $CGI->{item_id_left};
140 delete $CGI->{ui_sequence_edit};
144 delete $CGI->{item_id};
145 delete $CGI->{ui_sequence_edit};
147 last SEQUENCE unless $doit;
148 my $url = $Tag->area( {
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}
157 #::logDebug("flex_select sequence developed URL=$url");
158 $Tag->deliver( { location => $url } );
162 $ts->{table_meta} = $Tag->meta_record($table, $CGI->{ui_meta_view}) || {};
163 my $tm = $ts->{table_meta};
167 $extra .= "<b>$tm->{name}</br>";
169 if($ts->{help_url}) {
170 $extra .= qq{ <small><a href="$ts->{help_url}">};
171 $extra .= errmsg('help');
172 $extra .= "</a></small>";
175 $extra .= "<blockquote>$ts->{help}</blockquote>";
177 $::Scratch->{page_banner} ||= $::Scratch->{page_title};
178 $::Scratch->{page_banner} .= $extra;
181 $Tag->error({ name => 'flex_select', set => $_ });
190 my ($table, $opt, $body) = @_;
192 #::logDebug("Entering flex_select");
193 my $CGI = \%CGI::values;
195 $table ||= $CGI->{mv_data_table};
197 ## Do the initialization
199 return flex_select_init($table, $opt);
203 if(ref($opt->{filter}) eq 'HASH') {
204 $filter = $opt->{filter};
211 if($opt->{sql_query}) {
212 $q = $opt->{sql_query};
213 if($CGI->{ui_sort_field} =~ s/^(\w+)(:[rfn]+)?$/$1/) {
215 my $opt = $2 || $CGI->{ui_sort_option};
216 $field .= ' DESC', $CGI->{ui_sort_option} = 'r' if $opt =~ /r/i;
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
224 $q =~ s/(\s+LIMIT\s+\d+(?:\s*,\s*\d+)?)/ ORDER BY $field$1/ix
225 or $q .= " ORDER BY $field";
229 ($spec) = Vend::Scan::sql_statement($q);
231 if($@ || ! $spec->{rt}) {
233 set => errmsg("flex-select -- bad query %s: %s", $q, $@),
234 name => 'flex_select',
238 $table = $spec->{rt}->[0];
241 my $ref = dbref($table)
243 my $msg = errmsg("%s: table '%s' does not exist", 'flex_select', $table);
245 $Tag->error({ name => 'flex_select', set => $msg });
248 my $ts = $Tmp->{flex_select}{$table} ||= {};
249 my $meta = $ts->{table_meta} ||= $Tag->meta_record($table, $CGI->{ui_meta_view});
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/) {
256 my $opt = $2 || $CGI->{ui_sort_option};
257 $field .= ' DESC', $CGI->{ui_sort_option} = 'r' if $opt =~ /r/i;
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
265 $q =~ s/(\s+LIMIT\s+\d+(?:\s*,\s*\d+)?)/ ORDER BY $field$1/ix
266 or $q .= " ORDER BY $field";
270 ($spec) = Vend::Scan::sql_statement($q);
272 if($@ or ! $spec->{rt}) {
274 set => errmsg("flex-select -- bad query %s: %s", $q, $@),
275 name => 'flex_select',
279 $table = $spec->{rt}->[0];
282 if( $table ne $ref->config('name')) {
283 ## Probably transient database
284 $CGI->{mv_data_table_real} = $table = $ref->config('name');
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
300 if(my $show = $CGI->{ui_show_fields} ||= $meta->{ui_show_fields} || $meta->{field}) {
302 if($show =~ s/[\r\n]+/\n/g) {
305 my @f = split /\n/, $show;
310 if(s/\s*\((.+)\)\s*$//) {
311 $filter_show[$i] = $1;
314 if(/^(\w+)-(\w+)$/) {
318 elsif(/^(\w+)(?:-([^=]+))?(?:=(.*))?/) {
320 $views[$i] = $2 if $2;
328 $show = join ",", @c;
331 $show =~ s/(\w+)(?:\((.*?)\))?/ ($filter_show[$i++] = $2), $1/eg;
332 $show =~ s/[\0,\s]+/,/g;
334 $CGI->{ui_description_fields} = $show;
339 #::logDebug("flex_select spec=$spec");
340 if($spec->{rf} and $spec->{rf}[0] ne '*') {
343 for(my $i = 0; $i < @{$spec->{rf}}; $i++) {
344 if($spec->{hf}[$i]) {
346 push @c, $spec->{rf}[$i] . '=' . $spec->{hf}[$i];
349 push @c, $spec->{rf}[$i];
353 $CGI->{ui_show_fields} = join "\n", @c;
356 $CGI->{ui_show_fields} = join " ", @c;
359 if($spec->{tf} and $spec->{tf}[0]) {
360 $CGI->{ui_sort_field} = join ",", @{$spec->{tf}};
361 $CGI->{ui_sort_option} = join ",", @{$spec->{to}};
363 $CGI->{ui_list_size} = $spec->{ml} if $spec->{ml};
368 if($CGI->{ui_flex_key}) {
369 $ts->{keypos} = $CGI->{ui_flex_key};
372 $ts->{keypos} = $ref->config('KEY_INDEX');
375 $ts->{keyname} = $ref->config('KEY');
376 $ts->{owner_field} = $ref->config('OWNER_FIELD') || $::Scratch->{ui_owner};
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};
383 my $url = $Tag->area({
384 href => 'admin/flex_editor',
386 mv_data_table=$CGI->{mv_data_table}
388 ui_meta_view=$CGI->{ui_meta_view}
392 $Tag->deliver({ location => $url });
393 #::logDebug("deliver=$url");
398 if($sf = $CGI->{ui_sort_field} and $sf =~ s/^(\w+)([,\s\0]+.*)?$/$1/) {
400 $fmeta = $Tag->meta_record("${table}::$sf", $CGI->{ui_meta_view})
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/
410 $CGI->{ui_sort_option} = $o;
415 for(qw/ui_more_alpha ui_more_decade ui_meta_specific/) {
416 $CGI->{$_} = $meta->{$_} unless defined $CGI->{$_};
418 $Vend::Cfg->{NoSearch} = '';
419 my $out_message = '';
420 my $ui_text_qualification = $CGI->{ui_text_qualification};
422 if ($ui_text_qualification and $CGI->{ui_text_qualification} =~ /[<!=>\^]/ ) {
423 if($ts->{owner_field}) {
424 $CGI->{ui_text_qualification} = <<EOF;
427 sf=$ts->{owner_field}
437 $CGI->{ui_text_qualification} = "co=1\n";
440 my @entries = split /\s+(and|or)\s+/i, $ui_text_qualification;
445 $CGI->{ui_text_qualification} .= "os=1\n";
450 $CGI->{ui_text_qualification} .= "os=0\n";
453 my ($f, $op, $s) = split /\s*([<=!>\^]+)\s*/, $_, 2;
454 $op = "eq" if $op eq "==";
455 $op = "rm" if $op eq "=";
458 $CGI->{ui_text_qualification} .= "bs=1\nsu=1\n";
461 $CGI->{ui_text_qualification} .= "bs=0\nsu=0\n";
464 $CGI->{ui_text_qualification} .= "se=$s\nsf=$f\nop=$op\n";
467 $CGI->{ui_text_qualification} .= "se=.\nsf=$f\nop=rn\n";
469 if($op =~ /[<>]/ and $s =~ /^[\d.]+$/) {
470 $CGI->{ui_text_qualification} .= "nu=1\n";
473 $CGI->{ui_text_qualification} .= "nu=0\n";
477 $CGI->{ui_text_qualification} .= $or ? "os=1\n" : "os=0\n";
480 $out_message = errmsg('Entries matching "%s"', $ui_text_qualification);
482 elsif ($ui_text_qualification) {
483 $CGI->{ui_text_qualification} = "se=$CGI->{ui_text_qualification}";
484 $out_message = errmsg('Entries matching "%s"', $ui_text_qualification);
485 if($ts->{owner_field}) {
486 $CGI->{ui_text_qualification} = <<EOF;
488 sf=$ts->{owner_field}
492 se=$CGI->{ui_text_qualification}
496 elsif ( $CGI->{mv_like_field} ) {
497 my @f = split /\0/, $CGI->{mv_like_field};
498 my @s = split /\0/, $CGI->{mv_like_spec};
501 for(my $i = 0; $i < @f; $i++) {
502 next unless length $s[$i];
504 push @q, "lf=$f[$i]";
505 push @q, "ls=$s[$i]";
508 $CGI->{ui_text_qualification} = join "\n", @q;
512 $thing =~ s/^ls=/mv_like_spec=/;
513 $thing =~ s/^lf=/mv_like_field=/;
516 $ts->{like_recall} = join "\n", @out;
518 else { $CGI->{ui_text_qualification} = "" }
520 elsif($ts->{owner_field}) {
521 $CGI->{ui_text_qualification} = <<EOF;
523 sf=$ts->{owner_field}
528 elsif ($ts->{large}) {
529 my $keylabel = $Tag->display({
532 column => $ts->{keyname},
535 $ts->{like_spec} = $CGI->{mv_more_ip} ? 0 : 1;
536 $CGI->{ui_text_qualification} = "";
539 $CGI->{ui_text_qualification} = "ra=yes";
542 if($meta->{ui_sort_combined} =~ /\S/) {
543 $meta->{ui_sort_field} = $meta->{ui_sort_combined};
544 $meta->{ui_sort_option} = '';
547 $CGI->{ui_sort_field} ||= $meta->{ui_sort_field}
550 $CGI->{ui_sort_option} ||= $meta->{ui_sort_option};
551 $CGI->{ui_sort_option} =~ s/[\0,\s]+//g;
552 $CGI->{ui_list_size} = $opt->{height} || $meta->{height}
553 if ! $CGI->{ui_list_size};
555 if(! $CGI->{ui_show_fields} ) {
556 $CGI->{ui_show_fields} =
557 $CGI->{ui_description_fields}
558 = join ",", $ref->columns();
562 my $show = $CGI->{ui_show_fields};
567 if($show =~ s/[\r\n]+/\n/g) {
570 my @f = split /\n/, $show;
575 if(s/\s*\((.+)\)\s*$//) {
576 $filter_show[$i] = $1;
579 if(/^(\w+)-(\w+)$/) {
583 elsif(/^(\w+)(?:-([^=]+))?(?:=(.*))?/) {
585 $views[$i] = $2 if $2;
593 $show = join ",", @c;
596 $show =~ s/(\w+)(?:\((.*?)\))?/ ($filter_show[$i++] = $2), $1/eg;
597 $show =~ s/[\0,\s]+/,/g;
599 $CGI->{ui_description_fields} = $show;
603 my @cols = split /,/, $CGI->{ui_description_fields};
605 @cols = grep $ref->column_exists($_), @cols
610 $CGI->{ui_limit_fields} =~ s/[\0,\s]+/ /g;
611 $CGI->{ui_limit_fields} =~ s/^\s+//;
612 $CGI->{ui_limit_fields} =~ s/\s+$//;
614 my (@limit_field) = split " ", $CGI->{ui_limit_fields};
617 @limit_field{@limit_field} = ();
618 @cols = grep ! exists($limit_field{$_}), @cols;
621 unshift(@cols, $ts->{keyname})
622 if $cols[0] ne $ts->{keyname};
624 $CGI->{ui_description_fields} = join ",", @cols;
626 unless ($CGI->{ui_sort_option}) {
627 $CGI->{ui_sort_option} = 'n'
628 if $ref->numeric($CGI->{ui_sort_field});
631 my $fi = $CGI->{mv_data_table_real} || $CGI->{mv_data_table};
632 $ts->{sparams} = ($ts->{like_spec} || $spec) ? '' : <<EOF;
636 $CGI->{ui_text_qualification}
638 ma=$CGI->{ui_more_alpha}
639 md=$CGI->{ui_more_decade}
640 ml=$CGI->{ui_list_size}
641 tf=$CGI->{ui_sort_field}
642 to=$CGI->{ui_sort_option}
643 rf=$CGI->{ui_description_fields}
647 $::Scratch->{page_banner} .= $out_message;
648 $::Scratch->{page_title} .= $out_message;
651 ### Header determination
653 my @refkeys = grep ref($opt->{$_}) eq 'HASH', keys %$opt;
656 data_cell_class => '',
657 data_cell_style => '',
658 data_row_class_even => 'rownorm',
659 data_row_class_odd => 'rowalt',
660 data_row_style_even => '',
661 data_row_style_odd => '',
662 form_method => 'GET',
664 explicit_edit_page => '',
665 explicit_edit_form => '',
666 explicit_edit_anchor => '',
668 group_image => 'smindex.gif',
669 group_class => 'rhead',
672 group_width => '100%',
673 header_link_class => 'rhead',
674 header_cell_class => 'rhead',
675 header_cell_style => '',
676 header_row_class => 'rhead',
677 header_row_style => '',
679 meta_image => errmsg('meta.png'),
680 label => "flex_select_$table",
684 check_uncheck_all => 0,
687 table_class => 'rseparator',
691 table_width => '100%',
695 next if defined $opt->{$_};
696 if(length $meta->{$_}) {
697 $opt->{$_} = $meta->{$_};
700 $opt->{$_} = $default{$_};
704 $opt->{ui_style} = 1 unless defined $opt->{ui_style};
705 $opt->{no_checkbox} = 1 if $ts->{multikey};
709 if($Tag->if_mm('super') and ! $opt->{no_meta}) {
710 $show_meta = defined $::Values->{ui_meta_force}
711 ? $::Values->{ui_meta_force}
712 : $::Variable->{UI_META_SELECT};
713 if($opt->{meta_image}) {
714 $meta_anchor = qq{<img src="$opt->{meta_image}" border=0>};
721 $opt->{form_name} ||= "fs_$table";
723 $output{TOP_OF_TABLE} = <<EOF;
724 <table width="$opt->{table_width}" border="$opt->{table_border}" cellpadding="$opt->{table_padding}" cellspacing="$opt->{table_spacing}" class="$opt->{table_class}">
727 my $cwp = $Global::Variable->{MV_PAGE};
728 $opt->{form_href} ||= $CGI->{ui_searchpage} || $cwp;
729 $opt->{form_extra} ||= '';
730 $opt->{form_extra} .= qq{ name="$opt->{form_name}"} if $opt->{form_name};
731 $opt->{form_extra} =~ s/^\s*/ /;
732 my $action = $Tag->process({href => $opt->{form_href}});
734 $output{TOP_OF_FORM} = <<EOF;
735 <form action="$action" method="$opt->{form_method}"$opt->{form_extra}>
736 <input type=hidden name=mv_data_table value="$table">
737 <input type=hidden name=mv_action value="$opt->{mv_action}">
738 <input type=hidden name=mv_click value="warn_me_main_form">
739 <input type=hidden name=mv_session_id value="$Vend::SessionID">
742 ### What the heck is going on here?
743 if($CGI->{ui_meta_view}) {
744 $output{TOP_OF_FORM} .= <<EOF;
745 <input type=hidden name=ui_meta_view value="$CGI->{ui_meta_view}">
747 $output{TOP_OF_FORM} .= $Tag->return_to();
750 $output{TOP_OF_FORM} .= <<EOF;
751 <!-- got no return-to -->
752 <input type=hidden name=ui_meta_specific value="$CGI->{ui_meta_specific}">
753 <input type=hidden name=ui_page_title value="$CGI->{ui_page_title}">
754 <input type=hidden name=ui_page_banner value="$CGI->{ui_page_banner}">
755 <input type=hidden name=ui_limit_fields value="$CGI->{ui_limit_fields}">
756 <input type=hidden name=ui_show_fields value="$CGI->{ui_show_fields}">
757 <input type=hidden name=ui_return_to value="$cwp">
758 <input type=hidden name=ui_return_to value="mv_data_table=$table">
762 my $cc = $ts->{column_meta} ||= {};
763 my $mview = $CGI->{ui_meta_view};
767 return $cc->{$col} if $cc->{$col};
768 my $m = $Tag->meta_record("${table}::$col", $mview);
770 $m->{$_} = $opt->{$_}{$col} if exists $opt->{$_}{$col};
776 my $header_cell_style = sub {
778 my $m = $cmeta->($col);
779 #::logDebug("meta for header=" . ::uneval($m));
781 for(qw/ class style align valign /) {
782 my $tag = "header_cell_$_";
784 if(ref $opt->{$tag}) {
785 $thing = $opt->{$tag}{$col} || $m->{$tag} || $opt->{"all_$tag"}
789 $thing = $m->{$tag} || $opt->{$tag}
792 encode_entities($thing);
793 $stuff .= qq{ $_="$thing"};
798 my $data_cell_style = sub {
800 my $m = $cmeta->($col);
802 for(qw/ class style align valign /) {
803 my $tag = "data_cell_$_";
805 if(ref $opt->{$tag}) {
806 $thing = $opt->{$tag}{$col} || $m->{$tag} || $opt->{"all_$tag"}
810 $thing = $m->{$tag} || $opt->{$tag}
813 encode_entities($thing);
814 $stuff .= qq{ $_="$thing"};
820 my $rc = $opt->{header_row_class};
822 push @head, qq( class=$opt->{header_row_class}) if $opt->{header_row_class};
823 push @head, qq( style=$opt->{header_row_style}) if $opt->{header_row_style};
825 if(! $opt->{no_checkbox}) {
826 push @head, " <td class=rhead> </td>"
828 if($opt->{radio_box}) {
829 push @head, " <td class=rhead> </td>"
831 if($opt->{number_list}) {
832 push @head, " <td class=rhead align=right># </td>" ;
834 if($opt->{explicit_edit}) {
835 push @head, " <td class=rhead> </td>"
840 ui_return_to=ui_meta_view=$opt->{ui_meta_view}
841 ui_return_to=mv_return_table=$table
842 mv_return_table=$table
843 ui_return_stack=$CGI->{ui_return_stack}
844 start_at=extended.ui_more_alpha
848 if($ts->{multikey}) {
849 for(@{$ts->{key_columns}}) {
857 foreach my $col (@cols) {
859 if($redirect[$idx]) {
860 $mcol .= "-$redirect[$idx]";
862 my $td_extra = $header_cell_style->($mcol);
864 ## $cc is set in header_cell_class
865 my $m = $cc->{$mcol};
868 push @mcol, $idx - 1;
873 <table align="left" class="$opt->{group_class}" cellspacing=$opt->{group_spacing} cellpadding=$opt->{group_padding} width="$opt->{group_width}">
876 unless($opt->{no_group} || $m->{fs_no_group}) {
878 href => 'admin/flex_group',
882 from_page=$Global::Variable->{MV_PAGE}
886 my $msg = errmsg('Select group by %s', $col);
889 <td align="right" valign="center" width=1>
890 <a href="$u" title="$msg"><img src="$opt->{group_image}" border=0></a>
899 if($o = $m->{ui_sort_option}) {
901 $msg = "sort by %s (%s)";
903 if($CGI->{ui_sort_field} eq $col) {
904 if($CGI->{ui_sort_option} =~ /r/) {
911 push @m, errmsg('reverse') if $o =~ /r/;
912 push @m, errmsg('case insensitive') if $o =~ /f/;
913 push @m, errmsg('numeric') if $o =~ /n/;
914 $rmsg = join ", ", @m;
917 if ($CGI->{ui_sort_field} eq $col and $CGI->{ui_sort_option} !~ /r/) {
919 $msg = "sort by %s (%s)";
920 $rmsg = errmsg('reverse');
925 $o .= 'n' if $ref->numeric($col);
927 my $sort_msg = errmsg($msg, $col, $rmsg);
928 my $url = $Tag->area( {
932 ui_text_qualification=$ui_text_qualification
937 ui_more_alpha=$m->{ui_more_alpha}
941 my $lab = $labels[$idx] || $m->{label} || $col;
943 # Set up some stuff for the data cells;
944 $style[$idx] = $data_cell_style->($mcol);
946 $filter_show[$idx] = $filter->{$mcol} if $filter->{$mcol};
947 $filter_show[$idx] ||= $m->{fs_display_filter} || 'encode_entities';
948 $filter_show[$idx] .= ' encode_entities'
949 unless $filter_show[$idx] =~ /\b(?:encode_)?entities\b/;
950 $style[$idx] .= " $1" while $filter_show[$idx] =~ s/(v?align=\w+)//i;
953 my ($page, $parm, $l) = split /:/, $views[$idx];
954 $m->{fs_link_page} = $page;
957 my @p = split /[\s,\0]+/, $parm;
959 $m->{fs_link_parm} = $arg;
960 $m->{fs_link_parm_extra} = join ",", @p;
961 $m->{fs_link_anchor} = $l;
964 if($m->{fs_link_page}) {
965 $link_page[$idx] = $m->{fs_link_page};
966 $link_parm[$idx] = $m->{fs_link_parm};
967 if($m->{fs_link_parm_extra}) {
968 my @p = grep /\S/, split /[\s,\0]+/, $m->{fs_link_parm_extra};
969 $link_parm_extra[$idx] = \@p;
971 $link_anchor[$idx] = $m->{fs_link_anchor};
974 if(my $prog = $m->{fs_data_calc}) {
975 #::logDebug("looking at calcs=$prog");
978 if($prog =~ /^\w+$/) {
979 $calcs[$idx] = $Vend::Cfg->{Sub}{$prog} || $Global::GlobalSub->{$prog};
982 $prog =~ s/^\[(calc|perl)(.*?)\]//;
983 $prog =~ s{\[/(calc|perl)\]$}{};
984 $calcs[$idx] = $prog;
986 if($m->{fs_data_tables}) {
987 tag_perl($m->{fs_data_tables}, {});
993 <a href="$url" class=$opt->{header_link_class} title="$sort_msg">$lab</a>
998 my $u = $Tag->area({ href=>'admin/meta_editor',
1000 item_id=${table}::$mcol
1005 "Edit header meta information for %s::%s",
1011 <a href="$u" title="$tit">$meta_anchor</a>
1025 push @head, "</tr>";
1030 $ncols++ if $opt->{explicit_edit};
1031 $ncols++ if $opt->{number_list};
1032 $ncols++ if $opt->{radio_box};
1033 $ncols++ unless $opt->{no_checkbox};
1035 $output{HEADER_AREA} = join "", @head;
1038 my $cb_width = $opt->{checkbox_width} || '30';
1039 my $cb_name = $opt->{checkbox_name} || 'item_id';
1040 my $rb_name = $opt->{radiobox_name} || 'item_radio';
1041 my $edit_page = $opt->{edit_page} || 'admin/flex_editor';
1042 my $edit_parm = $opt->{edit_parm} || 'item_id';
1043 my $edit_extra = <<EOF;
1044 mv_data_table=$table
1045 ui_page_title=$CGI->{ui_page_title}
1047 ui_page_banner=$CGI->{ui_page_banner}
1048 ui_meta_specific=$CGI->{ui_meta_specific}
1054 if($ts->{like_spec}) {
1057 elsif($body =~ /\S/) {
1059 label => $opt->{label},
1060 list_prefix => 'flex',
1063 search => $ts->{sparams},
1065 push @rows, tag_loop_list($o);
1072 #::logDebug("MM=$CGI->{MM}($CGI::values{MM}) mv_more_matches=$CGI->{mv_more_matches}($CGI::values{mv_more_matches})");
1073 if($CGI->{mv_more_ip}) {
1074 $search = $::Instance->{SearchObject}{$opt->{label}};
1075 $search ||= $::Instance->{SearchObject}{''};
1076 $search ||= perform_search();
1078 @{$search->{mv_results}},
1079 $search->{mv_first_match},
1080 $search->{mv_matchlimit},
1082 #::logDebug("search first_match=$search->{mv_first_match} length=$search->{mv_matchlimit}");
1083 #::logDebug("Found search=" . ::uneval($search));
1086 my $db = dbref($table);
1088 ma => $CGI->{ui_more_alpha},
1089 md => $CGI->{ui_more_decade},
1090 ml => $CGI->{ui_list_size},
1095 $ary = $db->query($o);
1098 #::logDebug("In new search");
1099 $params = escape_scan($ts->{sparams});
1100 $c = { mv_search_immediate => 1, mv_search_label => $opt->{label} };
1101 Vend::Scan::find_search_params($c, $params);
1102 $search = Vend::Scan::perform_search($c);
1103 $ary = $search->{mv_results};
1106 finish_search($search) if $search;
1110 if($CGI->{ui_return_to} and ! $CGI->{ui_return_stack}) {
1111 $edit_extra .= $Tag->return_to('formlink');
1114 $edit_extra .= "ui_return_to=$cwp";
1119 if($opt->{explicit_edit}) {
1120 $edit_anchor = $opt->{explicit_edit_anchor} || errmsg('edit record');
1121 $edit_anchor =~ s/ / /g;
1123 for(qw/ class style width align valign /) {
1124 my $v = $opt->{"explicit_edit_$_"}
1126 $ee_extra .= qq{ $_="$v"};
1128 $ee_extra ||= ' width=30';
1130 #::logDebug("explicit_edit=$opt->{explicit_edit} no_code_link=$opt->{no_code_link}");
1131 my $j = $search->{mv_first_match} || 0;
1132 foreach my $line (@$ary) {
1133 my $code = shift (@$line);
1134 my $ecode = encode_entities($code);
1136 ? $opt->{data_row_class_even}
1137 : $opt->{data_row_class_odd};
1138 my $out = qq{<tr class="$rc">\n};
1140 my $code_pre; my $code_post;
1142 if($opt->{no_code_link} and ! $opt->{explicit_edit}) {
1143 $code_pre = $code_post = '';
1147 push @what, "$edit_parm=$code";
1148 if($ts->{multikey}) {
1149 unshift @what, 'ui_multi_key=1';
1151 push @what, "$edit_parm=$line->[$_]";
1156 $ep_string = join "\n", @what, $edit_extra;
1158 my $edit_url = $Tag->area({
1162 my $msg = errmsg('edit %s', $ecode);
1163 $code_pre = qq{<a href="$edit_url" title="$msg">};
1164 $code_post = qq{</a>};
1167 unless($opt->{no_checkbox}) {
1169 <td width="$cb_width"><input type=checkbox name=$cb_name value="$ecode"></td>
1172 if($opt->{radio_box}) {
1174 <td width="$cb_width"><input type=radio name=$rb_name value="$ecode"></td>
1178 if($opt->{number_list}) {
1179 $out .= qq{<td align=right> $j </td>};
1182 if($opt->{explicit_edit}) {
1183 my $form = $opt->{explicit_edit_form} || '';
1187 my $url = $Tag->area({
1188 href => $opt->{explicit_edit_page} || $edit_page,
1189 form => $form || $ep_string,
1191 my $msg = errmsg('process %s', $ecode);
1192 my $pre = qq{<a href="$url" title="$msg">};
1193 $out .= qq{<td$ee_extra> $pre$edit_anchor$code_post </td>};
1196 #::logDebug("keyname=$ts->{keyname}");
1197 $out .= "<td" . $data_cell_style->($ts->{keyname}) . ">";
1201 @item{@cols} = ($code, @$line);
1202 if(ref($calcs[0]) eq 'CODE') {
1203 $ecode = $calcs[0]->(\%item);
1206 $Vend::Interpolate::item = \%item;
1207 $ecode = tag_calc($calcs[0]);
1210 if ($filter_show[0]) {
1211 $ecode = $code unless $ecode;
1212 $ecode = $Tag->filter($filter_show[0], $ecode, $cols[0]);
1213 $ecode =~ s/\[/[/g;
1215 $ecode = encode_entities($code) unless $ecode;
1216 $out .= "$code_pre$ecode$code_post</td>";
1218 for my $v (@$line) {
1219 my $extra = $style[$i];
1224 if($link_page[$i]) {
1225 my $opt = { $link_parm[$i] => $v, form => 'auto' };
1226 if(my $p = $link_parm_extra[$i]) {
1228 $opt->{$_} = $CGI->{$_};
1231 $opt->{href} = $link_page[$i];
1233 $lab = $link_anchor[$i];
1235 my $url = $Tag->area($opt);
1236 my $ev = encode_entities($v);
1237 $pre = qq{<a href="$url" title="$ev">};
1242 #::logDebug("found a calc");
1244 @item{@cols} = ($code, @$line);
1245 if(ref($calcs[$i]) eq 'CODE') {
1246 $lab = $calcs[$i]->(\%item);
1249 $Vend::Interpolate::item = \%item;
1250 $lab = tag_calc($calcs[$i]);
1256 $lab = $Tag->filter($filter_show[$i], $lab, $cols[$i]);
1258 $lab =~ s/\[/[/g;
1259 $out .= "<td$extra>$pre$lab$post</td>";
1268 my $nomsg = errmsg('No records');
1269 push @rows, qq{<tr><td colspan=$ncols><blockquote>$nomsg.</blockquote></td></tr>};
1272 my $mmsg = errmsg($opt->{more_message} ||= 'More rows');
1273 $opt->{more_list} ||= <<EOF;
1275 <td colspan={NCOLS} align=center>
1276 $mmsg: [decade-next][/decade-next] [more] [decade-prev][/decade-prev]
1280 $opt->{more_list} =~ s/\{NCOLS\}/$ncols/g;
1281 my $override = { mv_data_table => $table, ui_meta_view => $mview };
1283 my @formparms = qw/ mv_data_table ui_meta_view ui_meta_specific /;
1285 my $thing = $override->{$_} || $CGI->{$_};
1286 next unless length $thing;
1287 push @forms, "$_=$thing";
1291 label => $opt->{label},
1292 form => join("\n", @forms),
1294 $output{MORE_LIST} = tag_more_list(
1295 $opt->{next_anchor},
1296 $opt->{prev_anchor},
1297 $opt->{page_anchor},
1298 $opt->{more_border},
1299 $opt->{more_border_selected},
1306 $output{BOTTOM_OF_TABLE} = '</table>';
1307 $output{BOTTOM_OF_FORM} = '</form>';
1308 my $calc_sequence = <<'EOF';
1309 ui_sequence_edit=[calc]
1310 $CGI->{item_id_left} = $CGI->{item_id};
1311 $CGI->{item_id_left} =~ s/\0+/,/g;
1312 if($CGI->{item_id_left} =~ s/^(.*?),//) {
1313 $CGI->{item_id} = $1;
1317 delete $CGI->{item_id_left};
1322 $calc_sequence .= "mv_nextpage=$edit_page\nmv_todo=return";
1323 my $ebutton = $Tag->button(
1325 text => errmsg('Edit checked records in sequence'),
1326 extra => $opt->{edit_button_extra} || ' class=s2',
1332 if($Tag->if_mm({ function => 'tables', table => "$table=d"}) ) {
1333 $opt->{confirm} ||= "Are you sure you want to delete the checked records?";
1335 [flag type=write table=$table]
1337 mv_click=db_maintenance};
1338 $dbutton = ' ';
1339 $dbutton .= $Tag->button(
1341 text => errmsg('Delete checked records'),
1342 extra => $opt->{edit_button_extra} || ' class=s2',
1343 confirm => errmsg($opt->{confirm}),
1348 if($opt->{user_merge}) {
1349 $opt->{confirm_merge} ||= "Are you sure you want to merge the checked users?";
1350 $mbutton = ' ';
1351 $mbutton .= $Tag->button(
1353 text => errmsg('Merge checked users'),
1354 extra => $opt->{merge_button_extra} || ' class=s2',
1355 confirm => errmsg($opt->{confirm_merge}),
1364 if($meta->{check_uncheck_all}) {
1365 my $uc_msg = errmsg('Uncheck all');
1366 my $ch_msg = errmsg('Check all');
1367 $ch_msg =~ s/\s/ /g;
1368 $uc_msg =~ s/\s/ /g;
1370 <a href="javascript:checkAll(document.$opt->{form_name}, '$cb_name')">
1373 <a href="javascript:checkAll(document.$opt->{form_name}, '$cb_name', 1)">
1380 if(! $opt->{no_checkbox} and ! $ts->{like_spec}) {
1381 unless($opt->{no_top} || $opt->{bottom_buttons}) {
1382 $output{TOP_BUTTONS} = $cboxes;
1383 $output{TOP_BUTTONS} .= $ebutton;
1385 $output{TOP_BUTTONS} .= ' ' x 4;
1386 $output{TOP_BUTTONS} .= $mbutton;
1389 $output{TOP_BUTTONS} .= ' ' x 4;
1390 $output{TOP_BUTTONS} .= $dbutton;
1394 unless($opt->{no_bottom} || $opt->{top_buttons}) {
1395 $output{BOTTOM_BUTTONS} = $cboxes;
1396 $output{BOTTOM_BUTTONS} .= $ebutton;
1398 $output{BOTTOM_BUTTONS} .= ' ' x 4;
1399 $output{BOTTOM_BUTTONS} .= $mbutton;
1402 $output{BOTTOM_BUTTONS} .= ' ' x 4;
1403 $output{BOTTOM_BUTTONS} .= $dbutton;
1409 TOP_OF_FORM top_of_form
1410 BOTTOM_OF_FORM bottom_of_form
1411 HIDDEN_FIELDS hidden_fields
1412 TOP_BUTTONS top_buttons
1413 BOTTOM_BUTTONS bottom_buttons
1414 EXTRA_BUTTONS extra_buttons
1430 if($ts->{like_spec}) {
1434 <td colspan="$ncols" align=left>
1435 [L]Check the box for exact record and enter the record id/key.[/L]
1436 [L]Or enter a query by example to select a set of records.[/L]
1437 [L]Each input will match on the <i>beginning</i> text in the field.[/L]
1439 <small><input type=checkbox name=ui_exact_record value=1 class=s3> Edit exact record in key column</small>
1446 [loop list="[cgi ui_description_fields]"]
1448 <input type=hidden name=mv_like_field value="[loop-code]">
1449 <input type=text name=mv_like_spec size=10>
1455 <td colspan="$ncols" align=left>
1460 <input type=submit value="[L]Find[/L]">
1466 $output{MAIN_BODY} = join "", @rows;
1470 next unless $output{$_};
1471 if($opt->{ui_style} and $map{$_}) {
1473 $Tag->output_to($op, { name => $op }, $output{$_} );
1476 push @out, $output{$_};
1479 return join "", @out;