root/branches/release-35/lib/MT/CMS/Search.pm @ 1960

Revision 1960, 26.7 kB (checked in by bchoate, 20 months ago)

Fixed list preferences for member listing screen. BugId:69212

  • Property svn:keywords set to Id Revision
Line 
1package MT::CMS::Search;
2
3use strict;
4
5sub core_search_apis {
6    my $app = shift;
7    my $q       = $app->param;
8    my $blog_id = $q->param('blog_id');
9    my $author  = $app->user;
10    my @perms;
11    if ( !$blog_id ) {
12        if ( !$author->is_superuser() ) {
13            require MT::Permission;
14            @perms = MT::Permission->load( { author_id => $author->id } );
15        }
16    }
17    else {
18        @perms = ( $app->permissions )
19          or return $app->error( $app->translate("No permissions") );
20    }
21    my $types = {
22        'entry' => {
23            'order' => 100,
24            'permission' => 'create_post,publish_post,edit_all_posts',
25            'handler' => '$Core::MT::CMS::Entry::build_entry_table',
26            'label' => 'Entries',
27            'perm_check' => sub {
28                grep { $_->can_edit_entry( $_[0], $author ) } @perms;
29            },
30            'search_cols' => {
31                'title' => sub { $app->translate('Title') },
32                'text' => sub { $app->translate('Entry Body') },
33                'text_more' => sub { $app->translate('Extended Entry') },
34                'keywords' => sub { $app->translate('Keywords') },
35                'excerpt' => sub { $app->translate('Excerpt') },
36                'basename' => sub { $app->translate('Basename') },
37            },
38            'replace_cols'       => [qw(title text text_more keywords excerpt)],
39            'can_replace'        => 1,
40            'can_search_by_date' => 1,
41            'date_column'        => 'authored_on',
42        },
43        'comment' => {
44            'order' => 200,
45            'permission' => 'publish_post,create_post,edit_all_posts,manage_feedback',
46            'handler' => '$Core::MT::CMS::Comment::build_comment_table',
47            'label' => 'Comments',
48            'perm_check' => sub {
49                require MT::Entry;
50                my $entry = MT::Entry->load( $_[0]->entry_id );
51                grep { $_->can_edit_entry( $entry, $author ) } @perms;
52            },
53            'search_cols' => {
54                'url' => sub { $app->translate('URL') },
55                'text' => sub { $app->translate('Comment Text') },
56                'email' => sub { $app->translate('Email Address') },
57                'ip' => sub { $app->translate('IP Address') },
58                'author' => sub { $app->translate('Name') },
59            },
60            'replace_cols'       => [qw(text)],
61            'can_replace'        => 1,
62            'can_search_by_date' => 1,
63        },
64        'ping' => {
65            'order' => 300,
66            'permission' => 'create_post,publish_post,edit_all_posts,manage_feedback',
67            'label' => 'TrackBacks',
68            'handler' => '$Core::MT::CMS::TrackBack::build_ping_table',
69            'perm_check' => sub {
70                my $ping = shift;
71                my $tb   = MT::Trackback->load( $ping->tb_id )
72                    or return undef;
73                if ( $tb->entry_id ) {
74                    require MT::Entry;
75                    my $entry = MT::Entry->load( $tb->entry_id );
76                    return
77                      grep { $_->can_edit_entry( $entry, $author ) } @perms;
78                }
79                elsif ( $tb->category_id ) {
80                    return grep { $_->can_edit_categories } @perms;
81                }
82            },
83            'search_cols' => {
84                'title' => sub { $app->translate('Title') },
85                'excerpt' => sub { $app->translate('Excerpt') },
86                'source_url' => sub { $app->translate('Source URL') },
87                'ip' => sub { $app->translate('IP Address') },
88                'blog_name' => sub { $app->translate('Blog Name') },
89            },
90            'replace_cols'       => [qw(title excerpt)],
91            'can_replace'        => 1,
92            'can_search_by_date' => 1,
93        },
94        'page' => {
95            'order' => 400,
96            'permission' => 'manage_pages',
97            'label' => 'Pages',
98            'handler' => '$Core::MT::CMS::Entry::build_entry_table',
99            'perm_check' => sub {
100                grep { $_->can_manage_pages( $_[0], $author ) } @perms;
101            },
102            'search_cols' => {
103                'title' => sub { $app->translate('Title') },
104                'text' => sub { $app->translate('Page Body') },
105                'text_more' => sub { $app->translate('Extended Page') },
106                'keywords' => sub { $app->translate('Keywords') },
107                'excerpt' => sub { $app->translate('Excerpt') },
108                'basename' => sub { $app->translate('Basename') },
109            },
110            'replace_cols'       => [qw(title text text_more keywords excerpt)],
111            'can_replace'        => 1,
112            'can_search_by_date' => 1,
113            'date_column'        => 'authored_on',
114            'results_table_template' => '<mt:include name="include/entry_table.tmpl">',
115        },
116        'template' => {
117            'order'         => 500,
118            'permission'    => 'edit_templates',
119            'handler' => '$Core::MT::CMS::Template::build_template_table',
120            'label'         => 'Templates',
121            'perm_check' => sub {
122                my ($obj) = @_;
123
124                # are there any perms that match this object and
125                # allow template editing?
126                my @check = grep {
127                         $_->blog_id == $obj->blog_id
128                      && $_->can_edit_templates
129                } @perms;
130                return @check;
131
132            },
133            'search_cols' => {
134                'name' => sub { $app->translate('Template Name') },
135                'text' => sub { $app->translate('Text') },
136                'linked_file' => sub { $app->translate('Linked Filename') },
137                'outfile' => sub { $app->translate('Output Filename') },
138            },
139            'replace_cols'       => [qw(name text linked_file outfile)],
140            'can_replace'        => 1,
141            'can_search_by_date' => 0,
142        },
143        'asset' => {
144            'order' => 600,
145            'permission' => 'manage_assets',
146            'label' => 'Assets',
147            'handler' => '$Core::MT::CMS::Asset::build_asset_table',
148            'perm_check' => sub {
149                1;
150            },
151            'search_cols' => {
152                'file_name' => sub { $app->translate('Filename') },
153                'description' => sub { $app->translate('Description') },
154                'label' => sub { $app->translate('Label') },
155            },
156            'replace_cols'       => [],
157            'can_replace'        => 0,
158            'can_search_by_date' => 1,
159            'setup_terms_args'   => sub {
160                my ($terms, $args, $blog_id) = @_;
161                $terms->{class} = '*';
162                $terms->{blog_id} = $blog_id if $blog_id;
163            }
164        },
165        'log' => {
166            'order' => 700,
167            'permission'        => "view_blog_log",
168            'system_permission' => "view_log",
169            'handler' => '$Core::MT::CMS::Log::build_log_table',
170            'label' => 'Activity Log',
171            'perm_check' => sub {
172                my ($obj) = @_;
173                return 1 if $author->can_view_log;
174                my $perm = $author->permissions( $obj->blog_id );
175                return $perm->can_view_blog_log;
176            },
177            'search_cols' => {
178                'ip' => sub { $app->translate('Log Message') },
179                'message' => sub { $app->translate('IP Address') },
180            },
181            'can_replace'        => 0,
182            'can_search_by_date' => 1,
183            'setup_terms_args'   => sub {
184                my ($terms, $args, $blog_id) = @_;
185                $terms->{class} = '*';
186                $terms->{blog_id} = $blog_id if $blog_id;
187            }
188        },
189        'author' => {
190            'order' => 800,
191            'system_permission' => 'administer',
192            'label' => 'Users',
193            'handler' => '$Core::MT::CMS::User::build_author_table',
194            'perm_check' => sub {
195                return 1 if $author->is_superuser;
196                if ($blog_id) {
197                    my $perm = $author->permissions($blog_id);
198                    return $perm->can_administer_blog;
199                }
200                return 0;
201            },
202            'search_cols' => {
203                'name'     => sub { $app->translate('Username') },
204                'nickname' => sub { $app->translate('Display Name') },
205                'email'    => sub { $app->translate('Email Address') },
206                'url'      => sub { $app->translate('URL') },
207            },
208            'can_replace'        => 0,
209            'can_search_by_date' => 0,
210            'setup_terms_args'   => sub {
211                my ($terms, $args, $blog_id) = @_;
212                if ($blog_id) {
213                    $args->{'join'} =
214                      MT::Permission->join_on( 'author_id',
215                        { blog_id => $blog_id } );
216                }
217                else {
218                    $terms->{'type'} = MT::Author::AUTHOR();
219                }
220            },
221            'results_table_template' => '
222<mt:if name="blog_id">
223    <mt:include name="include/member_table.tmpl">
224<mt:else>
225    <mt:include name="include/author_table.tmpl">
226</mt:if>',
227        },
228        'blog' => {
229            'order' => 900,
230            'system_permission' => 'administer',
231            'label' => 'Blogs',
232            'handler' => '$Core::MT::CMS::Blog::build_blog_table',
233            'perm_check' => sub {
234                return 1 if $author->is_superuser;
235                my ($obj) = @_;
236                my $perm = $author->permissions( $obj->id );
237                $perm
238                  && ( $perm->can_administer_blog || $perm->can_edit_config );
239            },
240            'search_cols' => {
241                'name' => sub { $app->translate('Name') },
242                'site_url' => sub { $app->translate('Site URL') },
243                'site_path' => sub { $app->translate('Site Root') },
244                'description' => sub { $app->translate('Description') },
245            },
246            'replace_cols'       => [qw(name site_url site_path description)],
247            'can_replace'        => $author->is_superuser(),
248            'can_search_by_date' => 0,
249            'view'               => 'system',
250            'setup_terms_args'   => sub {
251                my ($terms, $args, $blog_id) = @_;
252                $args->{sort}      = 'name';
253                $args->{direction} = 'ascend';
254            }
255        }
256    };
257    return $types;
258}
259
260sub search_replace {
261    my $app = shift;
262    my $param = do_search_replace($app, @_) or return;
263    my $blog_id = $app->param('blog_id');
264    $app->add_breadcrumb( $app->translate('Search & Replace') );
265    $param->{nav_search}   = 1;
266    $param->{screen_class} = "search-replace";
267    $param->{screen_id}    = "search-replace";
268    $param->{search_tabs}  = $app->search_apis($blog_id ? 'blog' : 'system');
269    $param->{entry_type}  = $app->param('entry_type');
270    my $tmpl = $app->load_tmpl( 'search_replace.tmpl', $param );
271    my $placeholder = $tmpl->getElementById('search_results');
272    $placeholder->innerHTML(delete $param->{results_template});
273    return $tmpl;
274}
275
276sub do_search_replace {
277    my $app     = shift;
278    my $q       = $app->param;
279    my $blog_id = $q->param('blog_id');
280    my $author  = $app->user;
281
282    my $search_api = $app->registry("search_apis");
283
284    my (
285        $search,        $replace,     $do_replace,    $case,
286        $is_regex,      $is_limited,  $type,          $is_junk,
287        $is_dateranged, $ids,         $datefrom_year, $datefrom_month,
288        $datefrom_day,  $dateto_year, $dateto_month,  $dateto_day,
289        $from,          $to,          $show_all,      $do_search,
290        $orig_search,   $quicksearch
291      )
292      = map scalar $q->param($_),
293      qw( search replace do_replace case is_regex is_limited _type is_junk is_dateranged replace_ids datefrom_year datefrom_month datefrom_day dateto_year dateto_month dateto_day from to show_all do_search orig_search quicksearch );
294
295    if ( !$type || ( 'category' eq $type ) || ( 'folder' eq $type ) ) {
296        $type = 'entry';
297    }
298    if ( ( 'user' eq $type ) ) {
299        $type = 'author';
300    }
301
302    foreach my $obj_type (qw( role association )) {
303        if ( $type eq $obj_type ) {
304            $type = 'author';
305        }
306    }
307
308    $replace && ( $app->validate_magic() or return );
309    $search = $orig_search if $do_replace;    # for safety's sake
310    my $list_pref = $app->list_pref($type);
311
312    $app->assert( $search_api->{$type}, "Invalid request." ) or return;
313
314    # force action bars to top and bottom
315    $list_pref->{"bar"}                     = 'both';
316    $list_pref->{"position_actions_both"}   = 1;
317    $list_pref->{"position_actions_top"}    = 1;
318    $list_pref->{"position_actions_bottom"} = 1;
319    $list_pref->{"view"}                    = 'compact';
320    $list_pref->{"view_compact"}            = 1;
321    my ( @cols, $datefrom, $dateto, $date_col );
322    $do_replace    = 0 unless $search_api->{$type}{can_replace};
323    $is_dateranged = 0 unless $search_api->{$type}{can_search_by_date};
324    my @ids;
325
326    if ($ids) {
327        @ids = split /,/, $ids;
328    }
329    if ($is_limited) {
330        @cols = $q->param('search_cols');
331        my %search_api_cols =
332          map { $_ => 1 } keys %{ $search_api->{$type}{search_cols} };
333        if ( @cols && ( $cols[0] =~ /,/ ) ) {
334            @cols = split /,/, $cols[0];
335        }
336        @cols = grep { $search_api_cols{$_} } @cols;
337    }
338    else {
339        @cols = keys %{ $search_api->{$type}->{search_cols} };
340    }
341    my $quicksearch_id;
342    if ($quicksearch && ($search || '') ne '' && $search !~ m{ \D }xms) {
343        $quicksearch_id = $search;
344        unshift @cols, 'id';
345    }
346    foreach (
347        $datefrom_year, $datefrom_month, $datefrom_day,
348        $dateto_year,   $dateto_month,   $dateto_day
349      )
350    {
351        s!\D!!g if $_;
352    }
353    if ($is_dateranged) {
354        $datefrom = sprintf( "%04d%02d%02d",
355            $datefrom_year, $datefrom_month, $datefrom_day );
356        $dateto =
357          sprintf( "%04d%02d%02d", $dateto_year, $dateto_month, $dateto_day );
358        if ( ( $datefrom eq '00000000' ) && ( $dateto eq '00000000' ) ) {
359            $is_dateranged = 0;
360        }
361        else {
362            if (   !is_valid_date( $datefrom . '000000' )
363                || !is_valid_date( $dateto . '000000' ) )
364            {
365                return $app->error(
366                    $app->translate(
367                        "Invalid date(s) specified for date range.")
368                );
369            }
370        }
371    }
372    elsif ( $from && $to ) {
373        $is_dateranged = 1;
374        s!\D!!g foreach ( $from, $to );
375        $datefrom = substr( $from, 0, 8 );
376        $dateto   = substr( $to,   0, 8 );
377    }
378    my $tab = $q->param('tab') || 'entry';
379    ## Sometimes we need to pass in the search columns like 'title,text', so
380    ## we look for a comma (not a valid character in a column name) and split
381    ## on it if it's there.
382    if ( ($search || '') ne '' ) {
383        my $enc = $app->charset;
384        $search = MT::I18N::encode_text( $search, 'utf-8', $enc )
385          if ( $enc !~ m/utf-?8/i )
386          && ( 'dialog_grant_role' eq $app->param('__mode') );
387        $search = quotemeta($search) unless $is_regex;
388        $search = '(?i)' . $search   unless $case;
389    }
390    my ( @to_save, @data );
391    my $api   = $search_api->{$type};
392    my $class = $app->model($api->{object_type} || $type);
393    my %param = %$list_pref;
394    my $limit = $q->param('limit') || 125;    # FIXME: mt.cfg setting?
395    my $matches;
396    $date_col = $api->{date_column} || 'created_on';
397    if ( ( $do_search && $search ne '' ) || $show_all || $do_replace ) {
398        my %terms;
399        my %args;
400        ## we need to search all user/group for 'grant permissions',
401        ## if $blog_id is specified. it affects the setup_terms_args.
402        if ( $app->param('__mode') eq 'dialog_grant_role' ) {
403            $blog_id = 0;
404        }
405        if (exists $api->{setup_terms_args}) {
406            my $code = $app->handler_to_coderef($api->{setup_terms_args});
407            $code->(\%terms, \%args, $blog_id);
408        }
409        else {
410            %terms = $blog_id ? ( blog_id => $blog_id ) : ();
411            if ( $type ne 'template' ) {
412                %args = ( 'sort' => $date_col, direction => 'descend' );
413            }
414        }
415        if ( $class->has_column('junk_status') ) {
416            require MT::Comment;
417            if ($is_junk) {
418                $terms{junk_status} = MT::Comment::JUNK();
419            }
420            else {
421                $terms{junk_status} = MT::Comment::NOT_JUNK();
422            }
423        }
424        if ($is_dateranged) {
425            $args{range_incl}{$date_col} = 1;
426            if ( $datefrom gt $dateto ) {
427                $terms{$date_col} =
428                  [ $dateto . '000000', $datefrom . '235959' ];
429            }
430            else {
431                $terms{$date_col} =
432                  [ $datefrom . '000000', $dateto . '235959' ];
433            }
434        }
435        my $iter;
436        if ($do_replace) {
437            $iter = sub {
438                if ( my $id = pop @ids ) {
439                    $class->load($id);
440                }
441            };
442        }
443        if ( $blog_id || ($type eq 'blog') ) {
444            $iter = $class->load_iter( \%terms, \%args ) or die $class->errstr;
445        }
446        else {
447
448            my @streams;
449            if ( $author->is_superuser ) {
450                @streams = ( { iter => $class->load_iter( \%terms, \%args ) } );
451            } 
452            else {
453                # Get an iter for each accessible blog
454                my @perms = $app->model('permission')->load(
455                    { blog_id => '0', author_id => $author->id },
456                    { not => { blog_id => 1 } },
457                );
458                if (@perms) {
459                    @streams = map {
460                        {
461                            iter => $class->load_iter(
462                                {
463                                    blog_id => $_->blog_id,
464                                    %terms
465                                },
466                                \%args
467                            )
468                        }
469                    } @perms;
470                }
471            }
472
473            # Pull out the head of each iterator
474            # Next: effectively mergesort the various iterators
475            # To call the iterator n times takes time in O(bn)
476            #   with 'b' the number of blogs
477            # we expect to hit the iterator l/p times where 'p' is the
478            #   prob. of the search term appearing and 'l' is $limit
479            $_->{head} = $_->{iter}->() foreach @streams;
480            if ( $type ne 'template' ) {
481                $iter = sub {
482
483                    # find the head with greatest created_on
484                    my $which = \$streams[0];
485                    foreach my $iter (@streams) {
486                        next
487                          if !exists $iter->{head}
488                          || !$which
489                          || !${$which}->{head}
490                          || !defined( $iter->{head} );
491                        if ( $iter->{head}->created_on >
492                            ${$which}->{head}->created_on )
493                        {
494                            $which = \$iter;
495                        }
496                    }
497
498                    # Advance the chosen one
499                    my $result = ${$which}->{head};
500                    ${$which}->{head} = ${$which}->{iter}->() if $result;
501                    $result;
502                };
503            }
504            else {
505                $iter = sub {
506                    return undef unless @streams;
507
508                    # find the head with greatest created_on
509                    my $which = \$streams[0];
510                    while ( @streams && ( !defined ${$which}->{head} ) ) {
511                        shift @streams;
512                        last unless @streams;
513                        $which = \$streams[0];
514                    }
515                    my $result = ${$which}->{head};
516                    ${$which}->{head} = ${$which}->{iter}->() if $result;
517                    $result;
518                };
519            }
520        }
521        my $i = 1;
522        my %replace_cols;
523        if ($do_replace) {
524            %replace_cols = map { $_ => 1 } @{ $api->{replace_cols} };
525        }
526
527        my $re;
528        if (($search || '') ne '') {
529            $re = eval { qr/$search/ };
530            if ( my $err = $@ ) {
531                return $app->error(
532                    $app->translate( "Error in search expression: [_1]", $@ ) );
533            }
534        }
535        while ( my $obj = $iter->() ) {
536            next unless $author->is_superuser || $api->{perm_check}->($obj);
537            my $match = 0;
538            unless ($show_all) {
539                for my $col (@cols) {
540                    next if $do_replace && !$replace_cols{$col};
541                    my $text = $obj->column($col);
542                    $text = '' unless defined $text;
543                    if ($do_replace) {
544                        if ( $text =~ s!$re!$replace!g ) {
545                            $match++;
546                            $obj->$col($text);
547                        }
548                    }
549                    else {
550                        $match = $search ne '' ? $text =~ m!$re! : 1;
551                        last if $match;
552                    }
553                }
554            }
555            if ( $match || $show_all ) {
556                push @to_save, $obj if $do_replace && !$show_all;
557                push @data, $obj;
558            }
559            last if ( $limit ne 'all' ) && @data > $limit;
560        }
561        if (@data) {
562            $param{have_results} = 1;
563
564            # We got one extra to see if there were more
565            if ( ( $limit ne 'all' ) && @data > $limit ) {
566                $param{have_more} = 1;
567                pop @data;
568            }
569            $matches = @data;
570        }
571        else {
572            $matches = 0;
573        }
574    }
575    my $replace_count = 0;
576    for my $obj (@to_save) {
577        $replace_count++;
578        $obj->save
579          or return $app->error(
580            $app->translate( "Saving object failed: [_2]", $obj->errstr ) );
581    }
582    if (@data) {
583        if ($quicksearch) {
584            my $obj;
585            if (1 == scalar @data) {
586                ($obj) = @data;
587            }
588            elsif (defined $quicksearch_id) {
589                ($obj) = grep { $_->id == $quicksearch_id } @data;
590            }
591
592            if ($obj) {
593                my %args = (
594                    _type         => $type,
595                    id            => $obj->id,
596                    search_result => 1,
597                );
598                $args{blog_id} = $obj->blog_id
599                    if $obj->has_column('blog_id');
600                my $mode = 'view';
601                if ($type eq 'blog') {
602                    $args{blog_id} = delete $args{id};
603                    $mode = 'cfg_prefs';
604                }
605                return $app->redirect($app->uri(
606                    mode => $mode,
607                    args => \%args,
608                ));
609            }
610        }
611
612        if (my $meth = $search_api->{$type}{handler}) {
613            $meth = $app->handler_to_coderef($meth);
614            $meth->($app, items => \@data, param => \%param, type => $type );
615        } else {
616            my $meth = 'build_' . $type . '_table';
617            if ( $app->can($meth) ) {
618                $app->$meth( items => \@data, param => \%param, type => $type );
619            }
620            else {
621                my @objects;
622                push @objects, { object => $_ } for @data;
623                $param{object_loop} = \@objects;
624            }
625        }
626        $param{object_type} = $type;
627        if ( exists $api->{results_table_template} ) {
628            $param{results_template} = $api->{results_table_template};
629        }
630        else {
631            $param{results_template} = _default_results_table_template($app, $type, 1, $class->class_label_plural);
632        }
633    }
634    else {
635        if ( exists $api->{no_results_template} ) {
636            $param{results_template} = $api->{no_results_template};
637        }
638        else {
639            $param{results_template} = _default_results_table_template($app, $type, 0, $class->class_label_plural);
640        }
641    }
642    if ($is_dateranged) {
643        ( $datefrom_year, $datefrom_month, $datefrom_day ) =
644          $datefrom =~ m/^(\d\d\d\d)(\d\d)(\d\d)/;
645        ( $dateto_year, $dateto_month, $dateto_day ) =
646          $dateto =~ m/^(\d\d\d\d)(\d\d)(\d\d)/;
647    }
648    my %res = (
649        error => $q->param('error') || '',
650        limit => $limit,
651        limit_all => $limit eq 'all',
652        count_matches  => $matches,
653        replace_count  => $replace_count,
654        "search_$type" => 1,
655        search_label   => $class->class_label_plural,
656        object_label_plural => $class->class_label_plural,
657        object_type    => $type,
658        search         => ($do_replace ? $q->param('orig_search')
659        : $q->param('search')) || '',
660        searched => (
661            $do_replace ? $q->param('orig_search')
662            : ( $do_search && $q->param('search') ne '' )
663          )
664          || $show_all,
665        replace            => $replace,
666        do_replace         => $do_replace,
667        case               => $case,
668        datefrom_year      => $datefrom_year,
669        datefrom_month     => $datefrom_month,
670        datefrom_day       => $datefrom_day,
671        dateto_year        => $dateto_year,
672        dateto_month       => $dateto_month,
673        dateto_day         => $dateto_day,
674        is_regex           => $is_regex,
675        is_limited         => $is_limited,
676        is_dateranged      => $is_dateranged,
677        is_junk            => $is_junk,
678        can_search_junk    => ( $type eq 'comment' || $type eq 'ping' ),
679        can_replace        => $search_api->{$type}{can_replace},
680        can_search_by_date => $search_api->{$type}{can_search_by_date},
681        quick_search       => 0,
682        "tab_$tab"         => 1,
683        %param
684    );
685    $res{'tab_junk'} = 1 if $is_junk;
686   
687    my $search_cols = $search_api->{$type}{search_cols};
688    my %cols = map { $_ => 1 } @cols;
689    my @search_cols;
690    for my $field (keys %$search_cols) {
691        my %search_field;
692        $search_field{field}    = $field;
693        $search_field{selected} = 1 if exists($cols{$field});
694        $search_field{label}    = 'CODE' eq ref($search_cols->{$field})
695          ? $search_cols->{$field}->()
696          : $app->translate($search_cols->{$field});
697        push @search_cols, \%search_field;
698    }
699    $res{'search_cols'} = \@search_cols;
700    \%res;
701}
702
703sub _default_results_table_template {
704    my $app = shift;
705    my ($type, $results, $plural) = @_;
706    if ($results) {
707        return "<mt:include name=\"include/${type}_table.tmpl\">";
708    }
709    else {
710        return <<TMPL;   
711        <mtapp:statusmsg
712                id="no-$plural"
713                class="info">
714                <__trans phrase="No [_1] were found that match the given criteria." params="$plural">
715            </mtapp:statusmsg>
716        </mt:if>
717TMPL
718    }
719}
720
7211;
Note: See TracBrowser for help on using the browser.