root/branches/release-41/lib/MT/Template/Context/Search.pm @ 2742

Revision 2742, 10.6 kB (checked in by bchoate, 17 months ago)

Updated POD for template tags; added test for template tag doc coverage.

  • Property svn:keywords set to Id Date Author Revision
Line 
1# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
2# This program is distributed under the terms of the
3# GNU General Public License, version 2.
4#
5# $Id$
6
7package MT::Template::Context::Search;
8
9use strict;
10use base qw( MT::Template::Context );
11use MT::Util qw( encode_url decode_html );
12
13sub load_core_tags {
14    require MT::Template::Context;
15    return {
16        function => {
17            SearchString => \&_hdlr_search_string,
18            SearchResultCount => \&_hdlr_result_count,
19            MaxResults => \&_hdlr_max_results,
20            SearchIncludeBlogs => \&_hdlr_include_blogs,
21            SearchTemplateID => \&_hdlr_template_id,
22        },
23        block => {
24            SearchResults => \&_hdlr_results,
25            'IfTagSearch?' => sub { MT->instance->mode eq 'tag' },
26            'IfStraightSearch?' => sub { MT->instance->mode eq 'default' },
27            'NoSearchResults?' => sub { $_[0]->stash('count') ? 0 : 1; },
28            'NoSearch?' => sub { ( $_[0]->stash('search_string') &&
29                                   $_[0]->stash('search_string') =~ /\S/ ) ? 0 : 1 },
30            SearchResultsHeader => \&MT::Template::Context::_hdlr_pass_tokens,
31            SearchResultsFooter => \&MT::Template::Context::_hdlr_pass_tokens,
32            BlogResultHeader => \&MT::Template::Context::_hdlr_pass_tokens,
33            BlogResultFooter => \&MT::Template::Context::_hdlr_pass_tokens,
34            'IfMaxResultsCutoff?' => \&MT::Template::Context::_hdlr_pass_tokens,
35        },
36    };
37}
38
39###########################################################################
40
41=head2 IfStraightSearch
42
43A conditional block which outputs its contents if the search in progress
44is a regular (or "straight") search.
45
46=for tags search
47
48=cut
49
50###########################################################################
51
52=head2 IfTagSearch
53
54A conditional block which outputs its contents if the search in progress
55is a search of entries by tag.
56
57=for tags search
58
59=cut
60
61###########################################################################
62
63=head2 NoSearch
64
65A container tag whose contents are displayed only if there is no search
66performed.
67
68This tag is only recognized in search templates.
69
70=for tags search
71
72=cut
73
74###########################################################################
75
76=head2 NoSearchResults
77
78A container tag whose contents are displayed if a search is performed
79but no results are found.
80
81This tag is only recognized in search templates.
82
83=for tags search
84
85=cut
86
87###########################################################################
88
89=head2 SearchResultsHeader
90
91The content of this block tag is rendered when the item in context
92from search results are the first item of the result set.  You can
93use the block to render headings and titles of the result table,
94for example.
95
96This tag is only recognized in SearchResults block.
97
98B<Example:>
99
100    <mt:SearchResultsHeader>
101    <h3>Look what we found!</h3>
102    </mt:SearchResultsHeader>
103
104=for tags search
105
106=cut
107
108###########################################################################
109
110=head2 SearchResultsFooter
111
112The content of this block tag is rendered when the item in context
113from search results are the last item of the result set.  You can
114use the block to render closeing tags of a HTML element, for example.
115
116This tag is only recognized in SearchResults block.
117
118B<Example:>
119
120    <mt:SearchResultsFooter>
121    <p>If you didn't find what you were looking for, you can also peruse
122    the <a href="<mt:Link identifier="archive_index">">site archives</a>.</p>
123    </mt:SearchResultsFooter>
124
125=for tags search
126
127=cut
128
129###########################################################################
130
131=head2 BlogResultHeader
132
133The contents of this container tag will be displayed when the blog id of
134the entry in context from search results differs from the previous entry's
135blog id.
136
137This tag is only recognized in search templates.
138
139=for tags search
140
141=cut
142
143###########################################################################
144
145=head2 BlogResultFooter
146
147The contents of this container tag will be displayed when the blog id of
148the entry in context from search results differs from the next entry's
149blog id.
150
151This tag is only recognized in search templates.
152
153=for tags search
154
155=cut
156
157###########################################################################
158
159=head2 IfMaxResultsCutOff
160
161NOTE: this tag only applies if you are using older Movable Type than
162version 4.15, or you set up your search script so it instantiates
163MT::App::Search::Legacy, the older search script.  Under the default
164search script in Movable Type, this tag will never be evaluated as true and
165therefore the contents will never be rendered.
166
167A conditional tag that returns true when the number of search results
168per blog exceeds the maximium limit specified in MaxResults configuration
169directive.
170
171This tag is only recognized in search templates.
172
173=for tags search
174
175=cut
176
177###########################################################################
178
179=head2 MaxResults
180
181Returns the value of SearchMaxResults, specified either in configuration
182(via C<SearchMaxResults> configuration directive) or in the search query
183parameter in the URL.
184
185This tag is only recognized in search templates.
186
187=cut
188
189###########################################################################
190
191=head2 SearchIncludeBlogs
192
193Used in the search result template to pass the IncludeBlogs parameters
194through from the search form keeping the context of any followup search
195the same as the initial search.
196
197B<Example:>
198
199    <input type="hidden" name="IncludeBlogs" value="<$mt:SearchIncludeBlogs$>" />
200
201=cut
202
203sub _hdlr_include_blogs { $_[0]->stash('include_blogs') || '' }
204
205###########################################################################
206
207=head2 SearchString
208
209An HTML-encoded search query. This tag is only recognized in search templates.
210
211B<Example:>
212
213    <$mt:SearchString$>
214
215=for tags search
216
217=cut
218
219sub _hdlr_search_string { $_[0]->stash('search_string') || '' }
220
221###########################################################################
222
223=head2 SearchTemplateID
224
225Returns the identifier of the search template (ie, "feed" or
226"nomorepizzaplease").
227
228B<Example:>
229
230    <$mt:SearchTemplateID$>
231
232=for tags search
233
234=cut
235
236sub _hdlr_template_id { $_[0]->stash('template_id') || '' }
237sub _hdlr_max_results { $_[0]->stash('maxresults') || '' }
238
239###########################################################################
240
241=head2 SearchResultCount
242
243The number of results found across all of the blogs searched. This tag
244is only recognized in search templates.
245
246B<Example:>
247
248    <$mt:SearchResultCount$>
249
250=for tags search, count
251
252=cut
253
254sub _hdlr_result_count {
255    my $results = $_[0]->stash('count');
256    $results ? $results : 0;
257}
258
259###########################################################################
260
261=head2 SearchResults
262
263A container tag that creates a list of search results. This tag
264creates an entry and blog context that all Entry* and Blog* tags
265can be used.
266
267This tag is only recognized in search templates.
268
269=for tags search
270
271=cut
272
273sub _hdlr_results {
274    my($ctx, $args, $cond) = @_;
275
276    ## If there are no results, return the empty string, knowing
277    ## that the handler for <MTNoSearchResults> will fill in the
278    ## no results message.
279    my $iter = $ctx->stash('results') or return '';
280    my $count = $ctx->stash('count') or return '';
281    my $max = $ctx->stash('maxresults');
282    my $stash_key = $ctx->stash('stash_key') || 'entry';
283
284    my $output = '';
285    my $build = $ctx->stash('builder');
286    my $tokens = $ctx->stash('tokens');
287    my $blog_header = 1;
288    my $blog_footer = 0;
289    my $footer = 0;
290    my $count_per_blog = 0;
291    my $max_reached = 0;
292    my ( $this_object, $next_object );
293    $this_object = $iter->();
294    return '' unless $this_object;
295    for ( my $i = 0; $i < $count; $i++) {
296        $count_per_blog++;
297        $ctx->stash($stash_key, $this_object);
298        local $ctx->{__stash}{blog} = $this_object->blog
299            if $this_object->can('blog');
300        my $ts;
301        if ( $this_object->isa('MT::Entry') ) {
302            $ts = $this_object->authored_on;
303        }
304        elsif ( $this_object->properties->{audit} ) {
305            $ts = $this_object->created_on;
306        }
307        local $ctx->{current_timestamp} = $ts;
308
309        # TODO: per blog max objects?
310        #if ( $count_per_blog >= $max ) {
311        #    while (1) {
312        #        if ( $count > $i + 1 ) {
313        #            $next_object = $results->[$i + 1];
314        #            if ( $next_object->blog_id ne $this_object->blog_id ) {
315        #                $blog_footer = 1;
316        #                last;
317        #            }
318        #            else {
319        #                $max_reached = 1;
320        #            }
321        #        }
322        #        else {
323        #            $next_object = undef;
324        #            $blog_footer = 1;
325        #            last;
326        #        }
327        #        $i++;
328        #    }
329        #}
330        #elsif ( $count > $i + 1 ) {
331        #    $next_object = $results->[$i + 1];
332        #    $blog_footer = $next_object->blog_id ne $this_object->blog_id ? 1 : 0;
333        #}
334        #else {
335        #    $blog_footer = 1;
336        #}
337        if ( $next_object = $iter->() ) {
338            $blog_footer = $next_object->blog_id ne $this_object->blog_id ? 1 : 0;
339        }
340        else {
341            $blog_footer = 1;
342            $footer      = 1;
343        }
344
345        defined(my $out = $build->build($ctx, $tokens,
346            { %$cond, 
347                SearchResultsHeader => $i == 0,
348                SearchResultsFooter => $footer,
349                BlogResultHeader => $blog_header,
350                BlogResultFooter => $blog_footer,
351                IfMaxResultsCutoff => $max_reached,
352            }
353            )) or return $ctx->error( $build->errstr );
354        $output .= $out;
355
356        $this_object = $next_object;
357        last unless $this_object;
358        $blog_header = $blog_footer ? 1 : 0;
359    }
360    $output;
361}
362
363sub context_script {
364        my ( $ctx, $args, $cond ) = @_;
365
366    my $search_string = decode_html( $ctx->stash('search_string') ) ;
367    my $cgipath = $ctx->_hdlr_cgi_path($args);
368    my $script = $ctx->{config}->SearchScript;
369    my $link = $cgipath.$script . '?search=' . encode_url( $search_string );
370    if ( my $mode = $ctx->stash('mode') ) {
371        $mode = encode_url($mode);
372        $link .= "&__mode=$mode";
373    }
374    if ( my $type = $ctx->stash('type') ) {
375        $type = encode_url($type);
376        $link .= "&type=$type";
377    }
378    if ( my $include_blogs = $ctx->stash('include_blogs') ) {
379        $link .= "&IncludeBlogs=$include_blogs";
380    }
381    elsif ( my $blog_id = $ctx->stash('blog_id') ) {
382        $link .= "&blog_id=$blog_id";
383    }
384    if ( my $format = $ctx->stash('format') ) {
385        $link .= '&format=' . encode_url($format);
386    }
387        $link;
388}
389
3901;
391__END__
392
Note: See TracBrowser for help on using the browser.