EBernhardson has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/322015

Change subject: [WIP] Extract main search result rendering from SpecialSearch
......................................................................

[WIP] Extract main search result rendering from SpecialSearch

Change-Id: Id1d6b357f45a2cf615d9412cc95dd597c724e8b6
---
M autoload.php
M includes/specials/SpecialSearch.php
A includes/widget/BasicSearchResultSetWidget.php
R includes/widget/FullSearchResultWidget.php
A includes/widget/InterwikiSearchResultSetWidget.php
A includes/widget/SearchResultWidget.php
R includes/widget/SimpleSearchResultWidget.php
7 files changed, 339 insertions(+), 227 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/15/322015/1

diff --git a/autoload.php b/autoload.php
index 99d7303..1f67fa3 100644
--- a/autoload.php
+++ b/autoload.php
@@ -920,15 +920,17 @@
        'MediaWiki\\Tidy\\RaggettWrapper' => __DIR__ . 
'/includes/tidy/RaggettWrapper.php',
        'MediaWiki\\Tidy\\TidyDriverBase' => __DIR__ . 
'/includes/tidy/TidyDriverBase.php',
        'MediaWiki\\Widget\\BasicSearchResultSetWidget' => __DIR__ . 
'/includes/widget/BasicSearchResultSetWidget.php',
-       'MediaWiki\\Widget\\BasicSearchResultWidget' => __DIR__ . 
'/includes/widget/BasicSearchResultWidget.php',
        'MediaWiki\\Widget\\ComplexNamespaceInputWidget' => __DIR__ . 
'/includes/widget/ComplexNamespaceInputWidget.php',
        'MediaWiki\\Widget\\ComplexTitleInputWidget' => __DIR__ . 
'/includes/widget/ComplexTitleInputWidget.php',
        'MediaWiki\\Widget\\DateInputWidget' => __DIR__ . 
'/includes/widget/DateInputWidget.php',
        'MediaWiki\\Widget\\DateTimeInputWidget' => __DIR__ . 
'/includes/widget/DateTimeInputWidget.php',
-       'MediaWiki\\Widget\\InterwikiSearchResultWidget' => __DIR__ . 
'/includes/widget/InterwikiSearchResultWidget.php',
+       'MediaWiki\\Widget\\FullSearchResultWidget' => __DIR__ . 
'/includes/widget/FullSearchResultWidget.php',
+       'MediaWiki\\Widget\\InterwikiSearchResultSetWidget' => __DIR__ . 
'/includes/widget/InterwikiSearchResultSetWidget.php',
        'MediaWiki\\Widget\\NamespaceInputWidget' => __DIR__ . 
'/includes/widget/NamespaceInputWidget.php',
        'MediaWiki\\Widget\\SearchFormWidget' => __DIR__ . 
'/includes/widget/SearchFormWidget.php',
        'MediaWiki\\Widget\\SearchInputWidget' => __DIR__ . 
'/includes/widget/SearchInputWidget.php',
+       'MediaWiki\\Widget\\SearchResultWidget' => __DIR__ . 
'/includes/widget/SearchResultWidget.php',
+       'MediaWiki\\Widget\\SimpleSearchResultWidget' => __DIR__ . 
'/includes/widget/SimpleSearchResultWidget.php',
        'MediaWiki\\Widget\\TitleInputWidget' => __DIR__ . 
'/includes/widget/TitleInputWidget.php',
        'MediaWiki\\Widget\\UserInputWidget' => __DIR__ . 
'/includes/widget/UserInputWidget.php',
        'MemCachedClientforWiki' => __DIR__ . 
'/includes/compat/MemcachedClientCompat.php',
diff --git a/includes/specials/SpecialSearch.php 
b/includes/specials/SpecialSearch.php
index 2ab5e58..943bb57 100644
--- a/includes/specials/SpecialSearch.php
+++ b/includes/specials/SpecialSearch.php
@@ -269,19 +269,45 @@
        public function showResults( $term ) {
                global $wgContLang;
 
+               $out = $this->getOutput();
+               $filePrefix = $wgContLang->getFormattedNsText( NS_FILE ) . ':';
+               $isEmptySearch = trim( $term ) === '' || $filePrefix === trim( 
$term );
+
+               if ( $this->searchEngineType !== null ) {
+                       $this->setExtraParam( 'srbackend', 
$this->searchEngineType );
+               }
+
+               $formWidget = new MediaWiki\Widget\SearchFormWidget(
+                       $this,
+                       $this->searchConfig,
+                       $this->getSearchProfiles()
+               );
+               if ( trim( $term ) === '' || $filePrefix === trim( $term ) ) {
+                       // empty search request. Just form and quit.
+                       if ( !Hooks::run( 'SpecialSearchResultsPrepend', [ 
$this, $out, $term ] ) ) {
+                               # Hook requested termination
+                               return;
+                       }
+                       $out->enableOOUI();
+                       $out->addHtml( $formWidget->render( $profile, $term, 0, 
0, $this->offset, $this->isPowerSearch(), $this->profile  ) );
+                       return;
+               }
+
                $search = $this->getSearchEngine();
                $search->setFeatureData( 'rewrite', $this->runSuggestion );
                $search->setLimitOffset( $this->limit, $this->offset );
                $search->setNamespaces( $this->namespaces );
                $search->prefix = $this->mPrefix;
                $term = $search->transformSearchTerm( $term );
-               $out = $this->getOutput();
-
                Hooks::run( 'SpecialSearchSetupEngine', [ $this, 
$this->profile, $search ] );
+
                if ( !Hooks::run( 'SpecialSearchResultsPrepend', [ $this, $out, 
$term ] ) ) {
                        # Hook requested termination
                        return;
                }
+
+               // For BC purposes this should come after 
SpecialSearchResultsPrepend
+               $out->enableOOUI();
 
                $title = Title::newFromText( $term );
                $showSuggestion = $title === null || !$title->isKnown();
@@ -289,7 +315,6 @@
 
                // fetch search results
                $rewritten = $search->replacePrefixes( $term );
-
                $titleMatches = $search->searchTitle( $rewritten );
                $textMatches = $search->searchText( $rewritten );
 
@@ -301,7 +326,7 @@
 
                // did you mean... suggestions
                $didYouMeanHtml = '';
-               if ( $showSuggestion && $textMatches ) {
+               if ( $textMatches ) {
                        if ( $textMatches->hasRewrittenQuery() ) {
                                $didYouMeanHtml = 
$this->getDidYouMeanRewrittenHtml( $term, $textMatches );
                        } elseif ( $textMatches->hasSuggestion() ) {
@@ -322,18 +347,12 @@
                $num = $titleMatchesNum + $textMatchesNum;
                $totalRes = $numTitleMatches + $numTextMatches;
 
-               // start rendering the page
-               $out->enableOOUI();
-               $formWidget = new MediaWiki\Widget\SearchFormWidget(
-                       $this,
-                       $this->searchConfig,
-                       $this->getSearchProfiles()
-               );
+               // Render the top form for search, profile selectors, etc.
+               // @TODO: See if we can do this before attempting to call 
search engine.
                $out->addHtml( $formWidget->render( $profile, $term, $num, 
$totalRes, $this->offset, $this->isPowerSearch(), $this->profile  ) );
 
-               $filePrefix = $wgContLang->getFormattedNsText( NS_FILE ) . ':';
-               if ( trim( $term ) === '' || $filePrefix === trim( $term ) ) {
-                       // Empty query -- straight view of search form
+               // Empty query -- straight view of search form
+               if ( $isEmptySearch ) {
                        return;
                }
 
@@ -347,87 +366,59 @@
                        ) );
                }
 
+               // Show the create link ahead
+               if ( !$textStatus || $textStatus->isOK() ) {
+                       $this->showCreateLink( $title, $num, $titleMatches, 
$textMatches );
+               }
+
                // prev/next links
                $prevnext = null;
-               if ( $num || $this->offset ) {
-                       // Show the create link ahead
-                       $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() + [ 
'search' => $term ],
-                                       $this->limit + $this->offset >= 
$totalRes
-                               );
-                       }
+               if ( $totalRes > $this->limit || $this->offset ) {
+                       $prevnext = $this->getLanguage()->viewPrevNext(
+                               $this->getPageTitle(),
+                               $this->offset,
+                               $this->limit,
+                               $this->powerSearchOptions() + [ 'search' => 
$term ],
+                               $this->limit + $this->offset >= $totalRes
+                       );
                }
                Hooks::run( 'SpecialSearchResults', [ $term, &$titleMatches, 
&$textMatches ] );
 
                $out->parserOptions()->setEditSection( false );
-               if ( $titleMatches ) {
-                       if ( $numTitleMatches > 0 ) {
-                               $out->wrapWikiMsg( "==$1==\n", 'titlematches' );
-                               $out->addHTML( $this->showMatches( 
$titleMatches ) );
-                       }
-                       $titleMatches->free();
-               }
-
-               if ( $textMatches ) {
-                       // output appropriate heading
-                       if ( $numTextMatches > 0 && $numTitleMatches > 0 ) {
-                               $out->addHTML( '<div 
class="mw-search-visualclear"></div>' );
-                               // if no title matches the heading is redundant
-                               $out->wrapWikiMsg( "==$1==\n", 'textmatches' );
-                       }
-
-                       // show results
-                       if ( $numTextMatches > 0 ) {
-                               $search->augmentSearchResults( $textMatches );
-                               $out->addHTML( $this->showMatches( $textMatches 
) );
-                       }
-
-                       // show secondary interwiki results if any
-                       if ( $textMatches->hasInterwikiResults( 
SearchResultSet::SECONDARY_RESULTS ) ) {
-                               $out->addHTML( $this->showInterwiki( 
$textMatches->getInterwikiResults(
-                                               
SearchResultSet::SECONDARY_RESULTS ), $term ) );
-                       }
-               }
-
-               $hasOtherResults = $textMatches &&
-                       $textMatches->hasInterwikiResults( 
SearchResultSet::INLINE_RESULTS );
 
                if ( $num === 0 ) {
                        if ( $textStatus && !$textStatus->isOK() ) {
                                $out->addHTML( '<div class="error">' .
                                        $textStatus->getMessage( 'search-error' 
) . '</div>' );
                        } else {
-                               if ( !$this->offset ) {
-                                       // If we have an offset the create link 
was rendered earlier in this function.
-                                       // This class needs a good 
de-spaghettification, but for now this will
-                                       // do the job.
-                                       $this->showCreateLink( $title, $num, 
$titleMatches, $textMatches );
-                               }
-                               $out->wrapWikiMsg( "<p 
class=\"mw-search-nonefound\">\n$1</p>",
-                                       [ $hasOtherResults ? 
'search-nonefound-thiswiki' : 'search-nonefound',
-                                                       wfEscapeWikiText( $term 
)
-                                       ] );
+                               $hasOtherResults = $textMatches &&
+                                       $textMatches->hasInterwikiResults( 
SearchResultSet::INLINE_RESULTS );
+
+                               $out->addHTML(
+                                       "<p class='mw-search-nonefound'>" .
+                                               $this->msg( $hasOtherResults ? 
'search-nonefound-thiswiki' : 'search-nonefound', $term )->escaped() .
+                                       "</p>"
+                               );
                        }
+               } else {
+                       if ( $numTextMatches > 0 ) {
+                               $search->augmentSearchResults( $textMatches );
+                       }
+                       $widget = new 
MediaWiki\Widget\BasicSearchResultSetWidget(
+                               $this,
+                               // Single search results in the main view
+                               new \MediaWiki\Widget\FullSearchResultWidget( 
$this ),
+                               // Sidebar of interwiki search results
+                               new 
\MediaWiki\Widget\InterwikiSearchResultSetWidget(
+                                       $this,
+                                       new 
\MediaWiki\Widget\SimpleSearchResultWidget( $this )
+                               )
+                       );
+                       $out->addHtml( $widget->render( $term, $this->offset, 
$titleMatches, $textMatches ) );
                }
 
-               if ( $hasOtherResults ) {
-                       foreach ( $textMatches->getInterwikiResults( 
SearchResultSet::INLINE_RESULTS )
-                                               as $interwiki => 
$interwikiResult ) {
-                               if ( $interwikiResult instanceof Status || 
$interwikiResult->numRows() == 0 ) {
-                                       // ignore bad interwikis for now
-                                       continue;
-                               }
-                               // TODO: wiki header
-                               $out->addHTML( $this->showMatches( 
$interwikiResult, $interwiki ) );
-                       }
+               if ( $titleMatches ) {
+                       $titleMatches->free();
                }
 
                if ( $textMatches ) {
@@ -443,18 +434,6 @@
                $out->addHTML( "</div>" );
 
                Hooks::run( 'SpecialSearchResultsAppend', [ $this, $out, $term 
] );
-       }
-
-       /**
-        * Produce wiki header for interwiki results
-        * @param string $interwiki Interwiki name
-        * @param SearchResultSet $interwikiResult The result set
-        * @return string
-        */
-       protected function interwikiHeader( $interwiki, $interwikiResult ) {
-               // TODO: we need to figure out how to name wikis correctly
-               $wikiMsg = $this->msg( 'search-interwiki-results-' . $interwiki 
)->parse();
-               return "<p class=\"mw-search-interwiki-header 
mw-search-visualclear\">\n$wikiMsg</p>";
        }
 
        /**
@@ -629,12 +608,12 @@
         */
        protected function powerSearchOptions() {
                $opt = [];
-               if ( !$this->isPowerSearch() ) {
-                       $opt['profile'] = $this->profile;
-               } else {
+               if ( $this->isPowerSearch() ) {
                        foreach ( $this->namespaces as $n ) {
                                $opt['ns' . $n] = 1;
                        }
+               } else {
+                       $opt['profile'] = $this->profile;
                }
 
                return $opt + $this->extraParams;
@@ -694,7 +673,9 @@
                $pos = $this->offset;
 
                if ( $result && $interwiki ) {
-                       $out .= $this->interwikiHeader( $interwiki, $matches );
+               // TODO: we need to figure out how to name wikis correctly
+                       $wikiMsg = $this->msg( 'search-interwiki-results-' . 
$interwiki )->parse();
+                       $out .= "<p class=\"mw-search-interwiki-header 
mw-search-visualclear\">\n$wikiMsg</p>";
                }
 
                $out .= "<ul class='mw-search-results'>\n";
@@ -708,115 +689,6 @@
                $out = $wgContLang->convert( $out );
 
                return $out;
-       }
-
-       /**
-        * Format a single hit result
-        *
-        * @param SearchResult $result
-        * @param array $terms Terms to highlight
-        * @param int $position Position within the search results, including 
offset.
-        *
-        * @return string
-        */
-       protected function showHit( SearchResult $result, $terms, $position ) {
-               $widget = new \MediaWiki\Widget\BasicSearchResultWidget( $this 
);
-               return $widget->render( $result, $terms, $position );
-       }
-
-       /**
-        * Extract custom captions from search-interwiki-custom message
-        */
-       protected function getCustomCaptions() {
-               if ( is_null( $this->customCaptions ) ) {
-                       $this->customCaptions = [];
-                       // 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
-                                       $this->customCaptions[$parts[0]] = 
$parts[1];
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Show results from other wikis
-        *
-        * @param SearchResultSet|array $matches
-        * @param string $query
-        *
-        * @return string
-        */
-       protected function showInterwiki( $matches, $query ) {
-               global $wgContLang;
-
-
-               // work out custom project captions
-               $this->getCustomCaptions();
-
-               if ( !is_array( $matches ) ) {
-                       $matches = [ $matches ];
-               }
-
-               $iwResults = [];
-               foreach ( $matches as $set ) {
-                       $result = $set->next();
-                       while ( $result ) {
-                               if ( !$result->isBrokenTitle() ) {
-                                       
$iwResults[$result->getTitle()->getInterwiki()][] = $result;
-                               }
-                               $result = $set->next();
-                       }
-               }
-
-               $out = '';
-               $widget = new MediaWiki\Widget\InterwikiSearchResultWidget( 
$this );
-               foreach ( $iwResults as $iwPrefix => $results ) {
-                       $out .= $this->iwHeaderHtml( $iwPrefix );
-                       $out .= "<ul class='mw-search-iwresults'>";
-                       foreach ( $results as $result ) {
-                               $out .= $widget->render( $result );
-                       }
-                       $ot .= "</ul>";
-               }
-
-               $out = 
-                       "<div id='mw-search-interwiki'>" .
-                               "<div id='mw-search-interwiki-caption'>" .
-                                       $this->msg( 'search-interwiki-caption' 
)->text() . 
-                               "</div>" .
-                               $out .
-                       "</div>";
-
-               // convert the whole thing to desired language variant
-               return $wgContLang->convert( $out );
-       }
-
-       protected function iwHeaderHtml( $iwPrefix ) {
-               if ( isset( $this->customCaptions[$iwPrefix] ) ) {
-                       $caption = $this->customCaptions[$iwPrefix];
-               } else {
-                       $iwLookup = 
MediaWiki\MediaWikiServices::getInstance()->getInterwikiLookup();
-                       $interwiki = $iwLookup->fetch( $iwPrefix );
-                       $parsed = wfParseUrl( wfExpandUrl( $interwiki ? 
$interwiki->getURL() : '/' ) );
-                       $caption = $this->msg( 'search-interwiki-default', 
$parsed['host'] )->text();
-               }
-               $searchLink = Linker::linkKnown(
-                       Title::newFromText( "$iwPrefix:Special:Search" ),
-                       $this->msg( 'search-interwiki-more' )->text(),
-                       [],
-                       [
-                               'search' => $query,
-                               'fulltext' => 1,
-                       ]
-               );
-               return
-                       "<div class='mw-search-interwiki-project'>" .
-                               "<span 
class='mw-search-interwiki-more'>{$searchLink}</span>" .
-                               $caption .
-                       "</div>";
        }
 
        /**
diff --git a/includes/widget/BasicSearchResultSetWidget.php 
b/includes/widget/BasicSearchResultSetWidget.php
new file mode 100644
index 0000000..182437b
--- /dev/null
+++ b/includes/widget/BasicSearchResultSetWidget.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace MediaWiki\Widget;
+
+use SearchResultSet;
+use SpecialSearch;
+
+class BasicSearchResultSetWidget {
+       /** @var SpecialSearch */
+       protected $specialPage;
+       /** @var SearchResultWidget */
+       protected $resultWidget;
+       /** @var InterwikiSearchResultSetWidget */
+       protected $sidebarWidget;
+
+       public function __construct( SpecialSearch $specialPage, 
SearchResultWidget $resultWidget, InterwikiSearchResultSetWidget $sidbarWidget 
) {
+               $this->specialPage = $specialPage;
+               $this->resultWidget = $resultWidget;
+               $this->sidbarWidget = $sidbarWidget;
+       }
+
+       public function render( $term, $offset, SearchResultSet $titleResultSet 
= null, SearchResultSet $testResultSet = null ) {
+               global $wgContLang;
+
+               $hasTitle = $titleResultSet ? $titleResultSet->numRows() > 0 : 
false;
+               $hasText = $testResultSet ? $testResultSet->numRows() > 0 : 
false;
+               $hasSecondary = $testResultSet
+                       ? $testResultSet->hasInterwikiResults( 
SearchResultSet::SECONDARY_RESULTS )
+                       : false;
+               $hasSecondaryInline = $testResultSet
+                       ? $testResultSet->hasInterwikiResults( 
SearchResultSet::INLINE_RESULTS )
+                       : false;
+
+
+               if ( !$hasTitle && !$hasText && !$hasSecondary && 
!$hasSecondaryInline ) {
+                       return '';
+               }
+
+               $out = '';
+               if ( $hasTitle ) {
+                       $out .= $this->header( $this->specialPage->msg( 
'titlematches' )->text() )
+                               . $this->renderOne( $titleResultSet );
+               }
+
+               if ( $hasText ) {
+                       if ( $hasTitle ) {
+                               $out .= "<div 
class='mw-search-visualclear'></div>" .
+                                       $this->header( $this->specialPage->msg( 
'textmatches' ) );
+                       }
+                       $out .= $this->renderOne( $testResultSet, $offset );
+               }
+
+               if ( $hasSecondaryInline ) {
+                       foreach ( $testResultSet->getInterwikiResults( 
SearchResultSet::INLINE_RESULTS ) as $interwiki => $results ) {
+                               if ( $results instanceof Status || 
$results->numRows() === 0 ) {
+                                       // ignore bad interwikis for now
+                                       continue;
+                               }
+                               $out .=
+                                       "<p class=>'mw-search-interwiki-header 
mw-search-visualclear'>" .
+                                               $this->specialPage->msg( 
"search-interwiki-results-{$interwiki}" )->parse() .
+                                       "</p>";
+                               $out .= $this->renderOne( $results, $offset );
+                       }
+               }
+
+               if ( $hasSecondary ) {
+                       $out .= $this->sidbarWidget->render(
+                               $term,
+                               $testResultSet->getInterwikiResults( 
SearchResultSet::SECONDARY_RESULTS )
+                       );
+               }
+
+               // Convert the whole thing to desired language variant
+               return $wgContLang->convert( $out );
+       }
+
+       protected function renderOne( SearchResultSet $resultSet, $offset ) {
+               global $wgContLang;
+
+               $terms = $wgContLang->convertForSearchResult( 
$resultSet->termMatches() );
+
+               $hits = [];
+               $result = $resultSet->next();
+               while ( $result ) {
+                       $hits[] .= $this->resultWidget->render( $result, 
$terms, $offset++ );
+                       $result = $resultSet->next();
+               }
+
+               return "<ul class='mw-search-results'>" . implode( '', $hits ) 
. "</ul>";
+       }
+}
diff --git a/includes/widget/BasicSearchResultWidget.php 
b/includes/widget/FullSearchResultWidget.php
similarity index 85%
rename from includes/widget/BasicSearchResultWidget.php
rename to includes/widget/FullSearchResultWidget.php
index 9627cbe..8e674a9 100644
--- a/includes/widget/BasicSearchResultWidget.php
+++ b/includes/widget/FullSearchResultWidget.php
@@ -8,7 +8,14 @@
 use SpecialSearch;
 use Title;
 
-class BasicSearchResultWidget {
+/**
+ * Renders a 'full' multi-line search result with metadata.
+ *
+ *  The Title
+ *  some *highlighted* *text* about the search result
+ *  5KB (651 words) - 12:40, 6 Aug 2016
+ */
+class FullSearchResultWidget implements SearchResultWidget {
        /** @var SpecialSearch */
        protected $specialPage;
 
@@ -31,7 +38,7 @@
 
                $link = $this->generateMainLinkHtml( $result );
                // If page content is not readable, just return ths title.
-               // This is not quite safe, but better than showing excerpts 
from 
+               // This is not quite safe, but better than showing excerpts from
                // non-readable pages. Note that hiding the entry entirely would
                // screw up paging (really?).
                if ( !$result->getTitle()->userCan( 'read', 
$this->specialPage->getUser() ) ) {
@@ -46,9 +53,14 @@
                        $this->specialPage->getUser()
                );
                list( $file, $desc, $thumb ) = $this->generateFileHtml( $result 
);
-               $extract = "<div class='searchresult'>" .
-                               $result->getTextSnippet( $terms ) .
-                       "</div>";
+               $snippet = $result->getTextSnippet( $terms );
+               if ( $snippet ) {
+                       $extract = "<div class='searchresult'>" .
+                                       $result->getTextSnippet( $terms ) .
+                               "</div>";
+               } else {
+                       $extract = '';
+               }
 
                if ( $thumb === null ) {
                        // If no thumb, then the description is about size
@@ -63,7 +75,7 @@
                        if ( !Hooks::run( 'ShowSearchHit', [
                                $this->specialPage, $result, $terms,
                                &$link, &$redirect, &$section, &$extract,
-                               &$score, &$size, &$date, &$related, &$html 
+                               &$score, &$size, &$date, &$related, &$html
                        ] ) ) {
                                return $html;
                        }
@@ -71,14 +83,14 @@
 
                // All the pieces have been collected. Now generate the final 
HTML
                $joined = "{$link} {$redirect} {$category} {$section} {$file}";
-               $meta = "<div class='mw-search-result-data'>{$desc} - 
{$date}</div>";
+               $meta = $this->buildMeta( $desc, $date );
 
                if ( $thumb === null ) {
-                       $html = 
+                       $html =
                                "<div 
class='mw-search-result-heading'>{$joined}</div>" .
                                "{$extract} {$meta}";
                } else {
-                       $html = 
+                       $html =
                                "<table class='searchResultImage'>" .
                                        "<tr>" .
                                                "<td style='width: 120px; 
text-align: center; vertical-align: top'>" .
@@ -119,9 +131,9 @@
 
        protected function generateAltTitleHtml( $msgKey, Title $title = null, 
$text ) {
                $inner = $title === null
-                       ? $text 
+                       ? $text
                        : Linker::linkKnown( $title, $text ?: null );
-               
+
                return "<span class='searchalttitle'>" .
                                $this->specialPage->msg( $msgKey )->rawParams( 
$inner )->text()
                        . "</span>";
@@ -155,7 +167,8 @@
                        return $this->specialPage->msg( 
'search-result-category-size' )
                                ->numParams( $cat->getPageCount(), 
$cat->getSubcatCount(), $cat->getFileCount() )
                                ->escaped();
-               } else {
+               // TODO: This is a bit odd...but requires changing the i18n 
message to fix
+               } elseif ( $result->getByteSize() !== null || 
$result->getWordCount() > 0 ) {
                        $lang = $this->specialPage->getLanguage();
                        $bytes = $lang->formatSize( $result->getByteSize() );
                        $words = $result->getWordCount();
@@ -164,6 +177,8 @@
                                ->numParams( $words )
                                ->escaped();
                }
+
+               return '';
        }
 
        /**
@@ -200,4 +215,18 @@
 
                return [ $html, $descHtml, $thumbHtml ];
        }
+
+       protected function buildMeta( $desc, $date ) {
+               if ( $desc && $date ) {
+                       $meta = "{$desc} - {$date}";
+               } elseif ( $desc ) {
+                       $meta = $desc;
+               } elseif ( $date ) {
+                       $meta = $date;
+               } else {
+                       return '';
+               }
+
+               return "<div class='mw-search-result-data'>{$meta}</div>";
+       }
 }
diff --git a/includes/widget/InterwikiSearchResultSetWidget.php 
b/includes/widget/InterwikiSearchResultSetWidget.php
new file mode 100644
index 0000000..2c50c11
--- /dev/null
+++ b/includes/widget/InterwikiSearchResultSetWidget.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace MediaWiki\Widget;
+
+use Linker;
+use SpecialSearch;
+use Title;
+
+class InterwikiSearchResultSetWidget {
+       /** @var SpecialSearch */
+       protected $specialSearch;
+       /** @var SearchResultWidget */
+       protected $resultWidget;
+       /** @var string[]|null */
+       protected $customCaptions;
+
+       public function __construct( SpecialSearch $specialSearch, 
SearchResultWidget $resultWidget ) {
+               $this->specialSearch = $specialSearch;
+               $this->resultWidget = $resultWidget;
+       }
+
+       /**
+        * @var string $term
+        * @var SearchResultSet|SearchResultSet[] $resultSets
+        */
+       public function render( $term, $resultSets ) {
+               global $wgContLang;
+
+               if ( !is_array( $resultSets ) ) {
+                       $resultSets = [$resultSets];
+               }
+
+               $this->loadCustomCaptions();
+
+               $iwResults = [];
+               foreach ( $resultSets as $resultSet ) {
+                       $result = $resultSet->next();
+                       while ( $result ) {
+                               if ( !$result->isBrokenTitle() ) {
+                                       
$iwResults[$result->getTitle()->getInterwiki()][] = $result;
+                               }
+                               $result = $resultSet->next();
+                       }
+               }
+
+               $out = '';
+               foreach ( $iwResults as $iwPrefix => $results ) {
+                       $out .= $this->headerHtml( $iwPrefix );
+                       $out .= "<ul class='mw-search-iwresults'>";
+                       foreach ( $results as $result ) {
+                               $out .= $this->resultWidget->render( $result );
+                       }
+                       $out .= "</ul>";
+               }
+
+               return
+                       "<div id='mw-search-interwiki'>" .
+                               "<div id='mw-search-interwiki-caption'>" .
+                                       $this->specialSearch->msg( 
'search-interwiki-caption' )->text() .
+                               '</div>' .
+                               $out .
+                       "</div>";
+       }
+
+       protected function headerHtml( $iwPrefix ) {
+               if ( isset( $this->customCaptions[$iwPrefix] ) ) {
+                       $caption = $this->customCaptions[$iwPrefix];
+               } else {
+                       $iwLookup = 
\MediaWiki\MediaWikiServices::getInstance()->getInterwikiLookup();
+                       $interwiki = $iwLookup->fetch( $iwPrefix );
+                       $parsed = wfParseUrl( wfExpandUrl( $interwiki ? 
$interwiki->getURL() : '/' ) );
+                       $caption = $this->specialSearch->msg( 
'search-interwiki-default', $parsed['host'] )->text();
+               }
+               $searchLink = Linker::linkKnown(
+                       Title::newFromText( "$iwPrefix:Special:Search" ),
+                       $this->specialSearch->msg( 'search-interwiki-more' 
)->text(),
+                       [],
+                       [
+                               'search' => $query,
+                               'fulltext' => 1,
+                       ]
+               );
+               return
+                       "<div class='mw-search-interwiki-project'>" .
+                               "<span 
class='mw-search-interwiki-more'>{$searchLink}</span>" .
+                               $caption .
+               "</div>";
+       }
+
+       protected function loadCustomCaptions() {
+               if ( $this->customCaptions !== null ) {
+                       return;
+               }
+
+               $this->customCaptions = [];
+               $customLines = explode( "\n", $this->specialSearch->msg( 
'search-interwiki-custom' )->text() );
+               foreach ( $customLines as $line ) {
+                       $parts = explode( ':', $line, 2 );
+                       if ( count( $parts ) === 2 ) {
+                               $this->customCaptions[$parts[0]] = $parts[1];
+                       }
+               }
+       }
+}
diff --git a/includes/widget/SearchResultWidget.php 
b/includes/widget/SearchResultWidget.php
new file mode 100644
index 0000000..30916ff
--- /dev/null
+++ b/includes/widget/SearchResultWidget.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace MediaWiki\Widget;
+
+use SearchResult;
+
+interface SearchResultWidget {
+       /**
+        * @param SearchResult $result The result to render
+        * @param string $terms Terms to be highlighted (@see 
SearchResult::getTextSnippet)
+        * @param int $position The result position, including offset
+        */
+       public function render( SearchResult $result, $terms, $position );
+}
diff --git a/includes/widget/InterwikiSearchResultWidget.php 
b/includes/widget/SimpleSearchResultWidget.php
similarity index 74%
rename from includes/widget/InterwikiSearchResultWidget.php
rename to includes/widget/SimpleSearchResultWidget.php
index b34df7c..4593344 100644
--- a/includes/widget/InterwikiSearchResultWidget.php
+++ b/includes/widget/SimpleSearchResultWidget.php
@@ -7,7 +7,10 @@
 use SpecialSearch;
 use Title;
 
-class InterwikiSearchResultWidget {
+/**
+ * Renders a simple one-line result
+ */
+class SimpleSearchResultWidget implements SearchResultWidget {
        /** @var SpecialSearch */
        protected $specialSearch;
 
@@ -15,7 +18,7 @@
                $this->specialSearch = $specialSearch;
        }
 
-       public function render( SearchResult $result, $lastInterwiki ) {
+       public function render( SearchResult $result, $terms, $position ) {
                $title = $result->getTitle();
                $titleSnippet = $result->getTitleSnippet();
                if ( $titleSnippet === '' ) {
@@ -25,13 +28,9 @@
                $link = Linker::linkKnown( $title, $titleSnippet );
 
                $redirectTitle = $result->getRedirectTitle();
-               $redirectText = $result->getRedirectSnippet();
                $redirect = '';
-               if ( $redirectTitle === null ) {
-                       if ( $redirectText === '' ) {
-                               $redirectText = null;
-                       }
-
+               if ( $redirectTitle !== null ) {
+                       $redirectText = $result->getRedirectSnippet() ?: null;
                        $redirect =
                                "<span class='searchalttitle'>" .
                                        $this->specialSearch->msg( 
'search-redirect' )->rawParams(

-- 
To view, visit https://gerrit.wikimedia.org/r/322015
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Id1d6b357f45a2cf615d9412cc95dd597c724e8b6
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: EBernhardson <ebernhard...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to