diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2014-12-27 15:41:37 +0100 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2014-12-31 11:43:28 +0100 |
commit | c1f9b1f7b1b77776192048005dcc66dcf3df2bfb (patch) | |
tree | 2b38796e738dd74cb42ecd9bfd151803108386bc /includes/specials/SpecialSearch.php | |
parent | b88ab0086858470dd1f644e64cb4e4f62bb2be9b (diff) |
Update to MediaWiki 1.24.1
Diffstat (limited to 'includes/specials/SpecialSearch.php')
-rw-r--r-- | includes/specials/SpecialSearch.php | 661 |
1 files changed, 328 insertions, 333 deletions
diff --git a/includes/specials/SpecialSearch.php b/includes/specials/SpecialSearch.php index 8609c740..88ab7d82 100644 --- a/includes/specials/SpecialSearch.php +++ b/includes/specials/SpecialSearch.php @@ -30,25 +30,24 @@ class SpecialSearch extends SpecialPage { /** * Current search profile. Search profile is just a name that identifies - * the active search tab on the search page (content, help, discussions...) + * the active search tab on the search page (content, discussions...) * For users tt replaces the set of enabled namespaces from the query * string when applicable. Extensions can add new profiles with hooks * with custom search options just for that profile. - * null|string + * @var null|string */ protected $profile; - function getProfile() { return $this->profile; } - /// Search engine + /** @var SearchEngine Search engine */ protected $searchEngine; - /// Search engine type, if not default + /** @var string Search engine type, if not default */ protected $searchEngineType; - /// For links + /** @var array For links */ protected $extraParams = array(); - /// No idea, apparently used by some other classes + /** @var string No idea, apparently used by some other classes */ protected $mPrefix; /** @@ -60,12 +59,6 @@ class SpecialSearch extends SpecialPage { * @var array */ protected $namespaces; - function getNamespaces() { return $this->namespaces; } - - /** - * @var bool - */ - protected $searchRedirects; /** * @var string @@ -81,14 +74,17 @@ class SpecialSearch extends SpecialPage { /** * Entry point * - * @param string $par or null + * @param string $par */ public function execute( $par ) { $this->setHeaders(); $this->outputHeader(); $out = $this->getOutput(); $out->allowClickjacking(); - $out->addModuleStyles( 'mediawiki.special' ); + $out->addModuleStyles( array( + 'mediawiki.special', 'mediawiki.special.search', 'mediawiki.ui', 'mediawiki.ui.button', + 'mediawiki.ui.input', + ) ); // Strip underscores from title parameter; most of the time we'll want // text form here. But don't strip underscores from actual text params! @@ -100,13 +96,22 @@ class SpecialSearch extends SpecialPage { $search = str_replace( "\n", " ", $request->getText( 'search', $titleParam ) ); $this->load(); + if ( !is_null( $request->getVal( 'nsRemember' ) ) ) { + $this->saveNamespaces(); + // Remove the token from the URL to prevent the user from inadvertently + // exposing it (e.g. by pasting it into a public wiki page) or undoing + // later settings changes (e.g. by reloading the page). + $query = $request->getValues(); + unset( $query['title'], $query['nsRemember'] ); + $out->redirect( $this->getPageTitle()->getFullURL( $query ) ); + return; + } $this->searchEngineType = $request->getVal( 'srbackend' ); if ( $request->getVal( 'fulltext' ) || !is_null( $request->getVal( 'offset' ) ) - || !is_null( $request->getVal( 'searchx' ) ) ) - { + ) { $this->showResults( $search ); } else { $this->goResult( $search ); @@ -120,7 +125,7 @@ class SpecialSearch extends SpecialPage { */ public function load() { $request = $this->getRequest(); - list( $this->limit, $this->offset ) = $request->getLimitOffset( 20, 'searchlimit' ); + list( $this->limit, $this->offset ) = $request->getLimitOffset( 20, '' ); $this->mPrefix = $request->getVal( 'prefix', '' ); $user = $this->getUser(); @@ -160,9 +165,6 @@ class SpecialSearch extends SpecialPage { } } - // Redirects defaults to true, but we don't know whether it was ticked of or just missing - $default = $request->getBool( 'profile' ) ? 0 : 1; - $this->searchRedirects = $request->getBool( 'redirs', $default ) ? 1 : 0; $this->didYouMeanHtml = ''; # html of did you mean... link $this->fulltext = $request->getVal( 'fulltext' ); $this->profile = $profile; @@ -171,57 +173,44 @@ class SpecialSearch extends SpecialPage { /** * If an exact title match can be found, jump straight ahead to it. * - * @param $term String + * @param string $term */ public function goResult( $term ) { $this->setupPage( $term ); # Try to go to page as entered. - $t = Title::newFromText( $term ); + $title = Title::newFromText( $term ); # If the string cannot be used to create a title - if ( is_null( $t ) ) { + if ( is_null( $title ) ) { $this->showResults( $term ); + return; } # If there's an exact or very near match, jump right there. - $t = SearchEngine::getNearMatch( $term ); + $title = SearchEngine::getNearMatch( $term ); - if ( !wfRunHooks( 'SpecialSearchGo', array( &$t, &$term ) ) ) { - # Hook requested termination - return; - } + if ( !is_null( $title ) ) { + $this->getOutput()->redirect( $title->getFullURL() ); - if ( !is_null( $t ) ) { - $this->getOutput()->redirect( $t->getFullURL() ); return; } # No match, generate an edit URL - $t = Title::newFromText( $term ); - if ( !is_null( $t ) ) { - global $wgGoToEdit; - wfRunHooks( 'SpecialSearchNogomatch', array( &$t ) ); - wfDebugLog( 'nogomatch', $t->getText(), false ); - - # If the feature is enabled, go straight to the edit page - if ( $wgGoToEdit ) { - $this->getOutput()->redirect( $t->getFullURL( array( 'action' => 'edit' ) ) ); - return; - } + $title = Title::newFromText( $term ); + if ( !is_null( $title ) ) { + wfRunHooks( 'SpecialSearchNogomatch', array( &$title ) ); } $this->showResults( $term ); } /** - * @param $term String + * @param string $term */ public function showResults( $term ) { - global $wgDisableTextSearch, $wgSearchForwardUrl, $wgContLang, $wgScript; - wfProfileIn( __METHOD__ ); + global $wgContLang; + $profile = new ProfileSection( __METHOD__ ); $search = $this->getSearchEngine(); $search->setLimitOffset( $this->limit, $this->offset ); $search->setNamespaces( $this->namespaces ); - $search->showRedirects = $this->searchRedirects; // BC - $search->setFeatureData( 'list-redirects', $this->searchRedirects ); $search->prefix = $this->mPrefix; $term = $search->transformSearchTerm( $term ); @@ -231,15 +220,20 @@ class SpecialSearch extends SpecialPage { $out = $this->getOutput(); - if ( $wgDisableTextSearch ) { - if ( $wgSearchForwardUrl ) { - $url = str_replace( '$1', urlencode( $term ), $wgSearchForwardUrl ); + if ( $this->getConfig()->get( 'DisableTextSearch' ) ) { + $searchFowardUrl = $this->getConfig()->get( 'SearchForwardUrl' ); + if ( $searchFowardUrl ) { + $url = str_replace( '$1', urlencode( $term ), $searchFowardUrl ); $out->redirect( $url ); } else { $out->addHTML( Xml::openElement( 'fieldset' ) . Xml::element( 'legend', null, $this->msg( 'search-external' )->text() ) . - Xml::element( 'p', array( 'class' => 'mw-searchdisabled' ), $this->msg( 'searchdisabled' )->text() ) . + Xml::element( + 'p', + array( 'class' => 'mw-searchdisabled' ), + $this->msg( 'searchdisabled' )->text() + ) . $this->msg( 'googlesearch' )->rawParams( htmlspecialchars( $term ), 'UTF-8', @@ -248,19 +242,19 @@ class SpecialSearch extends SpecialPage { Xml::closeElement( 'fieldset' ) ); } - wfProfileOut( __METHOD__ ); + return; } - $t = Title::newFromText( $term ); + $title = Title::newFromText( $term ); + $showSuggestion = $title === null || !$title->isKnown(); + $search->setShowSuggestion( $showSuggestion ); // fetch search results $rewritten = $search->replacePrefixes( $term ); $titleMatches = $search->searchTitle( $rewritten ); - if ( !( $titleMatches instanceof SearchResultTooMany ) ) { - $textMatches = $search->searchText( $rewritten ); - } + $textMatches = $search->searchText( $rewritten ); $textStatus = null; if ( $textMatches instanceof Status ) { @@ -269,9 +263,7 @@ class SpecialSearch extends SpecialPage { } // did you mean... suggestions - if ( $textMatches && !$textStatus && $textMatches->hasSuggestion() ) { - $st = SpecialPage::getTitleFor( 'Search' ); - + if ( $showSuggestion && $textMatches && !$textStatus && $textMatches->hasSuggestion() ) { # mirror Go/Search behavior of original request .. $didYouMeanParams = array( 'search' => $textMatches->getSuggestionQuery() ); @@ -291,18 +283,18 @@ class SpecialSearch extends SpecialPage { } $suggestLink = Linker::linkKnown( - $st, + $this->getPageTitle(), $suggestionSnippet, array(), $stParams ); - $this->didYouMeanHtml = '<div class="searchdidyoumean">' . $this->msg( 'search-suggest' )->rawParams( $suggestLink )->text() . '</div>'; + $this->didYouMeanHtml = '<div class="searchdidyoumean">' + . $this->msg( 'search-suggest' )->rawParams( $suggestLink )->text() . '</div>'; } if ( !wfRunHooks( 'SpecialSearchResultsPrepend', array( $this, $out, $term ) ) ) { # Hook requested termination - wfProfileOut( __METHOD__ ); return; } @@ -313,78 +305,62 @@ class SpecialSearch extends SpecialPage { array( 'id' => ( $this->profile === 'advanced' ? 'powersearch' : 'search' ), 'method' => 'get', - 'action' => $wgScript + 'action' => wfScript(), ) ) ); - $out->addHtml( - Xml::openElement( 'table', array( 'id' => 'mw-search-top-table', 'cellpadding' => 0, 'cellspacing' => 0 ) ) . - Xml::openElement( 'tr' ) . - Xml::openElement( 'td' ) . "\n" . - $this->shortDialog( $term ) . - Xml::closeElement( 'td' ) . - Xml::closeElement( 'tr' ) . - Xml::closeElement( 'table' ) - ); - // Sometimes the search engine knows there are too many hits - if ( $titleMatches instanceof SearchResultTooMany ) { - $out->wrapWikiMsg( "==$1==\n", 'toomanymatches' ); - wfProfileOut( __METHOD__ ); - return; + // Get number of results + $titleMatchesNum = $textMatchesNum = $numTitleMatches = $numTextMatches = 0; + if ( $titleMatches ) { + $titleMatchesNum = $titleMatches->numRows(); + $numTitleMatches = $titleMatches->getTotalHits(); + } + if ( $textMatches ) { + $textMatchesNum = $textMatches->numRows(); + $numTextMatches = $textMatches->getTotalHits(); } + $num = $titleMatchesNum + $textMatchesNum; + $totalRes = $numTitleMatches + $numTextMatches; + + $out->addHtml( + # This is an awful awful ID name. It's not a table, but we + # named it poorly from when this was a table so now we're + # stuck with it + Xml::openElement( 'div', array( 'id' => 'mw-search-top-table' ) ) . + $this->shortDialog( $term, $num, $totalRes ) . + Xml::closeElement( 'div' ) . + $this->formHeader( $term ) . + Xml::closeElement( 'form' ) + ); $filePrefix = $wgContLang->getFormattedNsText( NS_FILE ) . ':'; if ( trim( $term ) === '' || $filePrefix === trim( $term ) ) { - $out->addHTML( $this->formHeader( $term, 0, 0 ) ); - $out->addHtml( $this->getProfileForm( $this->profile, $term ) ); - $out->addHTML( '</form>' ); // Empty query -- straight view of search form - wfProfileOut( __METHOD__ ); return; } - // Get number of results - $titleMatchesNum = $titleMatches ? $titleMatches->numRows() : 0; - $textMatchesNum = $textMatches ? $textMatches->numRows() : 0; - // Total initial query matches (possible false positives) - $num = $titleMatchesNum + $textMatchesNum; - - // Get total actual results (after second filtering, if any) - $numTitleMatches = $titleMatches && !is_null( $titleMatches->getTotalHits() ) ? - $titleMatches->getTotalHits() : $titleMatchesNum; - $numTextMatches = $textMatches && !is_null( $textMatches->getTotalHits() ) ? - $textMatches->getTotalHits() : $textMatchesNum; - - // get total number of results if backend can calculate it - $totalRes = 0; - if ( $titleMatches && !is_null( $titleMatches->getTotalHits() ) ) { - $totalRes += $titleMatches->getTotalHits(); - } - if ( $textMatches && !is_null( $textMatches->getTotalHits() ) ) { - $totalRes += $textMatches->getTotalHits(); - } - - // show number of results and current offset - $out->addHTML( $this->formHeader( $term, $num, $totalRes ) ); - $out->addHtml( $this->getProfileForm( $this->profile, $term ) ); - - $out->addHtml( Xml::closeElement( 'form' ) ); $out->addHtml( "<div class='searchresults'>" ); // prev/next links + $prevnext = null; if ( $num || $this->offset ) { // Show the create link ahead - $this->showCreateLink( $t ); - $prevnext = $this->getLanguage()->viewPrevNext( $this->getTitle(), $this->offset, $this->limit, - $this->powerSearchOptions() + array( 'search' => $term ), - max( $titleMatchesNum, $textMatchesNum ) < $this->limit - ); - //$out->addHTML( "<p class='mw-search-pager-top'>{$prevnext}</p>\n" ); - wfRunHooks( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) ); - } else { - wfRunHooks( 'SpecialSearchNoResults', array( $term ) ); + $this->showCreateLink( $title, $num, $titleMatches, $textMatches ); + if ( $totalRes > $this->limit || $this->offset ) { + if ( $this->searchEngineType !== null ) { + $this->setExtraParam( 'srbackend', $this->searchEngineType ); + } + $prevnext = $this->getLanguage()->viewPrevNext( + $this->getPageTitle(), + $this->offset, + $this->limit, + $this->powerSearchOptions() + array( 'search' => $term ), + $this->limit + $this->offset >= $totalRes + ); + } } + wfRunHooks( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) ); $out->parserOptions()->setEditSection( false ); if ( $titleMatches ) { @@ -399,10 +375,8 @@ class SpecialSearch extends SpecialPage { if ( $numTextMatches > 0 && $numTitleMatches > 0 ) { // if no title matches the heading is redundant $out->wrapWikiMsg( "==$1==\n", 'textmatches' ); - } elseif ( $totalRes == 0 ) { - # Don't show the 'no text matches' if we received title matches - # $out->wrapWikiMsg( "==$1==\n", 'notextmatches' ); } + // show interwiki results if any if ( $textMatches->hasInterwikiResults() ) { $out->addHTML( $this->showInterwiki( $textMatches->getInterwikiResults(), $term ) ); @@ -417,49 +391,60 @@ class SpecialSearch extends SpecialPage { if ( $num === 0 ) { if ( $textStatus ) { $out->addHTML( '<div class="error">' . - htmlspecialchars( $textStatus->getWikiText( 'search-error' ) ) . '</div>' ); + $textStatus->getMessage( 'search-error' ) . '</div>' ); } else { $out->wrapWikiMsg( "<p class=\"mw-search-nonefound\">\n$1</p>", array( 'search-nonefound', wfEscapeWikiText( $term ) ) ); - $this->showCreateLink( $t ); + $this->showCreateLink( $title, $num, $titleMatches, $textMatches ); } } $out->addHtml( "</div>" ); - if ( $num || $this->offset ) { + if ( $prevnext ) { $out->addHTML( "<p class='mw-search-pager-bottom'>{$prevnext}</p>\n" ); } - wfRunHooks( 'SpecialSearchResultsAppend', array( $this, $out, $term ) ); - wfProfileOut( __METHOD__ ); } /** - * @param $t Title + * @param Title $title + * @param int $num The number of search results found + * @param null|SearchResultSet $titleMatches Results from title search + * @param null|SearchResultSet $textMatches Results from text search */ - protected function showCreateLink( $t ) { + protected function showCreateLink( $title, $num, $titleMatches, $textMatches ) { // show direct page/create link if applicable // Check DBkey !== '' in case of fragment link only. - if ( is_null( $t ) || $t->getDBkey() === '' ) { + if ( is_null( $title ) || $title->getDBkey() === '' + || ( $titleMatches !== null && $titleMatches->searchContainedSyntax() ) + || ( $textMatches !== null && $textMatches->searchContainedSyntax() ) + ) { // invalid title // preserve the paragraph for margins etc... $this->getOutput()->addHtml( '<p></p>' ); + return; } - if ( $t->isKnown() ) { + $linkClass = 'mw-search-createlink'; + if ( $title->isKnown() ) { $messageName = 'searchmenu-exists'; - } elseif ( $t->userCan( 'create', $this->getUser() ) ) { + $linkClass = 'mw-search-exists'; + } elseif ( $title->quickUserCan( 'create', $this->getUser() ) ) { $messageName = 'searchmenu-new'; } else { $messageName = 'searchmenu-new-nocreate'; } - $params = array( $messageName, wfEscapeWikiText( $t->getPrefixedText() ) ); - wfRunHooks( 'SpecialSearchCreateLink', array( $t, &$params ) ); + $params = array( + $messageName, + wfEscapeWikiText( $title->getPrefixedText() ), + Message::numParam( $num ) + ); + wfRunHooks( 'SpecialSearchCreateLink', array( $title, &$params ) ); // Extensions using the hook might still return an empty $messageName if ( $messageName ) { - $this->getOutput()->wrapWikiMsg( "<p class=\"mw-search-createlink\">\n$1</p>", $params ); + $this->getOutput()->wrapWikiMsg( "<p class=\"$linkClass\">\n$1</p>", $params ); } else { // preserve the paragraph for margins etc... $this->getOutput()->addHtml( '<p></p>' ); @@ -467,7 +452,7 @@ class SpecialSearch extends SpecialPage { } /** - * @param $term string + * @param string $term */ protected function setupPage( $term ) { # Should advanced UI be used? @@ -475,9 +460,10 @@ class SpecialSearch extends SpecialPage { $out = $this->getOutput(); if ( strval( $term ) !== '' ) { $out->setPageTitle( $this->msg( 'searchresults' ) ); - $out->setHTMLTitle( $this->msg( 'pagetitle' )->rawParams( - $this->msg( 'searchresults-title' )->rawParams( $term )->text() - ) ); + $out->setHTMLTitle( $this->msg( 'pagetitle' ) + ->rawParams( $this->msg( 'searchresults-title' )->rawParams( $term )->text() ) + ->inContentLanguage()->text() + ); } // add javascript specific to special:search $out->addModules( 'mediawiki.special.search' ); @@ -487,8 +473,8 @@ class SpecialSearch extends SpecialPage { * Extract "power search" namespace settings from the request object, * returning a list of index numbers to search. * - * @param $request WebRequest - * @return Array + * @param WebRequest $request + * @return array */ protected function powerSearch( &$request ) { $arr = array(); @@ -504,11 +490,10 @@ class SpecialSearch extends SpecialPage { /** * Reconstruct the 'power search' options for links * - * @return Array + * @return array */ protected function powerSearchOptions() { $opt = array(); - $opt['redirs'] = $this->searchRedirects ? 1 : 0; if ( $this->profile !== 'advanced' ) { $opt['profile'] = $this->profile; } else { @@ -516,28 +501,58 @@ class SpecialSearch extends SpecialPage { $opt['ns' . $n] = 1; } } + return $opt + $this->extraParams; } /** + * Save namespace preferences when we're supposed to + * + * @return bool Whether we wrote something + */ + protected function saveNamespaces() { + $user = $this->getUser(); + $request = $this->getRequest(); + + if ( $user->isLoggedIn() && + $user->matchEditToken( + $request->getVal( 'nsRemember' ), + 'searchnamespace', + $request + ) + ) { + // Reset namespace preferences: namespaces are not searched + // when they're not mentioned in the URL parameters. + foreach ( MWNamespace::getValidNamespaces() as $n ) { + $user->setOption( 'searchNs' . $n, false ); + } + // The request parameters include all the namespaces to be searched. + // Even if they're the same as an existing profile, they're not eaten. + foreach ( $this->namespaces as $n ) { + $user->setOption( 'searchNs' . $n, true ); + } + + $user->saveSettings(); + return true; + } + + return false; + } + + /** * Show whole set of results * - * @param $matches SearchResultSet + * @param SearchResultSet $matches * * @return string */ protected function showMatches( &$matches ) { global $wgContLang; - wfProfileIn( __METHOD__ ); + $profile = new ProfileSection( __METHOD__ ); $terms = $wgContLang->convertForSearchResult( $matches->termMatches() ); - $out = ""; - $infoLine = $matches->getInfo(); - if ( !is_null( $infoLine ) ) { - $out .= "\n<!-- {$infoLine} -->\n"; - } - $out .= "<ul class='mw-search-results'>\n"; + $out = "<ul class='mw-search-results'>\n"; $result = $matches->next(); while ( $result ) { $out .= $this->showHit( $result, $terms ); @@ -547,27 +562,26 @@ class SpecialSearch extends SpecialPage { // convert the whole thing to desired language variant $out = $wgContLang->convert( $out ); - wfProfileOut( __METHOD__ ); + return $out; } /** * Format a single hit result * - * @param $result SearchResult - * @param array $terms terms to highlight + * @param SearchResult $result + * @param array $terms Terms to highlight * * @return string */ protected function showHit( $result, $terms ) { - wfProfileIn( __METHOD__ ); + $profile = new ProfileSection( __METHOD__ ); if ( $result->isBrokenTitle() ) { - wfProfileOut( __METHOD__ ); - return "<!-- Broken link in search result -->\n"; + return ''; } - $t = $result->getTitle(); + $title = $result->getTitle(); $titleSnippet = $result->getTitleSnippet( $terms ); @@ -575,10 +589,10 @@ class SpecialSearch extends SpecialPage { $titleSnippet = null; } - $link_t = clone $t; + $link_t = clone $title; wfRunHooks( 'ShowSearchHitTitle', - array( &$link_t, &$titleSnippet, $result, $terms, $this ) ); + array( &$link_t, &$titleSnippet, $result, $terms, $this ) ); $link = Linker::linkKnown( $link_t, @@ -588,8 +602,7 @@ class SpecialSearch extends SpecialPage { //If page content is not readable, just return the title. //This is not quite safe, but better than showing excerpts from non-readable pages //Note that hiding the entry entirely would screw up paging. - if ( !$t->userCan( 'read', $this->getUser() ) ) { - wfProfileOut( __METHOD__ ); + if ( !$title->userCan( 'read', $this->getUser() ) ) { return "<li>{$link}</li>\n"; } @@ -597,8 +610,7 @@ class SpecialSearch extends SpecialPage { // The least confusing at this point is to drop the result. // You may get less results, but... oh well. :P if ( $result->isMissingRevision() ) { - wfProfileOut( __METHOD__ ); - return "<!-- missing page " . htmlspecialchars( $t->getPrefixedText() ) . "-->\n"; + return ''; } // format redirects / relevant sections @@ -637,16 +649,6 @@ class SpecialSearch extends SpecialPage { $lang = $this->getLanguage(); - // format score - if ( is_null( $result->getScore() ) ) { - // Search engine doesn't report scoring info - $score = ''; - } else { - $percent = sprintf( '%2.1f', $result->getScore() * 100 ); - $score = $this->msg( 'search-result-score' )->numParams( $percent )->text() - . ' - '; - } - // format description $byteSize = $result->getByteSize(); $wordCount = $result->getWordCount(); @@ -654,8 +656,8 @@ class SpecialSearch extends SpecialPage { $size = $this->msg( 'search-result-size', $lang->formatSize( $byteSize ) ) ->numParams( $wordCount )->escaped(); - if ( $t->getNamespace() == NS_CATEGORY ) { - $cat = Category::newFromTitle( $t ); + if ( $title->getNamespace() == NS_CATEGORY ) { + $cat = Category::newFromTitle( $title ); $size = $this->msg( 'search-result-category-size' ) ->numParams( $cat->getPageCount(), $cat->getSubcatCount(), $cat->getFileCount() ) ->escaped(); @@ -663,35 +665,19 @@ class SpecialSearch extends SpecialPage { $date = $lang->userTimeAndDate( $timestamp, $this->getUser() ); - // link to related articles if supported - $related = ''; - if ( $result->hasRelated() ) { - $st = SpecialPage::getTitleFor( 'Search' ); - $stParams = array_merge( - $this->powerSearchOptions(), - array( - 'search' => $this->msg( 'searchrelated' )->inContentLanguage()->text() . - ':' . $t->getPrefixedText(), - 'fulltext' => $this->msg( 'search' )->text() - ) - ); - - $related = ' -- ' . Linker::linkKnown( - $st, - $this->msg( 'search-relatedarticle' )->text(), - array(), - $stParams - ); - } - + $fileMatch = ''; // Include a thumbnail for media files... - if ( $t->getNamespace() == NS_FILE ) { - $img = wfFindFile( $t ); + if ( $title->getNamespace() == NS_FILE ) { + $img = $result->getFile(); + $img = $img ?: wfFindFile( $title ); + if ( $result->isFileMatch() ) { + $fileMatch = "<span class='searchalttitle'>" . + $this->msg( 'search-file-match' )->escaped() . "</span>"; + } if ( $img ) { $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) ); if ( $thumb ) { $desc = $this->msg( 'parentheses' )->rawParams( $img->getShortDesc() )->escaped(); - wfProfileOut( __METHOD__ ); // Float doesn't seem to interact well with the bullets. // Table messes up vertical alignment of the bullets. // Bullets are therefore disabled (didn't look great anyway). @@ -702,9 +688,9 @@ class SpecialSearch extends SpecialPage { $thumb->toHtml( array( 'desc-link' => true ) ) . '</td>' . '<td style="vertical-align: top;">' . - $link . + "{$link} {$redirect} {$section} {$fileMatch}" . $extract . - "<div class='mw-search-result-data'>{$score}{$desc} - {$date}{$related}</div>" . + "<div class='mw-search-result-data'>{$desc} - {$date}</div>" . '</td>' . '</tr>' . '</table>' . @@ -715,33 +701,33 @@ class SpecialSearch extends SpecialPage { $html = null; + $score = ''; if ( wfRunHooks( 'ShowSearchHit', array( $this, $result, $terms, &$link, &$redirect, &$section, &$extract, &$score, &$size, &$date, &$related, &$html ) ) ) { - $html = "<li><div class='mw-search-result-heading'>{$link} {$redirect} {$section}</div> {$extract}\n" . - "<div class='mw-search-result-data'>{$score}{$size} - {$date}{$related}</div>" . + $html = "<li><div class='mw-search-result-heading'>" . + "{$link} {$redirect} {$section} {$fileMatch}</div> {$extract}\n" . + "<div class='mw-search-result-data'>{$size} - {$date}</div>" . "</li>\n"; } - wfProfileOut( __METHOD__ ); return $html; } /** * Show results from other wikis * - * @param $matches SearchResultSet - * @param $query String + * @param SearchResultSet|array $matches + * @param string $query * * @return string */ - protected function showInterwiki( &$matches, $query ) { + protected function showInterwiki( $matches, $query ) { global $wgContLang; - wfProfileIn( __METHOD__ ); - $terms = $wgContLang->convertForSearchResult( $matches->termMatches() ); + $profile = new ProfileSection( __METHOD__ ); $out = "<div id='mw-search-interwiki'><div id='mw-search-interwiki-caption'>" . $this->msg( 'search-interwiki-caption' )->text() . "</div>\n"; @@ -749,7 +735,8 @@ class SpecialSearch extends SpecialPage { // work out custom project captions $customCaptions = array(); - $customLines = explode( "\n", $this->msg( 'search-interwiki-custom' )->text() ); // format per line <iwprefix>:<caption> + // format per line <iwprefix>:<caption> + $customLines = explode( "\n", $this->msg( 'search-interwiki-custom' )->text() ); foreach ( $customLines as $line ) { $parts = explode( ":", $line, 2 ); if ( count( $parts ) == 2 ) { // validate line @@ -757,57 +744,62 @@ class SpecialSearch extends SpecialPage { } } - $prev = null; - $result = $matches->next(); - while ( $result ) { - $out .= $this->showInterwikiHit( $result, $prev, $terms, $query, $customCaptions ); - $prev = $result->getInterwikiPrefix(); - $result = $matches->next(); + if ( !is_array( $matches ) ) { + $matches = array( $matches ); } - // TODO: should support paging in a non-confusing way (not sure how though, maybe via ajax).. + + foreach ( $matches as $set ) { + $prev = null; + $result = $set->next(); + while ( $result ) { + $out .= $this->showInterwikiHit( $result, $prev, $query, $customCaptions ); + $prev = $result->getInterwikiPrefix(); + $result = $set->next(); + } + } + + // @todo Should support paging in a non-confusing way (not sure how though, maybe via ajax).. $out .= "</ul></div>\n"; // convert the whole thing to desired language variant $out = $wgContLang->convert( $out ); - wfProfileOut( __METHOD__ ); + return $out; } /** * Show single interwiki link * - * @param $result SearchResult - * @param $lastInterwiki String - * @param $terms Array - * @param $query String - * @param array $customCaptions iw prefix -> caption + * @param SearchResult $result + * @param string $lastInterwiki + * @param string $query + * @param array $customCaptions Interwiki prefix -> caption * * @return string */ - protected function showInterwikiHit( $result, $lastInterwiki, $terms, $query, $customCaptions ) { - wfProfileIn( __METHOD__ ); + protected function showInterwikiHit( $result, $lastInterwiki, $query, $customCaptions ) { + $profile = new ProfileSection( __METHOD__ ); if ( $result->isBrokenTitle() ) { - wfProfileOut( __METHOD__ ); - return "<!-- Broken link in search result -->\n"; + return ''; } - $t = $result->getTitle(); + $title = $result->getTitle(); - $titleSnippet = $result->getTitleSnippet( $terms ); + $titleSnippet = $result->getTitleSnippet(); if ( $titleSnippet == '' ) { $titleSnippet = null; } $link = Linker::linkKnown( - $t, + $title, $titleSnippet ); // format redirect if any $redirectTitle = $result->getRedirectTitle(); - $redirectText = $result->getRedirectSnippet( $terms ); + $redirectText = $result->getRedirectSnippet(); $redirect = ''; if ( !is_null( $redirectTitle ) ) { if ( $redirectText == '' ) { @@ -822,18 +814,18 @@ class SpecialSearch extends SpecialPage { $out = ""; // display project name - if ( is_null( $lastInterwiki ) || $lastInterwiki != $t->getInterwiki() ) { - if ( array_key_exists( $t->getInterwiki(), $customCaptions ) ) { + if ( is_null( $lastInterwiki ) || $lastInterwiki != $title->getInterwiki() ) { + if ( array_key_exists( $title->getInterwiki(), $customCaptions ) ) { // captions from 'search-interwiki-custom' - $caption = $customCaptions[$t->getInterwiki()]; + $caption = $customCaptions[$title->getInterwiki()]; } else { // default is to show the hostname of the other wiki which might suck // if there are many wikis on one hostname - $parsed = wfParseUrl( $t->getFullURL() ); + $parsed = wfParseUrl( $title->getFullURL() ); $caption = $this->msg( 'search-interwiki-default', $parsed['host'] )->text(); } // "more results" link (special page stuff could be localized, but we might not know target lang) - $searchTitle = Title::newFromText( $t->getInterwiki() . ":Special:Search" ); + $searchTitle = Title::newFromText( $title->getInterwiki() . ":Special:Search" ); $searchLink = Linker::linkKnown( $searchTitle, $this->msg( 'search-interwiki-more' )->text(), @@ -848,36 +840,16 @@ class SpecialSearch extends SpecialPage { } $out .= "<li>{$link} {$redirect}</li>\n"; - wfProfileOut( __METHOD__ ); - return $out; - } - /** - * @param $profile - * @param $term - * @return String - */ - protected function getProfileForm( $profile, $term ) { - // Hidden stuff - $opts = array(); - $opts['redirs'] = $this->searchRedirects; - $opts['profile'] = $this->profile; - - if ( $profile === 'advanced' ) { - return $this->powerSearchBox( $term, $opts ); - } else { - $form = ''; - wfRunHooks( 'SpecialSearchProfileForm', array( $this, &$form, $profile, $term, $opts ) ); - return $form; - } + return $out; } /** * Generates the power search box at [[Special:Search]] * - * @param string $term search term - * @param $opts array - * @return String: HTML form + * @param string $term Search term + * @param array $opts + * @return string HTML form */ protected function powerSearchBox( $term, $opts ) { global $wgContLang; @@ -896,9 +868,7 @@ class SpecialSearch extends SpecialPage { } $rows[$subject] .= - Xml::openElement( - 'td', array( 'style' => 'white-space: nowrap' ) - ) . + Xml::openElement( 'td' ) . Xml::checkLabel( $name, "ns{$namespace}", @@ -929,30 +899,41 @@ class SpecialSearch extends SpecialPage { $showSections = array( 'namespaceTables' => $namespaceTables ); - // Show redirects check only if backend supports it - if ( $this->getSearchEngine()->supports( 'list-redirects' ) ) { - $showSections['redirects'] = - Xml::checkLabel( $this->msg( 'powersearch-redir' )->text(), 'redirs', 'redirs', $this->searchRedirects ); - } - wfRunHooks( 'SpecialSearchPowerBox', array( &$showSections, $term, $opts ) ); $hidden = ''; - unset( $opts['redirs'] ); foreach ( $opts as $key => $value ) { $hidden .= Html::hidden( $key, $value ); } + + # Stuff to feed saveNamespaces() + $remember = ''; + $user = $this->getUser(); + if ( $user->isLoggedIn() ) { + $remember .= Xml::checkLabel( + wfMessage( 'powersearch-remember' )->text(), + 'nsRemember', + 'mw-search-powersearch-remember', + false, + // The token goes here rather than in a hidden field so it + // is only sent when necessary (not every form submission). + array( 'value' => $user->getEditToken( + 'searchnamespace', + $this->getRequest() + ) ) + ); + } + // Return final output - return Xml::openElement( - 'fieldset', - array( 'id' => 'mw-searchoptions', 'style' => 'margin:0em;' ) - ) . + return Xml::openElement( 'fieldset', array( 'id' => 'mw-searchoptions' ) ) . Xml::element( 'legend', null, $this->msg( 'powersearch-legend' )->text() ) . Xml::tags( 'h4', null, $this->msg( 'powersearch-ns' )->parse() ) . - Html::element( 'div', array( 'id' => 'mw-search-togglebox' ) ) . + Xml::element( 'div', array( 'id' => 'mw-search-togglebox' ), '', false ) . Xml::element( 'div', array( 'class' => 'divider' ), '', false ) . implode( Xml::element( 'div', array( 'class' => 'divider' ), '', false ), $showSections ) . $hidden . + Xml::element( 'div', array( 'class' => 'divider' ), '', false ) . + $remember . Xml::closeElement( 'fieldset' ); } @@ -977,14 +958,6 @@ class SpecialSearch extends SpecialPage { 'tooltip' => 'searchprofile-images-tooltip', 'namespaces' => array( NS_FILE ), ), - 'help' => array( - 'message' => 'searchprofile-project', - 'tooltip' => 'searchprofile-project-tooltip', - 'namespaces' => SearchEngine::helpNamespaces(), - 'namespace-messages' => SearchEngine::namespacesAsText( - SearchEngine::helpNamespaces() - ), - ), 'all' => array( 'message' => 'searchprofile-everything', 'tooltip' => 'searchprofile-everything-tooltip', @@ -1010,12 +983,10 @@ class SpecialSearch extends SpecialPage { } /** - * @param $term - * @param $resultsShown - * @param $totalNum + * @param string $term * @return string */ - protected function formHeader( $term, $resultsShown, $totalNum ) { + protected function formHeader( $term ) { $out = Xml::openElement( 'div', array( 'class' => 'mw-search-formheader' ) ); $bareterm = $term; @@ -1054,69 +1025,74 @@ class SpecialSearch extends SpecialPage { } $out .= Xml::closeElement( 'ul' ); $out .= Xml::closeElement( 'div' ); - - // Results-info - if ( $resultsShown > 0 ) { - if ( $totalNum > 0 ) { - $top = $this->msg( 'showingresultsheader' ) - ->numParams( $this->offset + 1, $this->offset + $resultsShown, $totalNum ) - ->params( wfEscapeWikiText( $term ) ) - ->numParams( $resultsShown ) - ->parse(); - } elseif ( $resultsShown >= $this->limit ) { - $top = $this->msg( 'showingresults' ) - ->numParams( $this->limit, $this->offset + 1 ) - ->parse(); - } else { - $top = $this->msg( 'showingresultsnum' ) - ->numParams( $this->limit, $this->offset + 1, $resultsShown ) - ->parse(); - } - $out .= Xml::tags( 'div', array( 'class' => 'results-info' ), - Xml::tags( 'ul', null, Xml::tags( 'li', null, $top ) ) - ); - } - $out .= Xml::element( 'div', array( 'style' => 'clear:both' ), '', false ); $out .= Xml::closeElement( 'div' ); + // Hidden stuff + $opts = array(); + $opts['profile'] = $this->profile; + + if ( $this->profile === 'advanced' ) { + $out .= $this->powerSearchBox( $term, $opts ); + } else { + $form = ''; + wfRunHooks( 'SpecialSearchProfileForm', array( $this, &$form, $this->profile, $term, $opts ) ); + $out .= $form; + } + return $out; } /** - * @param $term string + * @param string $term + * @param int $resultsShown + * @param int $totalNum * @return string */ - protected function shortDialog( $term ) { - $out = Html::hidden( 'title', $this->getTitle()->getPrefixedText() ); + protected function shortDialog( $term, $resultsShown, $totalNum ) { + $out = Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ); $out .= Html::hidden( 'profile', $this->profile ) . "\n"; // Term box $out .= Html::input( 'search', $term, 'search', array( 'id' => $this->profile === 'advanced' ? 'powerSearchText' : 'searchText', 'size' => '50', - 'autofocus' + 'autofocus', + 'class' => 'mw-ui-input mw-ui-input-inline', ) ) . "\n"; $out .= Html::hidden( 'fulltext', 'Search' ) . "\n"; - $out .= Xml::submitButton( $this->msg( 'searchbutton' )->text() ) . "\n"; + $out .= Xml::submitButton( + $this->msg( 'searchbutton' )->text(), + array( 'class' => array( 'mw-ui-button', 'mw-ui-progressive' ) ) + ) . "\n"; + + // Results-info + if ( $totalNum > 0 && $this->offset < $totalNum ) { + $top = $this->msg( 'search-showingresults' ) + ->numParams( $this->offset + 1, $this->offset + $resultsShown, $totalNum ) + ->numParams( $resultsShown ) + ->parse(); + $out .= Xml::tags( 'div', array( 'class' => 'results-info' ), $top ) . + Xml::element( 'div', array( 'style' => 'clear:both' ), '', false ); + } + return $out . $this->didYouMeanHtml; } /** * Make a search link with some target namespaces * - * @param $term String - * @param array $namespaces ignored - * @param string $label link's text - * @param string $tooltip link's tooltip - * @param array $params query string parameters - * @return String: HTML fragment + * @param string $term + * @param array $namespaces Ignored + * @param string $label Link's text + * @param string $tooltip Link's tooltip + * @param array $params Query string parameters + * @return string HTML fragment */ protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params = array() ) { $opt = $params; foreach ( $namespaces as $n ) { $opt['ns' . $n] = 1; } - $opt['redirs'] = $this->searchRedirects; $stParams = array_merge( array( @@ -1129,7 +1105,7 @@ class SpecialSearch extends SpecialPage { return Xml::element( 'a', array( - 'href' => $this->getTitle()->getLocalURL( $stParams ), + 'href' => $this->getPageTitle()->getLocalURL( $stParams ), 'title' => $tooltip ), $label @@ -1139,33 +1115,35 @@ class SpecialSearch extends SpecialPage { /** * Check if query starts with image: prefix * - * @param string $term the string to check - * @return Boolean + * @param string $term The string to check + * @return bool */ protected function startsWithImage( $term ) { global $wgContLang; - $p = explode( ':', $term ); - if ( count( $p ) > 1 ) { - return $wgContLang->getNsIndex( $p[0] ) == NS_FILE; + $parts = explode( ':', $term ); + if ( count( $parts ) > 1 ) { + return $wgContLang->getNsIndex( $parts[0] ) == NS_FILE; } + return false; } /** * Check if query starts with all: prefix * - * @param string $term the string to check - * @return Boolean + * @param string $term The string to check + * @return bool */ protected function startsWithAll( $term ) { $allkeyword = $this->msg( 'searchall' )->inContentLanguage()->text(); - $p = explode( ':', $term ); - if ( count( $p ) > 1 ) { - return $p[0] == $allkeyword; + $parts = explode( ':', $term ); + if ( count( $parts ) > 1 ) { + return $parts[0] == $allkeyword; } + return false; } @@ -1179,17 +1157,34 @@ class SpecialSearch extends SpecialPage { $this->searchEngine = $this->searchEngineType ? SearchEngine::create( $this->searchEngineType ) : SearchEngine::create(); } + return $this->searchEngine; } /** + * Current search profile. + * @return null|string + */ + function getProfile() { + return $this->profile; + } + + /** + * Current namespaces. + * @return array + */ + function getNamespaces() { + return $this->namespaces; + } + + /** * Users of hook SpecialSearchSetupEngine can use this to * add more params to links to not lose selection when * user navigates search results. * @since 1.18 * - * @param $key - * @param $value + * @param string $key + * @param mixed $value */ public function setExtraParam( $key, $value ) { $this->extraParams[$key] = $value; |