root/branches/release-36/lib/MT/CMS/Search.pm @ 2093

Revision 2093, 27.1 kB (checked in by bchoate, 19 months ago)

Trim whitespace on search term. BugId:79424

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