| 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 | |
|---|
| 7 | package MT::Template::Context::Search; |
|---|
| 8 | |
|---|
| 9 | use strict; |
|---|
| 10 | use base qw( MT::Template::Context ); |
|---|
| 11 | use MT::Util qw( encode_url decode_html ); |
|---|
| 12 | |
|---|
| 13 | sub 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 SearchResultsHeader |
|---|
| 42 | |
|---|
| 43 | The content of this block tag is rendered when the item in context |
|---|
| 44 | from search results are the first item of the result set. You can |
|---|
| 45 | use the block to render headings and titles of the result table, |
|---|
| 46 | for example. |
|---|
| 47 | |
|---|
| 48 | This tag is only recognized in SearchResults block. |
|---|
| 49 | |
|---|
| 50 | =for tags search |
|---|
| 51 | |
|---|
| 52 | =cut |
|---|
| 53 | |
|---|
| 54 | ########################################################################### |
|---|
| 55 | |
|---|
| 56 | =head2 SearchResultsFooter |
|---|
| 57 | |
|---|
| 58 | The content of this block tag is rendered when the item in context |
|---|
| 59 | from search results are the last item of the result set. You can |
|---|
| 60 | use the block to render closeing tags of a HTML element, for example. |
|---|
| 61 | |
|---|
| 62 | This tag is only recognized in SearchResults block. |
|---|
| 63 | |
|---|
| 64 | =for tags search |
|---|
| 65 | |
|---|
| 66 | =cut |
|---|
| 67 | |
|---|
| 68 | ########################################################################### |
|---|
| 69 | |
|---|
| 70 | =head2 BlogResultHeader |
|---|
| 71 | |
|---|
| 72 | The contents of this container tag will be displayed when the blog id of |
|---|
| 73 | the entry in context from search results differs from the previous entry's |
|---|
| 74 | blog id. |
|---|
| 75 | |
|---|
| 76 | This tag is only recognized in search templates. |
|---|
| 77 | |
|---|
| 78 | =for tags search |
|---|
| 79 | |
|---|
| 80 | =cut |
|---|
| 81 | |
|---|
| 82 | ########################################################################### |
|---|
| 83 | |
|---|
| 84 | =head2 BlogResultFooter |
|---|
| 85 | |
|---|
| 86 | The contents of this container tag will be displayed when the blog id of |
|---|
| 87 | the entry in context from search results differs from the next entry's |
|---|
| 88 | blog id. |
|---|
| 89 | |
|---|
| 90 | This tag is only recognized in search templates. |
|---|
| 91 | |
|---|
| 92 | =for tags search |
|---|
| 93 | |
|---|
| 94 | =cut |
|---|
| 95 | |
|---|
| 96 | ########################################################################### |
|---|
| 97 | |
|---|
| 98 | =head2 IfMaxResultsCutOff |
|---|
| 99 | |
|---|
| 100 | NOTE: this tag only applies if you are using older Movable Type than |
|---|
| 101 | version 4.15, or you set up your search script so it instantiates |
|---|
| 102 | MT::App::Search::Legacy, the older search script. Under the default |
|---|
| 103 | search script in Movable Type, this tag will never be evaluated as true and |
|---|
| 104 | therefore the contents will never be rendered. |
|---|
| 105 | |
|---|
| 106 | A conditional tag that returns true when the number of search results |
|---|
| 107 | per blog exceeds the maximium limit specified in MaxResults configuration |
|---|
| 108 | directive. |
|---|
| 109 | |
|---|
| 110 | This tag is only recognized in search templates. |
|---|
| 111 | |
|---|
| 112 | =cut |
|---|
| 113 | |
|---|
| 114 | ########################################################################### |
|---|
| 115 | |
|---|
| 116 | =head2 MaxResults |
|---|
| 117 | |
|---|
| 118 | Returns the value of SearchMaxResults, specified either in configuration |
|---|
| 119 | (via C<SearchMaxResults> configuration directive) or in the search query |
|---|
| 120 | parameter in the URL. |
|---|
| 121 | |
|---|
| 122 | This tag is only recognized in search templates. |
|---|
| 123 | |
|---|
| 124 | =cut |
|---|
| 125 | |
|---|
| 126 | sub _hdlr_include_blogs { $_[0]->stash('include_blogs') || '' } |
|---|
| 127 | sub _hdlr_search_string { $_[0]->stash('search_string') || '' } |
|---|
| 128 | sub _hdlr_template_id { $_[0]->stash('template_id') || '' } |
|---|
| 129 | sub _hdlr_max_results { $_[0]->stash('maxresults') || '' } |
|---|
| 130 | |
|---|
| 131 | sub _hdlr_result_count { |
|---|
| 132 | my $results = $_[0]->stash('count'); |
|---|
| 133 | $results ? $results : 0; |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | sub _hdlr_results { |
|---|
| 137 | my($ctx, $args, $cond) = @_; |
|---|
| 138 | |
|---|
| 139 | ## If there are no results, return the empty string, knowing |
|---|
| 140 | ## that the handler for <MTNoSearchResults> will fill in the |
|---|
| 141 | ## no results message. |
|---|
| 142 | my $iter = $ctx->stash('results') or return ''; |
|---|
| 143 | my $count = $ctx->stash('count') or return ''; |
|---|
| 144 | my $max = $ctx->stash('maxresults'); |
|---|
| 145 | my $stash_key = $ctx->stash('stash_key') || 'entry'; |
|---|
| 146 | |
|---|
| 147 | my $output = ''; |
|---|
| 148 | my $build = $ctx->stash('builder'); |
|---|
| 149 | my $tokens = $ctx->stash('tokens'); |
|---|
| 150 | my $blog_header = 1; |
|---|
| 151 | my $blog_footer = 0; |
|---|
| 152 | my $footer = 0; |
|---|
| 153 | my $count_per_blog = 0; |
|---|
| 154 | my $max_reached = 0; |
|---|
| 155 | my ( $this_object, $next_object ); |
|---|
| 156 | $this_object = $iter->(); |
|---|
| 157 | return '' unless $this_object; |
|---|
| 158 | for ( my $i = 0; $i < $count; $i++) { |
|---|
| 159 | $count_per_blog++; |
|---|
| 160 | $ctx->stash($stash_key, $this_object); |
|---|
| 161 | local $ctx->{__stash}{blog} = $this_object->blog |
|---|
| 162 | if $this_object->can('blog'); |
|---|
| 163 | my $ts; |
|---|
| 164 | if ( $this_object->isa('MT::Entry') ) { |
|---|
| 165 | $ts = $this_object->authored_on; |
|---|
| 166 | } |
|---|
| 167 | elsif ( $this_object->properties->{audit} ) { |
|---|
| 168 | $ts = $this_object->created_on; |
|---|
| 169 | } |
|---|
| 170 | local $ctx->{current_timestamp} = $ts; |
|---|
| 171 | |
|---|
| 172 | # TODO: per blog max objects? |
|---|
| 173 | #if ( $count_per_blog >= $max ) { |
|---|
| 174 | # while (1) { |
|---|
| 175 | # if ( $count > $i + 1 ) { |
|---|
| 176 | # $next_object = $results->[$i + 1]; |
|---|
| 177 | # if ( $next_object->blog_id ne $this_object->blog_id ) { |
|---|
| 178 | # $blog_footer = 1; |
|---|
| 179 | # last; |
|---|
| 180 | # } |
|---|
| 181 | # else { |
|---|
| 182 | # $max_reached = 1; |
|---|
| 183 | # } |
|---|
| 184 | # } |
|---|
| 185 | # else { |
|---|
| 186 | # $next_object = undef; |
|---|
| 187 | # $blog_footer = 1; |
|---|
| 188 | # last; |
|---|
| 189 | # } |
|---|
| 190 | # $i++; |
|---|
| 191 | # } |
|---|
| 192 | #} |
|---|
| 193 | #elsif ( $count > $i + 1 ) { |
|---|
| 194 | # $next_object = $results->[$i + 1]; |
|---|
| 195 | # $blog_footer = $next_object->blog_id ne $this_object->blog_id ? 1 : 0; |
|---|
| 196 | #} |
|---|
| 197 | #else { |
|---|
| 198 | # $blog_footer = 1; |
|---|
| 199 | #} |
|---|
| 200 | if ( $next_object = $iter->() ) { |
|---|
| 201 | $blog_footer = $next_object->blog_id ne $this_object->blog_id ? 1 : 0; |
|---|
| 202 | } |
|---|
| 203 | else { |
|---|
| 204 | $blog_footer = 1; |
|---|
| 205 | $footer = 1; |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | defined(my $out = $build->build($ctx, $tokens, |
|---|
| 209 | { %$cond, |
|---|
| 210 | SearchResultsHeader => $i == 0, |
|---|
| 211 | SearchResultsFooter => $footer, |
|---|
| 212 | BlogResultHeader => $blog_header, |
|---|
| 213 | BlogResultFooter => $blog_footer, |
|---|
| 214 | IfMaxResultsCutoff => $max_reached, |
|---|
| 215 | } |
|---|
| 216 | )) or return $ctx->error( $build->errstr ); |
|---|
| 217 | $output .= $out; |
|---|
| 218 | |
|---|
| 219 | $this_object = $next_object; |
|---|
| 220 | last unless $this_object; |
|---|
| 221 | $blog_header = $blog_footer ? 1 : 0; |
|---|
| 222 | } |
|---|
| 223 | $output; |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | sub context_script { |
|---|
| 227 | my ( $ctx, $args, $cond ) = @_; |
|---|
| 228 | |
|---|
| 229 | my $search_string = decode_html( $ctx->stash('search_string') ) ; |
|---|
| 230 | my $cgipath = $ctx->_hdlr_cgi_path($args); |
|---|
| 231 | my $script = $ctx->{config}->SearchScript; |
|---|
| 232 | my $link = $cgipath.$script . '?search=' . encode_url( $search_string ); |
|---|
| 233 | if ( my $mode = $ctx->stash('mode') ) { |
|---|
| 234 | $mode = encode_url($mode); |
|---|
| 235 | $link .= "&__mode=$mode"; |
|---|
| 236 | } |
|---|
| 237 | if ( my $type = $ctx->stash('type') ) { |
|---|
| 238 | $type = encode_url($type); |
|---|
| 239 | $link .= "&type=$type"; |
|---|
| 240 | } |
|---|
| 241 | if ( my $include_blogs = $ctx->stash('include_blogs') ) { |
|---|
| 242 | $link .= "&IncludeBlogs=$include_blogs"; |
|---|
| 243 | } |
|---|
| 244 | elsif ( my $blog_id = $ctx->stash('blog_id') ) { |
|---|
| 245 | $link .= "&blog_id=$blog_id"; |
|---|
| 246 | } |
|---|
| 247 | if ( my $format = $ctx->stash('format') ) { |
|---|
| 248 | $link .= '&format=' . encode_url($format); |
|---|
| 249 | } |
|---|
| 250 | $link; |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | 1; |
|---|
| 254 | __END__ |
|---|
| 255 | |
|---|