| Index: trunk/phase3/docs/hooks.txt |
| — | — | @@ -1665,6 +1665,18 @@ |
| 1666 | 1666 | 'SpecialSearchProfiles': allows modification of search profiles |
| 1667 | 1667 | &$profiles: profiles, which can be modified. |
| 1668 | 1668 | |
| | 1669 | +'SpecialSearchProfileForm': allows modification of search profile forms |
| | 1670 | +$search: special page object |
| | 1671 | +&$form: String: form html |
| | 1672 | +$profile: String: current search profile |
| | 1673 | +$term: String: search term |
| | 1674 | +$opts: Array: key => value of hidden options for inclusion in custom forms |
| | 1675 | + |
| | 1676 | +'SpecialSearchSetupEngine': allows passing custom data to search engine |
| | 1677 | +$search: special page object |
| | 1678 | +$profile: String: current search profile |
| | 1679 | +$engine: the search engine |
| | 1680 | + |
| 1669 | 1681 | 'SpecialSearchResults': called before search result display when there |
| 1670 | 1682 | are matches |
| 1671 | 1683 | $term: string of search term |
| Index: trunk/phase3/includes/search/SearchEngine.php |
| — | — | @@ -22,6 +22,9 @@ |
| 23 | 23 | var $namespaces = array( NS_MAIN ); |
| 24 | 24 | var $showRedirects = false; |
| 25 | 25 | |
| | 26 | + /// Feature values |
| | 27 | + protected $features = array(); |
| | 28 | + |
| 26 | 29 | /** |
| 27 | 30 | * @var DatabaseBase |
| 28 | 31 | */ |
| — | — | @@ -59,12 +62,41 @@ |
| 60 | 63 | return null; |
| 61 | 64 | } |
| 62 | 65 | |
| 63 | | - /** If this search backend can list/unlist redirects */ |
| | 66 | + /** |
| | 67 | + * If this search backend can list/unlist redirects |
| | 68 | + * @deprecated Call supports( 'list-redirects' ); |
| | 69 | + */ |
| 64 | 70 | function acceptListRedirects() { |
| 65 | | - return true; |
| | 71 | + return $this->supports( 'list-redirects' ); |
| 66 | 72 | } |
| 67 | 73 | |
| 68 | 74 | /** |
| | 75 | + * @since 1.18 |
| | 76 | + * @param $feature String |
| | 77 | + * @return Boolean |
| | 78 | + */ |
| | 79 | + public function supports( $feature ) { |
| | 80 | + switch( $feature ) { |
| | 81 | + case 'list-redirects': |
| | 82 | + return true; |
| | 83 | + case 'title-suffix-filter': |
| | 84 | + default: |
| | 85 | + return false; |
| | 86 | + } |
| | 87 | + } |
| | 88 | + |
| | 89 | + /** |
| | 90 | + * Way to pass custom data for engines |
| | 91 | + * @since 1.18 |
| | 92 | + * @param $feature String |
| | 93 | + * @param $data Mixed |
| | 94 | + * @return Noolean |
| | 95 | + */ |
| | 96 | + public function setFeatureData( $feature, $data ) { |
| | 97 | + $this->features[$feature] = $data; |
| | 98 | + } |
| | 99 | + |
| | 100 | + /** |
| 69 | 101 | * When overridden in derived class, performs database-specific conversions |
| 70 | 102 | * on text to be used for searching or updating search index. |
| 71 | 103 | * Default implementation does nothing (simply returns $string). |
| Index: trunk/phase3/includes/search/SearchMySQL.php |
| — | — | @@ -199,15 +199,28 @@ |
| 200 | 200 | return new MySQLSearchResultSet( $resultSet, $this->searchTerms, $total ); |
| 201 | 201 | } |
| 202 | 202 | |
| | 203 | + public function supports( $feature ) { |
| | 204 | + switch( $feature ) { |
| | 205 | + case 'list-redirects': |
| | 206 | + case 'title-suffix-filter': |
| | 207 | + return true; |
| | 208 | + default: |
| | 209 | + return false; |
| | 210 | + } |
| | 211 | + } |
| 203 | 212 | |
| 204 | 213 | /** |
| 205 | | - * Add redirect conditions |
| | 214 | + * Add special conditions |
| 206 | 215 | * @param $query Array |
| 207 | | - * @since 1.18 (changed) |
| | 216 | + * @since 1.18 |
| 208 | 217 | */ |
| 209 | | - function queryRedirect( &$query ) { |
| 210 | | - if( !$this->showRedirects ) { |
| 211 | | - $query['conds']['page_is_redirect'] = 0; |
| | 218 | + protected function queryFeatures( &$query ) { |
| | 219 | + foreach ( $this->features as $feature => $value ) { |
| | 220 | + if ( $feature === 'list-redirects' && !$value ) { |
| | 221 | + $query['conds']['page_is_redirect'] = 0; |
| | 222 | + } elseif( $feature === 'title-suffix-filter' && $value ) { |
| | 223 | + $query['conds'][] = 'page_title' . $this->db->buildLike( $this->db->anyString(), $value ); |
| | 224 | + } |
| 212 | 225 | } |
| 213 | 226 | } |
| 214 | 227 | |
| — | — | @@ -253,7 +266,7 @@ |
| 254 | 267 | ); |
| 255 | 268 | |
| 256 | 269 | $this->queryMain( $query, $filteredTerm, $fulltext ); |
| 257 | | - $this->queryRedirect( $query ); |
| | 270 | + $this->queryFeatures( $query ); |
| 258 | 271 | $this->queryNamespaces( $query ); |
| 259 | 272 | $this->limitResult( $query ); |
| 260 | 273 | |
| — | — | @@ -301,7 +314,7 @@ |
| 302 | 315 | 'joins' => array(), |
| 303 | 316 | ); |
| 304 | 317 | |
| 305 | | - $this->queryRedirect( $query ); |
| | 318 | + $this->queryFeatures( $query ); |
| 306 | 319 | $this->queryNamespaces( $query ); |
| 307 | 320 | |
| 308 | 321 | return $query; |
| Index: trunk/phase3/includes/specials/SpecialSearch.php |
| — | — | @@ -28,7 +28,14 @@ |
| 29 | 29 | * @ingroup SpecialPage |
| 30 | 30 | */ |
| 31 | 31 | class SpecialSearch extends SpecialPage { |
| | 32 | + /// Current search profile |
| | 33 | + protected $profile; |
| 32 | 34 | |
| | 35 | + /// Search engine |
| | 36 | + protected $searchEngine; |
| | 37 | + |
| | 38 | + const NAMESPACES_CURRENT = 'sense'; |
| | 39 | + |
| 33 | 40 | public function __construct() { |
| 34 | 41 | parent::__construct( 'Search' ); |
| 35 | 42 | } |
| — | — | @@ -75,14 +82,40 @@ |
| 76 | 83 | public function load( &$request, &$user ) { |
| 77 | 84 | list( $this->limit, $this->offset ) = $request->getLimitOffset( 20, 'searchlimit' ); |
| 78 | 85 | $this->mPrefix = $request->getVal('prefix', ''); |
| 79 | | - # Extract requested namespaces |
| 80 | | - $this->namespaces = $this->powerSearch( $request ); |
| 81 | | - if( empty( $this->namespaces ) ) { |
| 82 | | - $this->namespaces = SearchEngine::userNamespaces( $user ); |
| | 86 | + |
| | 87 | + |
| | 88 | + # Extract manually requested namespaces |
| | 89 | + $nslist = $this->powerSearch( $request ); |
| | 90 | + $this->profile = $profile = $request->getVal( 'profile', null ); |
| | 91 | + $profiles = $this->getSearchProfiles(); |
| | 92 | + if ( $profile === null) { |
| | 93 | + // BC with old request format |
| | 94 | + $this->profile = 'advanced'; |
| | 95 | + if ( count( $nslist ) ) { |
| | 96 | + foreach( $profiles as $key => $data ) { |
| | 97 | + if ( $nslist === $data['namespaces'] && $key !== 'advanced') { |
| | 98 | + $this->profile = $key; |
| | 99 | + } |
| | 100 | + } |
| | 101 | + $this->namespaces = $nslist; |
| | 102 | + } else { |
| | 103 | + $this->namespaces = SearchEngine::userNamespaces( $user ); |
| | 104 | + } |
| | 105 | + } elseif ( $profile === 'advanced' ) { |
| | 106 | + $this->namespaces = $nslist; |
| | 107 | + } else { |
| | 108 | + if ( isset( $profiles[$profile]['namespaces'] ) ) { |
| | 109 | + $this->namespaces = $profiles[$profile]['namespaces']; |
| | 110 | + } else { |
| | 111 | + // Unknown profile requested |
| | 112 | + $this->profile = 'default'; |
| | 113 | + $this->namespaces = $profiles['default']['namespaces']; |
| | 114 | + } |
| 83 | 115 | } |
| 84 | | - $this->searchRedirects = $request->getCheck( 'redirs' ); |
| 85 | | - $this->searchAdvanced = $request->getVal( 'advanced' ); |
| 86 | | - $this->active = 'advanced'; |
| | 116 | + |
| | 117 | + // Redirects defaults to true, but we don't know whether it was ticked of or just missing |
| | 118 | + $default = $request->getBool( 'profile' ) ? 0 : 1; |
| | 119 | + $this->searchRedirects = $request->getBool( 'redirs', $default ) ? 1 : 0; |
| 87 | 120 | $this->sk = $user->getSkin(); |
| 88 | 121 | $this->didYouMeanHtml = ''; # html of did you mean... link |
| 89 | 122 | $this->fulltext = $request->getVal('fulltext'); |
| — | — | @@ -139,14 +172,16 @@ |
| 140 | 173 | |
| 141 | 174 | $sk = $wgUser->getSkin(); |
| 142 | 175 | |
| 143 | | - $this->searchEngine = SearchEngine::create(); |
| 144 | | - $search =& $this->searchEngine; |
| | 176 | + $search = $this->getSearchEngine(); |
| 145 | 177 | $search->setLimitOffset( $this->limit, $this->offset ); |
| 146 | 178 | $search->setNamespaces( $this->namespaces ); |
| 147 | | - $search->showRedirects = $this->searchRedirects; |
| | 179 | + $search->showRedirects = $this->searchRedirects; // BC |
| | 180 | + $search->setFeatureData( 'list-redirects', $this->searchRedirects ); |
| 148 | 181 | $search->prefix = $this->mPrefix; |
| 149 | 182 | $term = $search->transformSearchTerm($term); |
| 150 | 183 | |
| | 184 | + wfRunHooks( 'SpecialSearchSetupEngine', array( $this, $this->profile, $search ) ); |
| | 185 | + |
| 151 | 186 | $this->setupPage( $term ); |
| 152 | 187 | |
| 153 | 188 | if( $wgDisableTextSearch ) { |
| — | — | @@ -216,7 +251,7 @@ |
| 217 | 252 | Xml::openElement( |
| 218 | 253 | 'form', |
| 219 | 254 | array( |
| 220 | | - 'id' => ( $this->searchAdvanced ? 'powersearch' : 'search' ), |
| | 255 | + 'id' => ( $this->profile === 'advanced' ? 'powersearch' : 'search' ), |
| 221 | 256 | 'method' => 'get', |
| 222 | 257 | 'action' => $wgScript |
| 223 | 258 | ) |
| — | — | @@ -225,7 +260,7 @@ |
| 226 | 261 | $wgOut->addHtml( |
| 227 | 262 | Xml::openElement( 'table', array( 'id'=>'mw-search-top-table', 'border'=>0, 'cellpadding'=>0, 'cellspacing'=>0 ) ) . |
| 228 | 263 | Xml::openElement( 'tr' ) . |
| 229 | | - Xml::openElement( 'td' ) . "\n" . |
| | 264 | + Xml::openElement( 'td' ) . "\n" . |
| 230 | 265 | $this->shortDialog( $term ) . |
| 231 | 266 | Xml::closeElement('td') . |
| 232 | 267 | Xml::closeElement('tr') . |
| — | — | @@ -241,10 +276,8 @@ |
| 242 | 277 | |
| 243 | 278 | $filePrefix = $wgContLang->getFormattedNsText(NS_FILE).':'; |
| 244 | 279 | if( trim( $term ) === '' || $filePrefix === trim( $term ) ) { |
| 245 | | - $wgOut->addHTML( $this->formHeader($term, 0, 0)); |
| 246 | | - if( $this->searchAdvanced ) { |
| 247 | | - $wgOut->addHTML( $this->powerSearchBox( $term ) ); |
| 248 | | - } |
| | 280 | + $wgOut->addHTML( $this->formHeader( $term, 0, 0 ) ); |
| | 281 | + $wgOut->addHtml( $this->getProfileForm( $this->profile, $term ) ); |
| 249 | 282 | $wgOut->addHTML( '</form>' ); |
| 250 | 283 | // Empty query -- straight view of search form |
| 251 | 284 | wfProfileOut( __METHOD__ ); |
| — | — | @@ -271,11 +304,10 @@ |
| 272 | 305 | $totalRes += $textMatches->getTotalHits(); |
| 273 | 306 | |
| 274 | 307 | // show number of results and current offset |
| 275 | | - $wgOut->addHTML( $this->formHeader($term, $num, $totalRes)); |
| 276 | | - if( $this->searchAdvanced ) { |
| 277 | | - $wgOut->addHTML( $this->powerSearchBox( $term ) ); |
| 278 | | - } |
| | 308 | + $wgOut->addHTML( $this->formHeader( $term, $num, $totalRes ) ); |
| | 309 | + $wgOut->addHtml( $this->getProfileForm( $this->profile, $term ) ); |
| 279 | 310 | |
| | 311 | + |
| 280 | 312 | $wgOut->addHtml( Xml::closeElement( 'form' ) ); |
| 281 | 313 | $wgOut->addHtml( "<div class='searchresults'>" ); |
| 282 | 314 | |
| — | — | @@ -361,21 +393,10 @@ |
| 362 | 394 | */ |
| 363 | 395 | protected function setupPage( $term ) { |
| 364 | 396 | global $wgOut; |
| 365 | | - // Figure out the active search profile header |
| 366 | | - if( $this->searchAdvanced ) { |
| 367 | | - $this->active = 'advanced'; |
| 368 | | - } else { |
| 369 | | - $profiles = $this->getSearchProfiles(); |
| 370 | 397 | |
| 371 | | - foreach( $profiles as $key => $data ) { |
| 372 | | - if ( $this->namespaces == $data['namespaces'] && $key != 'advanced') |
| 373 | | - $this->active = $key; |
| 374 | | - } |
| 375 | | - |
| 376 | | - } |
| 377 | 398 | # Should advanced UI be used? |
| 378 | | - $this->searchAdvanced = ($this->active === 'advanced'); |
| 379 | | - if( !empty( $term ) ) { |
| | 399 | + $this->searchAdvanced = ($this->profile === 'advanced'); |
| | 400 | + if( strval( $term ) !== '' ) { |
| 380 | 401 | $wgOut->setPageTitle( wfMsg( 'searchresults') ); |
| 381 | 402 | $wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsg( 'searchresults-title', $term ) ) ); |
| 382 | 403 | } |
| — | — | @@ -398,6 +419,7 @@ |
| 399 | 420 | $arr[] = $ns; |
| 400 | 421 | } |
| 401 | 422 | } |
| | 423 | + |
| 402 | 424 | return $arr; |
| 403 | 425 | } |
| 404 | 426 | |
| — | — | @@ -412,8 +434,8 @@ |
| 413 | 435 | $opt['ns' . $n] = 1; |
| 414 | 436 | } |
| 415 | 437 | $opt['redirs'] = $this->searchRedirects ? 1 : 0; |
| 416 | | - if( $this->searchAdvanced ) { |
| 417 | | - $opt['advanced'] = $this->searchAdvanced; |
| | 438 | + if( $this->profile ) { |
| | 439 | + $opt['profile'] = $this->profile; |
| 418 | 440 | } |
| 419 | 441 | return $opt; |
| 420 | 442 | } |
| — | — | @@ -744,14 +766,28 @@ |
| 745 | 767 | return $out; |
| 746 | 768 | } |
| 747 | 769 | |
| | 770 | + protected function getProfileForm( $profile, $term ) { |
| | 771 | + // Hidden stuff |
| | 772 | + $opts = array(); |
| | 773 | + $opts['redirs'] = $this->searchRedirects; |
| | 774 | + $opts['profile'] = $this->profile; |
| 748 | 775 | |
| | 776 | + if ( $profile === 'advanced' ) { |
| | 777 | + return $this->powerSearchBox( $term, $opts ); |
| | 778 | + } else { |
| | 779 | + $form = ''; |
| | 780 | + wfRunHooks( 'SpecialSearchProfileForm', array( $this, &$form, $profile, $term, $opts ) ); |
| | 781 | + return $form; |
| | 782 | + } |
| | 783 | + } |
| | 784 | + |
| 749 | 785 | /** |
| 750 | | - * Generates the power search box at bottom of [[Special:Search]] |
| | 786 | + * Generates the power search box at [[Special:Search]] |
| 751 | 787 | * |
| 752 | 788 | * @param $term String: search term |
| 753 | 789 | * @return String: HTML form |
| 754 | 790 | */ |
| 755 | | - protected function powerSearchBox( $term ) { |
| | 791 | + protected function powerSearchBox( $term, $opts ) { |
| 756 | 792 | // Groups namespaces into rows according to subject |
| 757 | 793 | $rows = array(); |
| 758 | 794 | foreach( SearchEngine::searchableNamespaces() as $namespace => $name ) { |
| — | — | @@ -793,14 +829,16 @@ |
| 794 | 830 | } |
| 795 | 831 | // Show redirects check only if backend supports it |
| 796 | 832 | $redirects = ''; |
| 797 | | - if( $this->searchEngine->acceptListRedirects() ) { |
| | 833 | + if( $this->getSearchEngine()->supports( 'list-redirects' ) ) { |
| 798 | 834 | $redirects = |
| 799 | | - Xml::check( |
| 800 | | - 'redirs', $this->searchRedirects, array( 'value' => '1', 'id' => 'redirs' ) |
| 801 | | - ) . |
| 802 | | - ' ' . |
| 803 | | - Xml::label( wfMsg( 'powersearch-redir' ), 'redirs' ); |
| | 835 | + Xml::checkLabel( wfMsg( 'powersearch-redir' ), 'redirs', 'redirs', $this->searchRedirects ); |
| 804 | 836 | } |
| | 837 | + |
| | 838 | + $hidden = ''; |
| | 839 | + unset( $opts['redirs'] ); |
| | 840 | + foreach( $opts as $key => $value ) { |
| | 841 | + $hidden .= Html::hidden( $key, $value ); |
| | 842 | + } |
| 805 | 843 | // Return final output |
| 806 | 844 | return |
| 807 | 845 | Xml::openElement( |
| — | — | @@ -835,10 +873,7 @@ |
| 836 | 874 | Xml::element( 'div', array( 'class' => 'divider' ), '', false ) . |
| 837 | 875 | $namespaceTables . |
| 838 | 876 | Xml::element( 'div', array( 'class' => 'divider' ), '', false ) . |
| 839 | | - $redirects . |
| 840 | | - Html::hidden( 'title', SpecialPage::getTitleFor( 'Search' )->getPrefixedText() ) . |
| 841 | | - Html::hidden( 'advanced', $this->searchAdvanced ) . |
| 842 | | - Html::hidden( 'fulltext', 'Advanced search' ) . |
| | 877 | + $redirects . $hidden . |
| 843 | 878 | Xml::closeElement( 'fieldset' ); |
| 844 | 879 | } |
| 845 | 880 | |
| — | — | @@ -876,15 +911,15 @@ |
| 877 | 912 | 'advanced' => array( |
| 878 | 913 | 'message' => 'searchprofile-advanced', |
| 879 | 914 | 'tooltip' => 'searchprofile-advanced-tooltip', |
| 880 | | - 'namespaces' => $this->namespaces, |
| 881 | | - 'parameters' => array( 'advanced' => 1 ), |
| | 915 | + 'namespaces' => self::NAMESPACES_CURRENT, |
| 882 | 916 | ) |
| 883 | 917 | ); |
| 884 | 918 | |
| 885 | 919 | wfRunHooks( 'SpecialSearchProfiles', array( &$profiles ) ); |
| 886 | 920 | |
| 887 | 921 | foreach( $profiles as &$data ) { |
| 888 | | - sort($data['namespaces']); |
| | 922 | + if ( !is_array( $data['namespaces'] ) ) continue; |
| | 923 | + sort( $data['namespaces'] ); |
| 889 | 924 | } |
| 890 | 925 | |
| 891 | 926 | return $profiles; |
| — | — | @@ -907,19 +942,24 @@ |
| 908 | 943 | $out .= Xml::openElement( 'div', array( 'class' => 'search-types' ) ); |
| 909 | 944 | $out .= Xml::openElement( 'ul' ); |
| 910 | 945 | foreach ( $profiles as $id => $profile ) { |
| | 946 | + if ( !isset( $profile['parameters'] ) ) { |
| | 947 | + $profile['parameters'] = array(); |
| | 948 | + } |
| | 949 | + $profile['parameters']['profile'] = $id; |
| | 950 | + |
| 911 | 951 | $tooltipParam = isset( $profile['namespace-messages'] ) ? |
| 912 | 952 | $wgLang->commaList( $profile['namespace-messages'] ) : null; |
| 913 | 953 | $out .= Xml::tags( |
| 914 | 954 | 'li', |
| 915 | 955 | array( |
| 916 | | - 'class' => $this->active == $id ? 'current' : 'normal' |
| | 956 | + 'class' => $this->profile === $id ? 'current' : 'normal' |
| 917 | 957 | ), |
| 918 | 958 | $this->makeSearchLink( |
| 919 | 959 | $bareterm, |
| 920 | | - $profile['namespaces'], |
| | 960 | + array(), |
| 921 | 961 | wfMsg( $profile['message'] ), |
| 922 | 962 | wfMsg( $profile['tooltip'], $tooltipParam ), |
| 923 | | - isset( $profile['parameters'] ) ? $profile['parameters'] : array() |
| | 963 | + $profile['parameters'] |
| 924 | 964 | ) |
| 925 | 965 | ); |
| 926 | 966 | } |
| — | — | @@ -949,24 +989,14 @@ |
| 950 | 990 | $out .= Xml::element( 'div', array( 'style' => 'clear:both' ), '', false ); |
| 951 | 991 | $out .= Xml::closeElement('div'); |
| 952 | 992 | |
| 953 | | - // Adds hidden namespace fields |
| 954 | | - if ( !$this->searchAdvanced ) { |
| 955 | | - foreach( $this->namespaces as $ns ) { |
| 956 | | - $out .= Html::hidden( "ns{$ns}", '1' ); |
| 957 | | - } |
| 958 | | - } |
| 959 | | - |
| 960 | 993 | return $out; |
| 961 | 994 | } |
| 962 | 995 | |
| 963 | 996 | protected function shortDialog( $term ) { |
| 964 | | - $searchTitle = SpecialPage::getTitleFor( 'Search' ); |
| 965 | | - $out = Html::hidden( 'title', $searchTitle->getPrefixedText() ) . "\n"; |
| 966 | | - // Keep redirect setting |
| 967 | | - $out .= Html::hidden( "redirs", (int)$this->searchRedirects ) . "\n"; |
| | 997 | + $out = Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n"; |
| 968 | 998 | // Term box |
| 969 | 999 | $out .= Html::input( 'search', $term, 'search', array( |
| 970 | | - 'id' => $this->searchAdvanced ? 'powerSearchText' : 'searchText', |
| | 1000 | + 'id' => $this->profile === 'advanced' ? 'powerSearchText' : 'searchText', |
| 971 | 1001 | 'size' => '50', |
| 972 | 1002 | 'autofocus' |
| 973 | 1003 | ) ) . "\n"; |
| — | — | @@ -979,20 +1009,19 @@ |
| 980 | 1010 | * Make a search link with some target namespaces |
| 981 | 1011 | * |
| 982 | 1012 | * @param $term String |
| 983 | | - * @param $namespaces Array |
| | 1013 | + * @param $namespaces Array ignored |
| 984 | 1014 | * @param $label String: link's text |
| 985 | 1015 | * @param $tooltip String: link's tooltip |
| 986 | 1016 | * @param $params Array: query string parameters |
| 987 | 1017 | * @return String: HTML fragment |
| 988 | 1018 | */ |
| 989 | | - protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params=array() ) { |
| | 1019 | + protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params = array() ) { |
| 990 | 1020 | $opt = $params; |
| 991 | 1021 | foreach( $namespaces as $n ) { |
| 992 | 1022 | $opt['ns' . $n] = 1; |
| 993 | 1023 | } |
| 994 | | - $opt['redirs'] = $this->searchRedirects ? 1 : 0; |
| | 1024 | + $opt['redirs'] = $this->searchRedirects; |
| 995 | 1025 | |
| 996 | | - $st = SpecialPage::getTitleFor( 'Search' ); |
| 997 | 1026 | $stParams = array_merge( |
| 998 | 1027 | array( |
| 999 | 1028 | 'search' => $term, |
| — | — | @@ -1004,7 +1033,7 @@ |
| 1005 | 1034 | return Xml::element( |
| 1006 | 1035 | 'a', |
| 1007 | 1036 | array( |
| 1008 | | - 'href' => $st->getLocalURL( $stParams ), |
| | 1037 | + 'href' => $this->getTitle()->getLocalURL( $stParams ), |
| 1009 | 1038 | 'title' => $tooltip, |
| 1010 | 1039 | 'onmousedown' => 'mwSearchHeaderClick(this);', |
| 1011 | 1040 | 'onkeydown' => 'mwSearchHeaderClick(this);'), |
| — | — | @@ -1044,4 +1073,14 @@ |
| 1045 | 1074 | } |
| 1046 | 1075 | return false; |
| 1047 | 1076 | } |
| | 1077 | + |
| | 1078 | + /** |
| | 1079 | + * @since 1.18 |
| | 1080 | + */ |
| | 1081 | + public function getSearchEngine() { |
| | 1082 | + if ( $this->searchEngine === null ) { |
| | 1083 | + $this->searchEngine = SearchEngine::create(); |
| | 1084 | + } |
| | 1085 | + return $this->searchEngine; |
| | 1086 | + } |
| 1048 | 1087 | } |
| Index: trunk/extensions/Translate/TranslateEditAddons.php |
| — | — | @@ -498,4 +498,64 @@ |
| 499 | 499 | $profiles = wfArrayInsertAfter( $profiles, $insert, 'help' ); |
| 500 | 500 | return true; |
| 501 | 501 | } |
| | 502 | + |
| | 503 | + public static function searchProfileForm( $search, &$form, $profile, $term, $opts ) { |
| | 504 | + if ( $profile !== 'translation' ) { |
| | 505 | + return true; |
| | 506 | + } |
| | 507 | + |
| | 508 | + if( !$search->getSearchEngine()->supports( 'title-suffix-filter' ) ) { |
| | 509 | + return false; |
| | 510 | + } |
| | 511 | + |
| | 512 | + $hidden = ''; |
| | 513 | + foreach( $opts as $key => $value ) { |
| | 514 | + $hidden .= Html::hidden( $key, $value ); |
| | 515 | + } |
| | 516 | + |
| | 517 | + $context = $search->getContext(); |
| | 518 | + $code = $context->getLang()->getCode(); |
| | 519 | + $selected = $context->getRequest()->getVal( 'languagefilter' ); |
| | 520 | + |
| | 521 | + if ( is_callable( array( 'LanguageNames', 'getNames' ) ) ) { |
| | 522 | + $languages = LanguageNames::getNames( $code, |
| | 523 | + LanguageNames::FALLBACK_NORMAL, |
| | 524 | + LanguageNames::LIST_MW |
| | 525 | + ); |
| | 526 | + } else { |
| | 527 | + $languages = Language::getLanguageNames( false ); |
| | 528 | + } |
| | 529 | + |
| | 530 | + ksort( $languages ); |
| | 531 | + |
| | 532 | + $selector = new HTMLSelector( 'languagefilter', 'languagefilter', $selected ); |
| | 533 | + $selector->addOption( wfMessage( 'translate-search-nofilter' ), '-' ); |
| | 534 | + foreach ( $languages as $code => $name ) { |
| | 535 | + $selector->addOption( "$code - $name", $code ); |
| | 536 | + } |
| | 537 | + |
| | 538 | + $selector = $selector->getHTML(); |
| | 539 | + |
| | 540 | + $label = Xml::label( wfMessage( 'translate-search-languagefilter' ), 'languagefilter' ) . ' '; |
| | 541 | + $params = array( 'id' => 'mw-searchoptions' ); |
| | 542 | + |
| | 543 | + $form = Xml::fieldset( false, false, $params ) . |
| | 544 | + $hidden . $label . $selector . |
| | 545 | + Html::closeElement( 'fieldset' ); |
| | 546 | + return false; |
| | 547 | + } |
| | 548 | + |
| | 549 | + public static function searchProfileSetupEngine( $search, $profile, $engine ) { |
| | 550 | + if ( $profile !== 'translation' ) { |
| | 551 | + return true; |
| | 552 | + } |
| | 553 | + |
| | 554 | + $context = $search->getContext(); |
| | 555 | + $selected = $context->getRequest()->getVal( 'languagefilter' ); |
| | 556 | + if ( $selected !== '-' && $selected ) { |
| | 557 | + $engine->setFeatureData( 'title-suffix-filter', "/$selected" ); |
| | 558 | + } |
| | 559 | + return true; |
| | 560 | + } |
| | 561 | + |
| 502 | 562 | } |
| Index: trunk/extensions/Translate/Translate.php |
| — | — | @@ -113,6 +113,8 @@ |
| 114 | 114 | |
| 115 | 115 | // Search profile |
| 116 | 116 | $wgHooks['SpecialSearchProfiles'][] = 'TranslateEditAddons::searchProfile'; |
| | 117 | +$wgHooks['SpecialSearchProfileForm'][] = 'TranslateEditAddons::searchProfileForm'; |
| | 118 | +$wgHooks['SpecialSearchSetupEngine'][] = 'TranslateEditAddons::searchProfileSetupEngine'; |
| 117 | 119 | |
| 118 | 120 | // New rights |
| 119 | 121 | $wgAvailableRights[] = 'translate'; |
| Index: trunk/extensions/Translate/Translate.i18n.php |
| — | — | @@ -361,6 +361,8 @@ |
| 362 | 362 | // Search profile hook |
| 363 | 363 | 'translate-searchprofile' => 'Translations', |
| 364 | 364 | 'translate-searchprofile-tooltip' => 'Search from all translations', |
| | 365 | + 'translate-search-languagefilter' => 'Filter by language:', |
| | 366 | + 'translate-search-nofilter' => 'No filtering', |
| 365 | 367 | ); |
| 366 | 368 | |
| 367 | 369 | /** Message documentation (Message documentation) |