InterwikiSearchResultSetWidget.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. namespace MediaWiki\Widget\Search;
  3. use MediaWiki\Interwiki\InterwikiLookup;
  4. use MediaWiki\Linker\LinkRenderer;
  5. use ISearchResultSet;
  6. use SpecialSearch;
  7. use Title;
  8. use Html;
  9. use OOUI;
  10. /**
  11. * Renders one or more ISearchResultSets into a sidebar grouped by
  12. * interwiki prefix. Includes a per-wiki header indicating where
  13. * the results are from.
  14. */
  15. class InterwikiSearchResultSetWidget implements SearchResultSetWidget {
  16. /** @var SpecialSearch $specialSearch */
  17. protected $specialSearch;
  18. /** @var SearchResultWidget $resultWidget */
  19. protected $resultWidget;
  20. /** @var string[]|null $customCaptions */
  21. protected $customCaptions;
  22. /** @var LinkRenderer $linkRenderer */
  23. protected $linkRenderer;
  24. /** @var InterwikiLookup $iwLookup */
  25. protected $iwLookup;
  26. /** @var \OutputPage $output */
  27. protected $output;
  28. /** @var bool $showMultimedia */
  29. protected $showMultimedia;
  30. public function __construct(
  31. SpecialSearch $specialSearch,
  32. SearchResultWidget $resultWidget,
  33. LinkRenderer $linkRenderer,
  34. InterwikiLookup $iwLookup,
  35. $showMultimedia = false
  36. ) {
  37. $this->specialSearch = $specialSearch;
  38. $this->resultWidget = $resultWidget;
  39. $this->linkRenderer = $linkRenderer;
  40. $this->iwLookup = $iwLookup;
  41. $this->output = $specialSearch->getOutput();
  42. $this->showMultimedia = $showMultimedia;
  43. }
  44. /**
  45. * @param string $term User provided search term
  46. * @param ISearchResultSet|ISearchResultSet[] $resultSets List of interwiki
  47. * results to render.
  48. * @return string HTML
  49. */
  50. public function render( $term, $resultSets ) {
  51. if ( !is_array( $resultSets ) ) {
  52. $resultSets = [ $resultSets ];
  53. }
  54. $this->loadCustomCaptions();
  55. if ( $this->showMultimedia ) {
  56. $this->output->addModules( 'mediawiki.special.search.commonsInterwikiWidget' );
  57. }
  58. $this->output->addModuleStyles( 'mediawiki.special.search.interwikiwidget.styles' );
  59. $iwResults = [];
  60. foreach ( $resultSets as $resultSet ) {
  61. foreach ( $resultSet as $result ) {
  62. if ( !$result->isBrokenTitle() ) {
  63. $iwResults[$result->getTitle()->getInterwiki()][] = $result;
  64. }
  65. }
  66. }
  67. $iwResultSetPos = 1;
  68. $iwResultListOutput = '';
  69. foreach ( $iwResults as $iwPrefix => $results ) {
  70. // TODO: Assumes interwiki results are never paginated
  71. $position = 0;
  72. $iwResultItemOutput = '';
  73. foreach ( $results as $result ) {
  74. $iwResultItemOutput .= $this->resultWidget->render( $result, $position++ );
  75. }
  76. $footerHtml = $this->footerHtml( $term, $iwPrefix );
  77. $iwResultListOutput .= Html::rawElement( 'li',
  78. [
  79. 'class' => 'iw-resultset',
  80. 'data-iw-resultset-pos' => $iwResultSetPos,
  81. 'data-iw-resultset-source' => $iwPrefix
  82. ],
  83. $iwResultItemOutput .
  84. $footerHtml
  85. );
  86. $iwResultSetPos++;
  87. }
  88. return Html::rawElement(
  89. 'div',
  90. [ 'id' => 'mw-interwiki-results' ],
  91. Html::rawElement(
  92. 'p',
  93. [ 'class' => 'iw-headline' ],
  94. $this->specialSearch->msg( 'search-interwiki-caption' )->parse()
  95. ) .
  96. Html::rawElement(
  97. 'ul', [ 'class' => 'iw-results', ], $iwResultListOutput
  98. )
  99. );
  100. }
  101. /**
  102. * Generates an HTML footer for the given interwiki prefix
  103. *
  104. * @param string $term User provided search term
  105. * @param string $iwPrefix Interwiki prefix of wiki to show footer for
  106. * @return string HTML
  107. */
  108. protected function footerHtml( $term, $iwPrefix ) {
  109. $href = Title::makeTitle( NS_SPECIAL, 'Search', null, $iwPrefix )->getLocalURL(
  110. [ 'search' => $term, 'fulltext' => 1 ]
  111. );
  112. $interwiki = $this->iwLookup->fetch( $iwPrefix );
  113. $parsed = wfParseUrl( wfExpandUrl( $interwiki ? $interwiki->getURL() : '/' ) );
  114. $caption = $this->customCaptions[$iwPrefix] ??
  115. $this->specialSearch->msg( 'search-interwiki-default', $parsed['host'] )->escaped();
  116. $searchLink = Html::rawElement( 'em', null,
  117. Html::rawElement( 'a', [ 'href' => $href, 'target' => '_blank' ], $caption )
  118. );
  119. return Html::rawElement( 'div',
  120. [ 'class' => 'iw-result__footer' ],
  121. $this->iwIcon( $iwPrefix ) . $searchLink );
  122. }
  123. protected function loadCustomCaptions() {
  124. if ( $this->customCaptions !== null ) {
  125. return;
  126. }
  127. $this->customCaptions = [];
  128. $customLines = explode( "\n", $this->specialSearch->msg( 'search-interwiki-custom' )->escaped() );
  129. foreach ( $customLines as $line ) {
  130. $parts = explode( ':', $line, 2 );
  131. if ( count( $parts ) === 2 ) {
  132. $this->customCaptions[$parts[0]] = $parts[1];
  133. }
  134. }
  135. }
  136. /**
  137. * Generates a custom OOUI icon element with a favicon as the image.
  138. * The favicon image URL is generated by parsing the interwiki URL
  139. * and returning the default location of the favicon for that domain,
  140. * which is assumed to be '/favicon.ico'.
  141. *
  142. * @param string $iwPrefix Interwiki prefix
  143. * @return OOUI\IconWidget
  144. */
  145. protected function iwIcon( $iwPrefix ) {
  146. $interwiki = $this->iwLookup->fetch( $iwPrefix );
  147. $parsed = wfParseUrl( wfExpandUrl( $interwiki ? $interwiki->getURL() : '/' ) );
  148. $iwIconUrl = $parsed['scheme'] .
  149. $parsed['delimiter'] .
  150. $parsed['host'] .
  151. ( isset( $parsed['port'] ) ? ':' . $parsed['port'] : '' ) .
  152. '/favicon.ico';
  153. $iwIcon = new OOUI\IconWidget( [
  154. 'icon' => 'favicon'
  155. ] );
  156. $iwIcon->setAttributes( [ 'style' => "background-image:url($iwIconUrl);" ] );
  157. return $iwIcon;
  158. }
  159. }