Index: trunk/extensions/SphinxSearch/SphinxSearch_body.php |
— | — | @@ -1,872 +0,0 @@ |
2 | | -<?php |
3 | | - |
4 | | -/** |
5 | | - * Class file for the SphinxSearch extension |
6 | | - * |
7 | | - * http://www.mediawiki.org/wiki/Extension:SphinxSearch |
8 | | - * |
9 | | - * Released under GNU General Public License (see http://www.fsf.org/licenses/gpl.html) |
10 | | - * |
11 | | - * @file |
12 | | - * @ingroup Extensions |
13 | | - * @author Svemir Brkic <svemir@deveblog.com> and Paul Grinberg |
14 | | - */ |
15 | | - |
16 | | -class SphinxSearch extends SpecialPage { |
17 | | - |
18 | | - var $search_term = ''; // what are we looking for |
19 | | - var $namespaces = array(); // namespaces to search |
20 | | - var $categories = array(); // categories to include |
21 | | - var $exc_categories = array(); // categories to exclude |
22 | | - var $page = 1; // results page we are on |
23 | | - |
24 | | - /** |
25 | | - * Build a set of next/previous links for a given title |
26 | | - * |
27 | | - * @param Title $title |
28 | | - * @return string |
29 | | - */ |
30 | | - function __construct() { |
31 | | - global $wgDisableInternalSearch, $wgAutoloadClasses; |
32 | | - |
33 | | - if ( $wgDisableInternalSearch ) { |
34 | | - parent::__construct( 'Search' ); |
35 | | - } else { |
36 | | - parent::__construct( 'SphinxSearch' ); |
37 | | - } |
38 | | - |
39 | | - |
40 | | - |
41 | | - return true; |
42 | | - } |
43 | | - |
44 | | - /** |
45 | | - * Determine which namespaces may be included in a search |
46 | | - * |
47 | | - * @return array |
48 | | - */ |
49 | | - function searchableNamespaces() { |
50 | | - $namespaces = SearchEngine::searchableNamespaces(); |
51 | | - |
52 | | - wfRunHooks( 'SphinxSearchFilterSearchableNamespaces', array( &$namespaces ) ); |
53 | | - |
54 | | - return $namespaces; |
55 | | - } |
56 | | - |
57 | | - /** |
58 | | - * Determine which categories may be included in a search |
59 | | - * |
60 | | - * @return array |
61 | | - */ |
62 | | - function searchableCategories() { |
63 | | - global $wgSphinxTopSearchableCategory; |
64 | | - |
65 | | - if ( $wgSphinxTopSearchableCategory ) { |
66 | | - $categories = self::getChildrenCategories( $wgSphinxTopSearchableCategory ); |
67 | | - } else { |
68 | | - $categories = array(); |
69 | | - } |
70 | | - |
71 | | - wfRunHooks( 'SphinxSearchGetSearchableCategories', array( &$categories ) ); |
72 | | - |
73 | | - return $categories; |
74 | | - } |
75 | | - |
76 | | - /** |
77 | | - * Determine sub-categories of a given category |
78 | | - * |
79 | | - * @param string $parent |
80 | | - * @return array |
81 | | - */ |
82 | | - function getChildrenCategories( $parent ) { |
83 | | - global $wgMemc, $wgDBname; |
84 | | - |
85 | | - $categories = null; |
86 | | - if ( is_object( $wgMemc ) ) { |
87 | | - $cache_key = $wgDBname . ':sphinx_cats:' . md5( $parent ); |
88 | | - $categories = $wgMemc->get( $cache_key ); |
89 | | - } |
90 | | - |
91 | | - if ( !is_array( $categories ) ) { |
92 | | - $categories = array(); |
93 | | - $dbr = wfGetDB( DB_SLAVE ); |
94 | | - $res = $dbr->select( |
95 | | - array( 'categorylinks', 'page' ), |
96 | | - array( 'cl_from', 'cl_sortkey', 'page_title' ), |
97 | | - array( '1', |
98 | | - 'cl_from = page_id', |
99 | | - 'cl_to' => $parent, |
100 | | - 'page_namespace' => NS_CATEGORY ), |
101 | | - __METHOD__, |
102 | | - array( 'ORDER BY' => 'cl_sortkey' ) |
103 | | - ); |
104 | | - while ( $x = $dbr->fetchObject ( $res ) ) { |
105 | | - $categories[$x->cl_from] = $x->cl_sortkey; |
106 | | - } |
107 | | - if ( $cache_key ) { |
108 | | - # cache query results for a day |
109 | | - $wgMemc->set( $cache_key, $categories, 86400 ); |
110 | | - } |
111 | | - $dbr->freeResult( $res ); |
112 | | - } |
113 | | - return $categories; |
114 | | - } |
115 | | - |
116 | | - /** |
117 | | - * $wgAjaxExportList callback - create a category filter sub-menu |
118 | | - * |
119 | | - * @param string $parent_id |
120 | | - * @return string |
121 | | - */ |
122 | | - function ajaxGetCategoryChildren( $parent_id ) { |
123 | | - |
124 | | - $title = Title::newFromID( $parent_id ); |
125 | | - |
126 | | - if ( !$title ) { |
127 | | - return false; |
128 | | - } |
129 | | - |
130 | | - # Retrieve page_touched for the category |
131 | | - $dbkey = $title->getDBkey(); |
132 | | - $dbr = wfGetDB( DB_SLAVE ); |
133 | | - $touched = $dbr->selectField( |
134 | | - 'page', 'page_touched', |
135 | | - array( |
136 | | - 'page_namespace' => NS_CATEGORY, |
137 | | - 'page_title' => $dbkey, |
138 | | - ), |
139 | | - __METHOD__ |
140 | | - ); |
141 | | - |
142 | | - $response = new AjaxResponse(); |
143 | | - |
144 | | - if ( $response->checkLastModified( $touched ) ) { |
145 | | - return $response; |
146 | | - } |
147 | | - |
148 | | - $categories = self::getChildrenCategories( $dbkey ); |
149 | | - |
150 | | - $html = self::getCategoryCheckboxes( $categories, $parent_id ); |
151 | | - |
152 | | - $response->addText( $html ); |
153 | | - |
154 | | - return $response; |
155 | | - } |
156 | | - |
157 | | - /** |
158 | | - * Main execution function |
159 | | - * |
160 | | - * @param string $par Parameters passed to the page |
161 | | - */ |
162 | | - function execute( $par ) { |
163 | | - global $wgRequest, $wgOut, $wgUser, $wgSphinxMatchAll, $wgSphinxSearch_index_list; |
164 | | - |
165 | | - # extract the options from the GET query |
166 | | - $term = $wgRequest->getText( 'search', $par ); |
167 | | - if ( $term === '' ) { |
168 | | - $term = $wgRequest->getText( 'sphinxsearch', $par ); |
169 | | - } |
170 | | - # see if we want to go the title directly |
171 | | - # this logic is actually reversed (if we are not doing a search, |
172 | | - # thn try to go to title directly). This is needed because IE has a |
173 | | - # different behavior when the <ENTER> button is pressed in a form - |
174 | | - # it does not send the name of the default button! |
175 | | - if ( !$wgRequest->getVal( 'fulltext' ) ) { |
176 | | - $this->goResult( $term ); |
177 | | - } |
178 | | - |
179 | | - $this->setHeaders(); |
180 | | - $wgOut->setPagetitle( wfMsg( 'sphinxsearch' ) ); |
181 | | - |
182 | | - $this->namespaces = array(); |
183 | | - $all_namespaces = self::searchableNamespaces(); |
184 | | - foreach ( $all_namespaces as $ns => $name ) { |
185 | | - if ( $wgRequest->getCheck( "ns{$ns}" ) ) { |
186 | | - $this->namespaces[] = $ns; |
187 | | - } |
188 | | - } |
189 | | - if ( !count( $this->namespaces ) ) { |
190 | | - foreach ( $all_namespaces as $ns => $name ) { |
191 | | - if ( $wgUser->getOption( 'searchNs' . $ns ) ) { |
192 | | - $this->namespaces[] = $ns; |
193 | | - } |
194 | | - } |
195 | | - } |
196 | | - |
197 | | - $this->categories = $wgRequest->getIntArray( "cat", array() ); |
198 | | - $this->exc_categories = $wgRequest->getIntArray( "exc", array() ); |
199 | | - |
200 | | - $this->page = $wgRequest->getInt( 'page', 1 ); |
201 | | - $wgSphinxMatchAll = $wgRequest->getInt( 'match_all', intval( $wgSphinxMatchAll ) ); |
202 | | - $match_titles_only = ( $wgRequest->getInt( 'match_titles' ) == 1 ); |
203 | | - |
204 | | - # do the actual search |
205 | | - $found = 0; |
206 | | - $cl = $this->prepareSphinxClient( $term, $match_titles_only ); |
207 | | - if ( $cl ) { |
208 | | - $res = $cl->Query( |
209 | | - addcslashes( $this->search_term, '/()[]"!' ), |
210 | | - $wgSphinxSearch_index_list |
211 | | - ); |
212 | | - if ( $res === false ) { |
213 | | - $wgOut->addWikiText( wfMsg( 'sphinxSearchFailed', $cl->GetLastError() ) . "\n" ); |
214 | | - } else { |
215 | | - $found = $this->wfSphinxDisplayResults( $term, $res, $cl ); |
216 | | - } |
217 | | - } else { |
218 | | - $wgOut->addWikiText( wfMsg( 'sphinxClientFailed' ) . "\n" ); |
219 | | - } |
220 | | - |
221 | | - # prepare for the next search |
222 | | - if ( $found ) { |
223 | | - $this->createNextPageBar( $found, $term ); |
224 | | - } |
225 | | - |
226 | | - $this->createNewSearchForm( $term ); |
227 | | - } |
228 | | - |
229 | | - /** |
230 | | - * If an exact title match can be found, jump straight ahead to it. |
231 | | - * |
232 | | - * @param string $term |
233 | | - */ |
234 | | - function goResult( $term ) { |
235 | | - global $wgOut, $wgGoToEdit; |
236 | | - |
237 | | - # Try to go to page as entered. |
238 | | - $t = Title::newFromText( $term ); |
239 | | - |
240 | | - # If the string cannot be used to create a title |
241 | | - if ( is_null( $t ) ) { |
242 | | - return; |
243 | | - } |
244 | | - |
245 | | - # If there's an exact or very near match, jump right there. |
246 | | - $t = SearchEngine::getNearMatch( $term ); |
247 | | - wfRunHooks( 'SphinxSearchGetNearMatch', array( &$term, &$t ) ); |
248 | | - if ( !is_null( $t ) ) { |
249 | | - $wgOut->redirect( $t->getFullURL() ); |
250 | | - return; |
251 | | - } |
252 | | - |
253 | | - # No match, generate an edit URL |
254 | | - $t = Title::newFromText( $term ); |
255 | | - if ( !is_null( $t ) ) { |
256 | | - # If the feature is enabled, go straight to the edit page |
257 | | - if ( $wgGoToEdit ) { |
258 | | - $wgOut->redirect( $t->getFullURL( 'action=edit' ) ); |
259 | | - return; |
260 | | - } |
261 | | - } |
262 | | - |
263 | | - $wgOut->addWikiText( wfMsg( 'searchmenu-new', wfEscapeWikiText( $term ) ) ); |
264 | | - } |
265 | | - |
266 | | - /** |
267 | | - * Set the maximum number of results to return |
268 | | - * and how many to skip before returning the first. |
269 | | - * |
270 | | - * @param int $limit |
271 | | - * @param int $offset |
272 | | - * @access public |
273 | | - */ |
274 | | - function setLimitOffset( $limit, $offset = 0 ) { |
275 | | - global $wgSphinxSearch_matches; |
276 | | - |
277 | | - $wgSphinxSearch_matches = intval( $limit ); |
278 | | - |
279 | | - if ( $offset > 0 && $limit > 0 ) { |
280 | | - $this->page = 1 + intval( $offset / $limit ); |
281 | | - } |
282 | | - } |
283 | | - |
284 | | - /** |
285 | | - * Set which namespaces the search should include. |
286 | | - * Give an array of namespace index numbers. |
287 | | - * |
288 | | - * @param array $namespaces |
289 | | - * @access public |
290 | | - */ |
291 | | - function setNamespaces( $namespaces ) { |
292 | | - $this->namespaces = $namespaces; |
293 | | - } |
294 | | - |
295 | | - /** |
296 | | - * Perform a full text search query and return a result set. |
297 | | - * |
298 | | - * @param string $term - Raw search term |
299 | | - * @return SphinxSearchResultSet |
300 | | - * @access public |
301 | | - */ |
302 | | - function searchText( $term, $titles_only = false ) { |
303 | | - global $wgSphinxSearch_index_list; |
304 | | - |
305 | | - $cl = $this->prepareSphinxClient( $term, $titles_only ); |
306 | | - if ( $cl ) { |
307 | | - $res = $cl->Query( |
308 | | - addcslashes( $this->search_term, '/()[]"!' ), |
309 | | - $wgSphinxSearch_index_list |
310 | | - ); |
311 | | - } else { |
312 | | - $res = false; |
313 | | - } |
314 | | - |
315 | | - if ( $res === false ) { |
316 | | - return null; |
317 | | - } else { |
318 | | - return new SphinxSearchResultSet( $term, $res, $cl ); |
319 | | - } |
320 | | - } |
321 | | - |
322 | | - /** |
323 | | - * Perform a title-only search query and return a result set. |
324 | | - * |
325 | | - * @param string $term - Raw search term |
326 | | - * @return SphinxSearchResultSet |
327 | | - * @access public |
328 | | - */ |
329 | | - function searchTitle( $term ) { |
330 | | - return $this->searchText( $term, true ); |
331 | | - } |
332 | | - |
333 | | - /** |
334 | | - * Search for "$term" |
335 | | - * Display the results of the search one page at a time. |
336 | | - * Returns the number of matches. |
337 | | - */ |
338 | | - function prepareSphinxClient( $term, $match_titles_only = false ) { |
339 | | - global $wgSphinxSearch_sortmode, $wgSphinxSearch_sortby, $wgSphinxSearch_host, |
340 | | - $wgSphinxSearch_port, $wgSphinxSearch_index_weights, $wgSphinxSearch_index, |
341 | | - $wgSphinxSearch_matches, $wgSphinxSearch_mode, $wgSphinxSearch_weights, |
342 | | - $wgSphinxMatchAll, $wgSphinxSearch_maxmatches, $wgSphinxSearch_cutoff; |
343 | | - |
344 | | - # don't do anything for blank searches |
345 | | - if ( trim( $term ) === '' ) { |
346 | | - return false; |
347 | | - } |
348 | | - |
349 | | - wfRunHooks( 'SphinxSearchBeforeResults', array( |
350 | | - &$term, |
351 | | - &$this->page, |
352 | | - &$this->namespaces, |
353 | | - &$this->categories, |
354 | | - &$this->exc_categories |
355 | | - ) ); |
356 | | - |
357 | | - if ( $wgSphinxSearch_mode == SPH_MATCH_EXTENDED && $wgSphinxMatchAll != '1' ) { |
358 | | - # make OR the default in extended mode |
359 | | - $this->search_term = preg_replace( '/[\s_\-&]+/', '|', trim( $term ) ); |
360 | | - } else { |
361 | | - $this->search_term = $term; |
362 | | - } |
363 | | - |
364 | | - $cl = new SphinxClient(); |
365 | | - |
366 | | - # setup the options for searching |
367 | | - if ( isset( $wgSphinxSearch_host ) && isset( $wgSphinxSearch_port ) ) { |
368 | | - $cl->SetServer( $wgSphinxSearch_host, $wgSphinxSearch_port ); |
369 | | - } |
370 | | - if ( count( $wgSphinxSearch_weights ) ) { |
371 | | - if ( is_string( key( $wgSphinxSearch_weights ) ) ) { |
372 | | - $cl->SetFieldWeights( $wgSphinxSearch_weights ); |
373 | | - } else { |
374 | | - $cl->SetWeights( $wgSphinxSearch_weights ); |
375 | | - } |
376 | | - } |
377 | | - if ( is_array( $wgSphinxSearch_index_weights ) ) { |
378 | | - $cl->SetIndexWeights( $wgSphinxSearch_index_weights ); |
379 | | - } |
380 | | - if ( isset( $wgSphinxSearch_mode ) ) { |
381 | | - $cl->SetMatchMode( $wgSphinxSearch_mode ); |
382 | | - } |
383 | | - if ( count( $this->namespaces ) ) { |
384 | | - $cl->SetFilter( 'page_namespace', $this->namespaces ); |
385 | | - } |
386 | | - |
387 | | - if ( count( $this->categories ) ) { |
388 | | - $cl->SetFilter( 'category', $this->categories ); |
389 | | - } |
390 | | - |
391 | | - if ( count( $this->exc_categories ) ) { |
392 | | - $cl->SetFilter( 'category', $this->exc_categories, true ); |
393 | | - } |
394 | | - |
395 | | - $cl->SetSortMode( $wgSphinxSearch_sortmode, $wgSphinxSearch_sortby ); |
396 | | - $cl->SetLimits( |
397 | | - ( $this->page - 1 ) * $wgSphinxSearch_matches, |
398 | | - $wgSphinxSearch_matches, |
399 | | - $wgSphinxSearch_maxmatches, |
400 | | - $wgSphinxSearch_cutoff |
401 | | - ); |
402 | | - |
403 | | - if ( $match_titles_only ) { |
404 | | - $this->search_term = '@page_title ' . $this->search_term; |
405 | | - } |
406 | | - |
407 | | - wfRunHooks( 'SphinxSearchBeforeQuery', array( &$this->search_term, &$cl ) ); |
408 | | - |
409 | | - return $cl; |
410 | | - } |
411 | | - |
412 | | - function wfSphinxDisplayResults( $term, $res, $cl ) { |
413 | | - |
414 | | - global $wgOut, $wgSphinxSuggestMode, $wgSphinxSearch_matches, |
415 | | - $wgSphinxSearch_index, $wgSphinxSearch_maxmatches; |
416 | | - |
417 | | - if ($cl->GetLastWarning()) { |
418 | | - $wgOut->addWikiText( wfMsg( 'sphinxSearchWarning', $cl->GetLastWarning() ) . "\n\n"); |
419 | | - } |
420 | | - $found = $res['total_found']; |
421 | | - |
422 | | - if ( $wgSphinxSuggestMode ) { |
423 | | - $didyoumean = $this->spell(); |
424 | | - if ( $didyoumean ) { |
425 | | - $wgOut->addhtml( wfMsg( 'sphinxSearchDidYouMean' ) . |
426 | | - " <b><a href='" . |
427 | | - $this->getActionURL( $didyoumean, $this->namespaces ) . |
428 | | - "1'>" . $didyoumean . '</a></b>' |
429 | | - ); |
430 | | - } |
431 | | - } |
432 | | - |
433 | | - $from = min( |
434 | | - ( ( $this->page - 1 ) * $wgSphinxSearch_matches ) + 1, |
435 | | - $res['total'] |
436 | | - ); |
437 | | - $to = min( |
438 | | - $this->page * $wgSphinxSearch_matches, |
439 | | - $res['total'] |
440 | | - ); |
441 | | - $wgOut->addWikiText( wfMsgExt( 'sphinxSearchPreamble', 'parsemag', |
442 | | - $from, $to, $res['total'], $term, $res['time'] ) |
443 | | - ); |
444 | | - |
445 | | - if ( is_array( $res["words"] ) ) { |
446 | | - $warn = false; |
447 | | - foreach ( $res["words"] as $word => $info ) { |
448 | | - $wgOut->addWikiText( |
449 | | - wfMsgExt( 'sphinxSearchStats', 'parsemag', $word, $info['hits'], $info['docs'] ) |
450 | | - ); |
451 | | - if ( ( $info['docs'] < $wgSphinxSearch_maxmatches ) && ( $info['docs'] > $res['total'] ) ) { |
452 | | - $warn = true; |
453 | | - } |
454 | | - } |
455 | | - if ( $warn ) { |
456 | | - $wgOut->addWikiText( wfMsg( 'sphinxSearchStatsInfo' ) ); |
457 | | - } else { |
458 | | - $wgOut->addWikiText( "\n" ); |
459 | | - } |
460 | | - } |
461 | | - $start_time = microtime( true ); |
462 | | - |
463 | | - if ( isset( $res["matches"] ) && is_array( $res["matches"] ) ) { |
464 | | - $wgOut->addWikiText( "----" ); |
465 | | - $dbr = wfGetDB( DB_SLAVE ); |
466 | | - $excerpts_opt = array( |
467 | | - "before_match" => "<span style='color:red'>", |
468 | | - "after_match" => "</span>", |
469 | | - "chunk_separator" => " ... ", |
470 | | - "limit" => 400, |
471 | | - "around" => 15 |
472 | | - ); |
473 | | - foreach ( $res["matches"] as $doc => $docinfo ) { |
474 | | - $page_content = $dbr->selectField( |
475 | | - 'text', 'old_text', |
476 | | - array( |
477 | | - 'old_id' => $docinfo['attrs']['old_id'] |
478 | | - ), |
479 | | - __METHOD__ |
480 | | - ); |
481 | | - if ( $page_content ) { |
482 | | - $title_obj = Title::newFromID( $doc ); |
483 | | - if ( is_object( $title_obj ) ) { |
484 | | - $wiki_title = $title_obj->getPrefixedText(); |
485 | | - $wiki_path = $title_obj->getPrefixedDBkey(); |
486 | | - $wgOut->addWikiText( "* <span style='font-size:110%;'>[[:$wiki_path|$wiki_title]]</span>" ); |
487 | | - |
488 | | - # uncomment this line to see the weights etc. as HTML comments in the source of the page |
489 | | - # $wgOut->addHTML("<!-- page_id: ".$doc."\ninfo: ".print_r($docinfo, true)." -->"); |
490 | | - |
491 | | - $excerpts = $cl->BuildExcerpts( |
492 | | - array( $page_content ), |
493 | | - $wgSphinxSearch_index, |
494 | | - $term, |
495 | | - $excerpts_opt |
496 | | - ); |
497 | | - if ( !is_array( $excerpts ) ) { |
498 | | - $excerpts = array( wfMsg( 'sphinxSearchWarning', $cl->GetLastError() ) ); |
499 | | - } |
500 | | - foreach ( $excerpts as $entry ) { |
501 | | - # add excerpt to output, removing some wiki markup |
502 | | - $entry = preg_replace( '/([\[\]\{\}\*\#\|\!]+|==+)/', |
503 | | - ' ', |
504 | | - strip_tags( $entry, '<span><br>' ) |
505 | | - ); |
506 | | - $wgOut->addHTML( "<div style='margin: 0.2em 1em 1em 1em;'>$entry</div>\n" ); |
507 | | - } |
508 | | - } |
509 | | - } |
510 | | - } |
511 | | - $time = number_format( microtime( true ) - $start_time, 3); |
512 | | - $wgOut->addWikiText( wfMsg( 'sphinxSearchEpilogue', $time ) ); |
513 | | - } |
514 | | - |
515 | | - wfRunHooks( 'SphinxSearchAfterResults', array( $term, $this->page ) ); |
516 | | - |
517 | | - return $found; |
518 | | - } |
519 | | - |
520 | | - function getActionURL( $term ) { |
521 | | - global $wgDisableInternalSearch, $wgSphinxMatchAll, $wgRequest; |
522 | | - |
523 | | - $search_title = ( $wgDisableInternalSearch ? 'Search' : 'SphinxSearch' ); |
524 | | - $titleObj = SpecialPage::getTitleFor( $search_title ); |
525 | | - $qry = $titleObj->getLocalUrl(); |
526 | | - $searchField = strtolower( $search_title ); |
527 | | - $term = urlencode( $term ); |
528 | | - $qry .= ( strpos( $qry, '?' ) === false ? '?' : '&' ) . |
529 | | - $searchField . "={$term}&fulltext=" . |
530 | | - wfMsg( 'sphinxSearchButton' ) . "&"; |
531 | | - if ( $wgSphinxMatchAll == '1' ) { |
532 | | - $qry .= "match_all=1&"; |
533 | | - } |
534 | | - if ( $wgRequest->getInt( 'match_titles' ) ) { |
535 | | - $qry .= "match_titles=1&"; |
536 | | - } |
537 | | - foreach ( $this->namespaces as $ns ) { |
538 | | - $qry .= "ns{$ns}=1&"; |
539 | | - } |
540 | | - foreach ( $this->categories as $c ) { |
541 | | - $qry .= "cat[]={$c}&"; |
542 | | - } |
543 | | - foreach ( $this->exc_categories as $c ) { |
544 | | - $qry .= "exc[]={$c}&"; |
545 | | - } |
546 | | - $qry .= "page="; |
547 | | - |
548 | | - return $qry; |
549 | | - } |
550 | | - |
551 | | - function createNextPageBar( $found, $term ) { |
552 | | - global $wgOut, $wgSphinxSearch_matches; |
553 | | - |
554 | | - $qry = $this->getActionURL( $term ); |
555 | | - |
556 | | - $display_pages = 10; |
557 | | - $max_page = ceil( $found / $wgSphinxSearch_matches ); |
558 | | - $center_page = floor( ( $this->page + $display_pages ) / 2 ); |
559 | | - $first_page = $center_page - $display_pages / 2; |
560 | | - if ( $first_page < 1 ) { |
561 | | - $first_page = 1; |
562 | | - } |
563 | | - $last_page = $first_page + $display_pages - 1; |
564 | | - if ( $last_page > $max_page ) { |
565 | | - $last_page = $max_page; |
566 | | - } |
567 | | - if ( $first_page != $last_page ) { |
568 | | - $wgOut->addWikiText( "----" ); |
569 | | - $wgOut->addHTML( "<center> |
570 | | - <table border='0' cellpadding='0' width='1%' cellspacing='0'> |
571 | | - <tr align='center' valign='top'> |
572 | | - <td valign='bottom' nowrap='1'>" . wfMsg( 'sphinxResultPage' ) . "</td>" ); |
573 | | - |
574 | | - if ( $first_page > 1 ) { |
575 | | - $prev_page = "<td> <a href='{$qry}"; |
576 | | - $prev_page .= ( $this->page - 1 ) . "'>" . wfMsg( 'sphinxPreviousPage' ) . "</a> </td>"; |
577 | | - $wgOut->addHTML( $prev_page ); |
578 | | - } |
579 | | - for ( $i = $first_page; $i < $this->page; $i++ ) { |
580 | | - $wgOut->addHTML( "<td> <a href='{$qry}{$i}'>{$i}</a> </td>" ); |
581 | | - } |
582 | | - $wgOut->addHTML( "<td> <b>{$this->page}</b> </td>" ); |
583 | | - for ( $i = $this->page + 1; $i <= $last_page; $i++ ) { |
584 | | - $wgOut->addHTML( "<td> <a href='{$qry}{$i}'>{$i}</a> </td>" ); |
585 | | - } |
586 | | - if ( $last_page < $max_page ) { |
587 | | - $next_page = "<td> <a href='{$qry}"; |
588 | | - $next_page .= ( $this->page + 1 ) . "'>" . wfMsg( 'sphinxNextPage' ) . "</a> </td>"; |
589 | | - $wgOut->addHTML( $next_page ); |
590 | | - } |
591 | | - |
592 | | - $wgOut->addHTML( "</tr></table></center>" ); |
593 | | - } |
594 | | - } |
595 | | - |
596 | | - function createNewSearchForm( $term ) { |
597 | | - global $wgOut, $wgDisableInternalSearch, $wgSphinxSearch_mode, $wgSphinxMatchAll, |
598 | | - $wgUseExcludes, $wgUseAjax, $wgJsMimeType, $wgScriptPath, |
599 | | - $wgSphinxSearchExtPath, $wgSphinxSearchJSPath, $wgRequest; |
600 | | - |
601 | | - $search_title = ( $wgDisableInternalSearch ? 'Search' : 'SphinxSearch' ); |
602 | | - $titleObj = SpecialPage::getTitleFor( $search_title ); |
603 | | - $kiAction = $titleObj->getLocalUrl(); |
604 | | - $searchField = strtolower( $search_title ); |
605 | | - $wgOut->addHTML( "<form action='$kiAction' method='GET'> |
606 | | - <input type='hidden' name='title' value='" . $titleObj->getPrefixedText() . "'> |
607 | | - <input type='text' name='$searchField' maxlength='100' value='$term'> |
608 | | - <input type='submit' name='fulltext' value='" . wfMsg( 'sphinxSearchButton' ) . "'>" ); |
609 | | - |
610 | | - $wgOut->addHTML( "<div style='margin:0.5em 0 0.5em 0;'>" ); |
611 | | - if ( $wgSphinxSearch_mode == SPH_MATCH_EXTENDED ) { |
612 | | - $wgOut->addHTML( "<input type='radio' name='match_all' value='0' " . |
613 | | - ( $wgSphinxMatchAll ? "" : "checked='checked'" ) . " />" . |
614 | | - wfMsg( 'sphinxMatchAny' ) . |
615 | | - " <input type='radio' name='match_all' value='1' " . |
616 | | - ( $wgSphinxMatchAll ? "checked='checked'" : "" ) . " />" . |
617 | | - wfMsg( 'sphinxMatchAll' ) |
618 | | - ); |
619 | | - } |
620 | | - $wgOut->addHTML( "   <input type='checkbox' name='match_titles' value='1' " . |
621 | | - ( $wgRequest->getInt( 'match_titles' ) ? "checked='checked'" : "" ) . ">" . |
622 | | - wfMsg( 'sphinxMatchTitles' ) . "</div>" |
623 | | - ); |
624 | | - # get user settings for which namespaces to search |
625 | | - $wgOut->addHTML( "<div style='width:30%; border:1px #eee solid; padding:4px; margin-right:1px; float:left;'>" ); |
626 | | - $wgOut->addHTML( wfMsg( 'sphinxSearchInNamespaces' ) . '<br />' ); |
627 | | - $all_namespaces = self::searchableNamespaces(); |
628 | | - foreach ( $all_namespaces as $ns => $name ) { |
629 | | - $checked = in_array( $ns, $this->namespaces ) ? ' checked="checked"' : ''; |
630 | | - $name = str_replace( '_', ' ', $name ); |
631 | | - if ( '' == $name ) { |
632 | | - $name = wfMsg( 'blanknamespace' ); |
633 | | - } |
634 | | - $wgOut->addHTML( "<label><input type='checkbox' value='1' name='ns$ns'$checked />$name</label><br />" ); |
635 | | - } |
636 | | - |
637 | | - $all_categories = self::searchableCategories(); |
638 | | - if ( is_array( $all_categories ) && count( $all_categories ) ) { |
639 | | - $cat_parents = $wgRequest->getIntArray( "catp", array() ); |
640 | | - $wgOut->addScript( Skin::makeVariablesScript( array( |
641 | | - 'sphinxLoadingMsg' => wfMsg( 'sphinxLoading' ), |
642 | | - 'wgSphinxSearchExtPath' => ( $wgSphinxSearchJSPath ? $wgSphinxSearchJSPath : $wgSphinxSearchExtPath ) |
643 | | - ) ) ); |
644 | | - $wgOut->addScript( |
645 | | - "<script type='{$wgJsMimeType}' src='" . |
646 | | - ( $wgSphinxSearchJSPath ? $wgSphinxSearchJSPath : $wgSphinxSearchExtPath ) . |
647 | | - "/SphinxSearch.js?2'></script>\n" |
648 | | - ); |
649 | | - $wgOut->addHTML( "</div> |
650 | | - <div style='width:30%; border:1px #eee solid; padding:4px; margin-right:1px; float:left;'>" |
651 | | - ); |
652 | | - $wgOut->addHTML( wfMsg('sphinxSearchInCategories') ); |
653 | | - if ( $wgUseExcludes ) { |
654 | | - $wgOut->addHTML("<div style='float:right; font-size:80%;'>exclude</div>"); |
655 | | - } |
656 | | - $wgOut->addHTML('<br />'); |
657 | | - $wgOut->addHTML( $this->getCategoryCheckboxes( $all_categories, '', $cat_parents ) ); |
658 | | - } |
659 | | - $wgOut->addHTML( "</div></form><br clear='both' />" ); |
660 | | - |
661 | | - # Put a Sphinx label for this search |
662 | | - $wgOut->addHTML( "<div style='text-align:center'>" . |
663 | | - wfMsg( 'sphinxPowered', "<a href='http://www.sphinxsearch.com/'>Sphinx</a>" ) . |
664 | | - "</div>" |
665 | | - ); |
666 | | - } |
667 | | - |
668 | | - function getCategoryCheckboxes( $all_categories, $parent_id, $cat_parents = array() ) { |
669 | | - global $wgUseAjax, $wgRequest, $wgUseExcludes; |
670 | | - |
671 | | - $html = ''; |
672 | | - |
673 | | - foreach ( $all_categories as $cat => $name ) { |
674 | | - $input_attrs = ''; |
675 | | - if ( $this && in_array( $cat, $this->categories ) ) { |
676 | | - $input_attrs .= ' checked="checked"'; |
677 | | - } |
678 | | - $name = str_replace( '_', ' ', $name ); |
679 | | - if ( '' == $name ) { |
680 | | - $name = wfMsg( 'blanknamespace' ); |
681 | | - } |
682 | | - $children = ''; |
683 | | - if ( isset( $cat_parents['_' . $cat] ) && ( $input_attrs || $cat_parents['_' . $cat] > 0 ) ) { |
684 | | - $title = Title::newFromID( $cat ); |
685 | | - $children_cats = self::getChildrenCategories( $title->getDBkey() ); |
686 | | - if ( count( $children_cats ) ) { |
687 | | - if ( $this ) { |
688 | | - $children = $this->getCategoryCheckboxes( $children_cats, $cat, $cat_parents ); |
689 | | - } else { |
690 | | - $children = self::getCategoryCheckboxes( $children_cats, $cat, $cat_parents ); |
691 | | - } |
692 | | - } |
693 | | - } |
694 | | - if ( $wgUseAjax ) { |
695 | | - $input_attrs .= " onmouseup='sphinxShowCats(this)'"; |
696 | | - } |
697 | | - $html .= "<label><input type='checkbox' id='{$parent_id}_$cat' value='$cat' name='cat[]'$input_attrs />$name</label>"; |
698 | | - if ( $wgUseExcludes ) { |
699 | | - $input_attrs = ''; |
700 | | - if ( $this && in_array( $cat, $this->exc_categories ) ) { |
701 | | - $input_attrs .= ' checked="checked"'; |
702 | | - } |
703 | | - if ( $wgUseAjax ) { |
704 | | - $input_attrs .= " onmouseup='sphinxShowCats(this)'"; |
705 | | - } |
706 | | - $html .= "<input type='checkbox' id='exc_{$parent_id}_$cat' value='$cat' name='exc[]'$input_attrs style='float:right' />"; |
707 | | - } |
708 | | - $html .= "<div id='cat{$cat}_children'>$children</div>\n"; |
709 | | - } |
710 | | - if ( $parent_id && $html ) { |
711 | | - $html = "<input type='hidden' name='catp[_$parent_id]' value='" . |
712 | | - intval( $cat_parents['_' . $parent_id] ) . |
713 | | - "' /><div style='margin-left:10px; margin-bottom:4px; padding-left:8px; border-left:1px dashed #ccc; border-bottom:1px solid #ccc;'>" . |
714 | | - $html . "</div>"; |
715 | | - } |
716 | | - return $html; |
717 | | - } |
718 | | - |
719 | | - function spell() { |
720 | | - $string = str_replace( '"', '', $this->search_term ); |
721 | | - $words = preg_split( '/(\s+|\|)/', $string, -1, PREG_SPLIT_NO_EMPTY ); |
722 | | - if ( function_exists( 'pspell_check' ) ) { |
723 | | - $suggestion = $this->builtin_spell($words); |
724 | | - } else { |
725 | | - $suggestion = $this->nonnative_spell($words); |
726 | | - } |
727 | | - return $suggestion; |
728 | | - } |
729 | | - |
730 | | - function builtin_spell($words) { |
731 | | - global $wgUser, $wgSphinxSearchPersonalDictionary, $wgSphinxSearchPspellDictionaryDir; |
732 | | - |
733 | | - $ret = ''; |
734 | | - $suggestion_needed = false; |
735 | | - foreach ( $words as $word ) { |
736 | | - $pspell_config = pspell_config_create( |
737 | | - $wgUser->getDefaultOption( 'language' ), |
738 | | - $wgUser->getDefaultOption( 'variant' ) |
739 | | - ); |
740 | | - if ( $wgSphinxSearchPspellDictionaryDir ) { |
741 | | - pspell_config_data_dir( $pspell_config, $wgSphinxSearchPspellDictionaryDir ); |
742 | | - pspell_config_dict_dir( $pspell_config, $wgSphinxSearchPspellDictionaryDir ); |
743 | | - } |
744 | | - pspell_config_mode( $pspell_config, PSPELL_FAST | PSPELL_RUN_TOGETHER ); |
745 | | - if ( $wgSphinxSearchPersonalDictionary ) { |
746 | | - pspell_config_personal( $pspell_config, $wgSphinxSearchPersonalDictionary ); |
747 | | - } |
748 | | - $pspell_link = pspell_new_config( $pspell_config ); |
749 | | - |
750 | | - if ( !$pspell_link ) { |
751 | | - return wfMsg( 'sphinxPspellError' ); |
752 | | - } |
753 | | - if ( !pspell_check( $pspell_link, $word ) ) { |
754 | | - $suggestions = pspell_suggest( $pspell_link, $word ); |
755 | | - if ( count( $suggestions ) ) { |
756 | | - $guess = array_shift($suggestions); |
757 | | - } else { |
758 | | - $guess = ''; |
759 | | - } |
760 | | - if ( !$guess || (strtolower( $word ) == strtolower( $guess )) ) { |
761 | | - $ret .= "$word "; |
762 | | - } else { |
763 | | - $ret .= "$guess "; |
764 | | - $suggestion_needed = true; |
765 | | - } |
766 | | - } else { |
767 | | - $ret .= "$word "; |
768 | | - } |
769 | | - } |
770 | | - |
771 | | - return ( $suggestion_needed ? trim( $ret ) : '' ); |
772 | | - } |
773 | | - |
774 | | - function nonnative_spell($words) { |
775 | | - global $wgUser, $wgSphinxSearchPersonalDictionary, $wgSphinxSearchAspellPath; |
776 | | - |
777 | | - // aspell will only return mis-spelled words, so remember all here |
778 | | - $word_suggestions = array(); |
779 | | - foreach ( $words as $word ) { |
780 | | - $word_suggestions[$word] = $word; |
781 | | - } |
782 | | - |
783 | | - // prepare the system call with optional dictionary |
784 | | - $aspellcommand = 'echo ' . escapeshellarg( join( ' ', $words ) ) . |
785 | | - ' | ' . escapeshellarg( $wgSphinxSearchAspellPath ) . |
786 | | - ' -a --ignore-accents --ignore-case'; |
787 | | - if ( $wgUser ) { |
788 | | - $aspellcommand .= ' --lang=' . $wgUser->getDefaultOption( 'language' ); |
789 | | - } |
790 | | - if ( $wgSphinxSearchPersonalDictionary ) { |
791 | | - $aspellcommand .= ' --home-dir=' . dirname( $wgSphinxSearchPersonalDictionary ); |
792 | | - $aspellcommand .= ' -p ' . basename( $wgSphinxSearchPersonalDictionary ); |
793 | | - } |
794 | | - |
795 | | - // run aspell |
796 | | - $shell_return = shell_exec( $aspellcommand ); |
797 | | - |
798 | | - // parse return line by line |
799 | | - $returnarray = explode( "\n", $shell_return ); |
800 | | - $suggestion_needed = false; |
801 | | - foreach ( $returnarray as $key => $value ) { |
802 | | - // lines with suggestions start with & |
803 | | - if ( substr( $value, 0, 1 ) == "&" ) { |
804 | | - $correction = explode( " ", $value ); |
805 | | - $word = $correction[1]; |
806 | | - $suggestions = substr( $value, strpos( $value, ":" ) + 2 ); |
807 | | - $suggestions = explode( ", ", $suggestions ); |
808 | | - if (count($suggestions)) { |
809 | | - $guess = array_shift($suggestions); |
810 | | - if ( strtolower( $word ) != strtolower( $guess ) ) { |
811 | | - $word_suggestions[$word] = $guess; |
812 | | - $suggestion_needed = true; |
813 | | - } |
814 | | - } |
815 | | - } |
816 | | - } |
817 | | - |
818 | | - return ( $suggestion_needed ? join( ' ', $word_suggestions ) : '' ); |
819 | | - } |
820 | | - |
821 | | -} |
822 | | - |
823 | | -/** |
824 | | - * @ingroup Search |
825 | | - */ |
826 | | -class SphinxSearchResultSet extends SearchResultSet { |
827 | | - var $mNdx = 0; |
828 | | - |
829 | | - function __construct( $term, $rs, $cl ) { |
830 | | - global $wgSphinxSearch_index; |
831 | | - |
832 | | - $this->mResultSet = array(); |
833 | | - if ( is_array( $rs ) && is_array( $rs['matches'] ) ) { |
834 | | - $dbr = wfGetDB( DB_SLAVE ); |
835 | | - foreach ( $rs['matches'] as $id => $docinfo ) { |
836 | | - $res = $dbr->select( |
837 | | - 'page', |
838 | | - array( 'page_id', 'page_title', 'page_namespace' ), |
839 | | - array( 'page_id' => $id ), |
840 | | - __METHOD__, |
841 | | - array() |
842 | | - ); |
843 | | - if ( $dbr->numRows( $res ) > 0 ) { |
844 | | - $this->mResultSet[] = $dbr->fetchObject( $res ); |
845 | | - } |
846 | | - } |
847 | | - } |
848 | | - $this->mNdx = 0; |
849 | | - $this->mTerms = $term; |
850 | | - } |
851 | | - |
852 | | - function termMatches() { |
853 | | - return $this->mTerms; |
854 | | - } |
855 | | - |
856 | | - function numRows() { |
857 | | - return count( $this->mResultSet ); |
858 | | - } |
859 | | - |
860 | | - function next() { |
861 | | - if ( isset( $this->mResultSet[$this->mNdx] ) ) { |
862 | | - $row = $this->mResultSet[$this->mNdx]; |
863 | | - ++$this->mNdx; |
864 | | - return new SearchResult( $row ); |
865 | | - } else { |
866 | | - return false; |
867 | | - } |
868 | | - } |
869 | | - |
870 | | - function free() { |
871 | | - unset( $this->mResultSet ); |
872 | | - } |
873 | | -} |
Index: trunk/extensions/SphinxSearch/SphinxSearch.js |
— | — | @@ -1,54 +0,0 @@ |
2 | | -function sphinxShowCats(input) { |
3 | | - |
4 | | - var parent_id = input.id.substring(0, input.id.indexOf('_')); |
5 | | - var delta = (input.checked ? -1 : 1); |
6 | | - var parent_fld = input.form['catp[_' + parent_id + ']']; |
7 | | - var seen_parents = []; |
8 | | - seen_parents[parent_id] = true; |
9 | | - var cnt = input.form.elements.length; |
10 | | - |
11 | | - while (parent_fld) { |
12 | | - var parent_cnt = parseInt(parent_fld.value); |
13 | | - if (isNaN(parent_cnt)) { |
14 | | - parent_cnt = 0; |
15 | | - } |
16 | | - parent_fld.value = parent_cnt + delta; |
17 | | - parent_fld = null; |
18 | | - for (var i = 0; i < cnt; i++) { |
19 | | - var el = input.form.elements[i]; |
20 | | - if (el.name.indexOf('catp') == 0) { |
21 | | - var grandparent_id = el.name.replace(/[^\d]+/g, ''); |
22 | | - if (seen_parents[grandparent_id]) { |
23 | | - continue; |
24 | | - } |
25 | | - if (document.getElementById(grandparent_id + '_' + parent_id)) { |
26 | | - parent_fld = input.form['catp[_' + grandparent_id + ']']; |
27 | | - seen_parents[grandparent_id] = true; |
28 | | - } |
29 | | - } |
30 | | - } |
31 | | - } |
32 | | - |
33 | | - if (input.checked) { |
34 | | - return; |
35 | | - } |
36 | | - |
37 | | - var div = document.getElementById('cat' + input.value + '_children'); |
38 | | - if (div.innerHTML.length > 10) { |
39 | | - return; |
40 | | - } |
41 | | - |
42 | | - injectSpinner( input, 'sphinxsearch' ); |
43 | | - |
44 | | - function f( request ) { |
45 | | - var result = request.responseText; |
46 | | - |
47 | | - if (request.status != 200) { |
48 | | - result = "<div class='error'> " + request.status + " " + request.statusText + ": " + result + "</div>"; |
49 | | - } |
50 | | - removeSpinner( 'sphinxsearch' ); |
51 | | - div.innerHTML = result; |
52 | | - } |
53 | | - |
54 | | - sajax_do_call( "SphinxSearch::ajaxGetCategoryChildren", [input.value] , f ); |
55 | | -} |
\ No newline at end of file |
Index: trunk/extensions/SphinxSearch/SphinxSearch.php |
— | — | @@ -11,7 +11,7 @@ |
12 | 12 | |
13 | 13 | $wgExtensionCredits['specialpage'][] = array( |
14 | 14 | 'path' => __FILE__, |
15 | | - 'version' => '0.7.2', |
| 15 | + 'version' => '0.8.0', |
16 | 16 | 'name' => 'SphinxSearch', |
17 | 17 | 'author' => array( 'Svemir Brkic', 'Paul Grinberg' ), |
18 | 18 | 'email' => 'svemir at deveblog dot com, gri6507 at yahoo dot com', |
— | — | @@ -26,20 +26,16 @@ |
27 | 27 | # To completely disable the default search and replace it with SphinxSearch, |
28 | 28 | # set this BEFORE including SphinxSearch.php in LocalSettings.php |
29 | 29 | # $wgSearchType = 'SphinxSearch'; |
| 30 | + |
| 31 | +# prior to version 0.8.0 there was a SphinxSearch search type |
| 32 | +if ( $wgSearchType == 'SphinxSearch' ) { |
| 33 | + $wgSearchType == 'SphinxMWSearch'; |
| 34 | +} |
| 35 | + |
30 | 36 | # To use the new approach (added in 0.7.2) set it to SphinxMWSearch |
31 | 37 | if ( $wgSearchType == 'SphinxMWSearch' ) { |
32 | 38 | $wgAutoloadClasses['SphinxMWSearch'] = $dir . 'SphinxMWSearch.php'; |
33 | | -} else { |
34 | | - $wgAutoloadClasses['SphinxSearch'] = $dir . 'SphinxSearch_body.php'; |
35 | | - if ( $wgSearchType == 'SphinxSearch' ) { |
36 | | - $wgDisableInternalSearch = true; |
37 | | - $wgDisableSearchUpdate = true; |
38 | | - $wgSpecialPages['Search'] = 'SphinxSearch'; |
39 | | - $wgDisableSearchUpdate = true; |
40 | | - } else { |
41 | | - $wgExtensionAliasesFiles['SphinxSearch'] = $dir . 'SphinxSearch.alias.php'; |
42 | | - $wgSpecialPages['SphinxSearch'] = 'SphinxSearch'; |
43 | | - } |
| 39 | + $wgDisableSearchUpdate = true; |
44 | 40 | } |
45 | 41 | |
46 | 42 | # this assumes you have copied sphinxapi.php from your Sphinx |
— | — | @@ -50,7 +46,7 @@ |
51 | 47 | } |
52 | 48 | |
53 | 49 | # Host and port on which searchd deamon is running |
54 | | -$wgSphinxSearch_host = 'localhost'; |
| 50 | +$wgSphinxSearch_host = '127.0.0.1'; |
55 | 51 | $wgSphinxSearch_port = 9312; |
56 | 52 | |
57 | 53 | # Main sphinx.conf index to search |
— | — | @@ -76,38 +72,9 @@ |
77 | 73 | $wgSphinxSearch_sortmode = SPH_SORT_RELEVANCE; |
78 | 74 | $wgSphinxSearch_sortby = ''; |
79 | 75 | |
80 | | -if ( $wgSearchType == 'SphinxMWSearch' ) { |
81 | | - # Following settings apply only in the new search model |
| 76 | +# Set to true to use MW's default search snippets and highlighting |
| 77 | +$wgSphinxSearchMWHighlighter = false; |
82 | 78 | |
83 | | - # Set to true to use MW's default search snippets and highlighting |
84 | | - $wgSphinxSearchMWHighlighter = false; |
85 | | -} else { |
86 | | - # Following settings apply only in the old search model |
87 | | - |
88 | | - # By default, search will return articles that match any of the words in the search |
89 | | - # To change that to require all words to match by default, set the following to true |
90 | | - $wgSphinxMatchAll = false; |
91 | | - |
92 | | - # Number of matches to display at once |
93 | | - $wgSphinxSearch_matches = 10; |
94 | | - |
95 | | - # To enable hierarchical category search, specify the top category of your hierarchy |
96 | | - $wgSphinxTopSearchableCategory = ''; |
97 | | - |
98 | | - # This will fetch sub-categories as parent categories are checked |
99 | | - # Requires $wgUseAjax to be true |
100 | | - $wgAjaxExportList[] = 'SphinxSearch::ajaxGetCategoryChildren'; |
101 | | - |
102 | | - # Allow excluding selected categories when filtering |
103 | | - $wgUseExcludes = false; |
104 | | - |
105 | | - # Web-accessible path to the extension's folder |
106 | | - $wgSphinxSearchExtPath = $wgScriptPath . '/extensions/SphinxSearch'; |
107 | | - |
108 | | - # Web-accessible path to the folder with SphinxSearch.js file (if different from $wgSphinxSearchExtPath) |
109 | | - $wgSphinxSearchJSPath = ''; |
110 | | -} |
111 | | - |
112 | 79 | # ######################################################### |
113 | 80 | # Use Aspell to suggest possible misspellings. This can be provided via |
114 | 81 | # PHP pspell module (http://www.php.net/manual/en/ref.pspell.php) |