MediaWiki  master
SearchFormWidget.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use Html;
10 use NamespaceInfo;
12 use SpecialSearch;
13 use Xml;
14 
17  protected $specialSearch;
19  protected $searchConfig;
21  protected $profiles;
23  private $hookContainer;
25  private $hookRunner;
29  private $namespaceInfo;
30 
39  public function __construct(
45  array $profiles
46  ) {
47  $this->specialSearch = $specialSearch;
48  $this->searchConfig = $searchConfig;
49  $this->hookContainer = $hookContainer;
50  $this->hookRunner = new HookRunner( $hookContainer );
51  $this->languageConverter = $languageConverter;
52  $this->namespaceInfo = $namespaceInfo;
53  $this->profiles = $profiles;
54  }
55 
66  public function render(
67  $profile,
68  $term,
69  $numResults,
70  $totalResults,
71  $offset,
72  $isPowerSearch,
73  array $options = []
74  ) {
75  $user = $this->specialSearch->getUser();
76 
77  $form = Xml::openElement(
78  'form',
79  [
80  'id' => $isPowerSearch ? 'powersearch' : 'search',
81  // T151903: default to POST in case JS is disabled
82  'method' => ( $isPowerSearch && $user->isRegistered() ) ? 'post' : 'get',
83  'action' => wfScript(),
84  ]
85  ) .
87  'div',
88  [ 'id' => 'mw-search-top-table' ],
89  $this->shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset, $options )
90  ) .
91  Html::rawElement( 'div', [ 'class' => 'mw-search-visualclear' ] ) .
93  'div',
94  [ 'class' => 'mw-search-profile-tabs' ],
95  $this->profileTabsHtml( $profile, $term ) .
96  Html::rawElement( 'div', [ 'style' => 'clear:both' ] )
97  ) .
98  $this->optionsHtml( $term, $isPowerSearch, $profile ) .
99  Xml::closeElement( 'form' );
100 
101  return Html::rawElement( 'div', [ 'class' => 'mw-search-form-wrapper' ], $form );
102  }
103 
113  protected function shortDialogHtml(
114  $profile,
115  $term,
116  $numResults,
117  $totalResults,
118  $offset,
119  array $options = []
120  ) {
121  $html = '';
122 
123  $searchWidget = new SearchInputWidget( $options + [
124  'id' => 'searchText',
125  'name' => 'search',
126  'autofocus' => trim( $term ) === '',
127  'title' => $this->specialSearch->msg( 'searchsuggest-search' )->text(),
128  'value' => $term,
129  'dataLocation' => 'content',
130  'infusable' => true,
131  ] );
132 
133  $layout = new \OOUI\ActionFieldLayout( $searchWidget, new \OOUI\ButtonInputWidget( [
134  'type' => 'submit',
135  'label' => $this->specialSearch->msg( 'searchbutton' )->text(),
136  'flags' => [ 'progressive', 'primary' ],
137  ] ), [
138  'align' => 'top',
139  ] );
140 
141  $html .= $layout;
142 
143  if ( $this->specialSearch->getPrefix() !== '' ) {
144  $html .= Html::hidden( 'prefix', $this->specialSearch->getPrefix() );
145  }
146 
147  if ( $totalResults > 0 && $offset < $totalResults ) {
148  $html .= Xml::tags(
149  'div',
150  [
151  'class' => 'results-info',
152  'data-mw-num-results-offset' => $offset,
153  'data-mw-num-results-total' => $totalResults
154  ],
155  $this->specialSearch->msg( 'search-showingresults' )
156  ->numParams( $offset + 1, $offset + $numResults, $totalResults )
157  ->numParams( $numResults )
158  ->parse()
159  );
160  }
161 
162  $html .=
163  Html::hidden( 'title', $this->specialSearch->getPageTitle()->getPrefixedText() ) .
164  Html::hidden( 'profile', $profile ) .
165  Html::hidden( 'fulltext', '1' );
166 
167  return $html;
168  }
169 
177  protected function profileTabsHtml( $profile, $term ) {
178  $bareterm = $this->startsWithImage( $term )
179  ? substr( $term, strpos( $term, ':' ) + 1 )
180  : $term;
181  $lang = $this->specialSearch->getLanguage();
182  $items = [];
183  foreach ( $this->profiles as $id => $profileConfig ) {
184  $profileConfig['parameters']['profile'] = $id;
185  $tooltipParam = isset( $profileConfig['namespace-messages'] )
186  ? $lang->commaList( $profileConfig['namespace-messages'] )
187  : null;
188  $items[] = Xml::tags(
189  'li',
190  [ 'class' => $profile === $id ? 'current' : 'normal' ],
191  $this->makeSearchLink(
192  $bareterm,
193  $this->specialSearch->msg( $profileConfig['message'] )->text(),
194  $this->specialSearch->msg( $profileConfig['tooltip'], $tooltipParam )->text(),
195  $profileConfig['parameters']
196  )
197  );
198  }
199 
200  return Html::rawElement(
201  'div',
202  [ 'class' => 'search-types' ],
203  Html::rawElement( 'ul', [], implode( '', $items ) )
204  );
205  }
206 
213  protected function startsWithImage( $term ) {
214  $parts = explode( ':', $term );
215  return count( $parts ) > 1
216  ? $this->specialSearch->getContentLanguage()->getNsIndex( $parts[0] ) ===
217  NS_FILE
218  : false;
219  }
220 
230  protected function makeSearchLink( $term, $label, $tooltip, array $params = [] ) {
231  $params += [
232  'search' => $term,
233  'fulltext' => 1,
234  ];
235 
236  return Xml::element(
237  'a',
238  [
239  'href' => $this->specialSearch->getPageTitle()->getLocalURL( $params ),
240  'title' => $tooltip,
241  ],
242  $label
243  );
244  }
245 
255  protected function optionsHtml( $term, $isPowerSearch, $profile ) {
256  $html = '';
257 
258  if ( $isPowerSearch ) {
259  $html .= $this->powerSearchBox( $term, [] );
260  } else {
261  $form = '';
262  $this->getHookRunner()->onSpecialSearchProfileForm(
263  $this->specialSearch, $form, $profile, $term, [] );
264  $html .= $form;
265  }
266 
267  return $html;
268  }
269 
276  protected function powerSearchBox( $term, array $opts ) {
277  $rows = [];
278  $activeNamespaces = $this->specialSearch->getNamespaces();
279  foreach ( $this->searchConfig->searchableNamespaces() as $namespace => $name ) {
280  $subject = $this->namespaceInfo->getSubject( $namespace );
281  if ( !isset( $rows[$subject] ) ) {
282  $rows[$subject] = "";
283  }
284 
285  $name = $this->languageConverter->convertNamespace( $namespace );
286  if ( $name === '' ) {
287  $name = $this->specialSearch->msg( 'blanknamespace' )->text();
288  }
289 
290  $rows[$subject] .= Html::rawElement(
291  'td',
292  [],
294  $name,
295  "ns{$namespace}",
296  "mw-search-ns{$namespace}",
297  in_array( $namespace, $activeNamespaces )
298  )
299  );
300  }
301 
302  // Lays out namespaces in multiple floating two-column tables so they'll
303  // be arranged nicely while still accomodating diferent screen widths
304  $tableRows = [];
305  foreach ( $rows as $row ) {
306  $tableRows[] = Html::rawElement( 'tr', [], $row );
307  }
308  $namespaceTables = [];
309  foreach ( array_chunk( $tableRows, 4 ) as $chunk ) {
310  $namespaceTables[] = implode( '', $chunk );
311  }
312 
313  $showSections = [
314  'namespaceTables' => "<table>" . implode( '</table><table>', $namespaceTables ) . '</table>',
315  ];
316  $this->getHookRunner()->onSpecialSearchPowerBox( $showSections, $term, $opts );
317 
318  $hidden = '';
319  foreach ( $opts as $key => $value ) {
320  $hidden .= Html::hidden( $key, $value );
321  }
322 
323  $divider = Html::rawElement( 'div', [ 'class' => 'divider' ], '' );
324 
325  // Stuff to feed SpecialSearch::saveNamespaces()
326  $user = $this->specialSearch->getUser();
327  $remember = '';
328  if ( $user->isRegistered() ) {
329  $remember = $divider . Xml::checkLabel(
330  $this->specialSearch->msg( 'powersearch-remember' )->text(),
331  'nsRemember',
332  'mw-search-powersearch-remember',
333  false,
334  // The token goes here rather than in a hidden field so it
335  // is only sent when necessary (not every form submission)
336  [ 'value' => $user->getEditToken(
337  'searchnamespace',
338  $this->specialSearch->getRequest()
339  ) ]
340  );
341  }
342 
343  // Temporary variables to reduce nesting needed
344  $toggleBoxContents =
345  Html::rawElement( 'label', [], $this->specialSearch->msg( 'powersearch-togglelabel' )->escaped() ) .
347  'input',
348  [
349  'type' => 'button',
350  'id' => 'mw-search-toggleall',
351  'value' => $this->specialSearch->msg( 'powersearch-toggleall' )->text(),
352  ]
353  ) .
355  'input',
356  [
357  'type' => 'button',
358  'id' => 'mw-search-togglenone',
359  'value' => $this->specialSearch->msg( 'powersearch-togglenone' )->text(),
360  ]
361  );
362  $fieldSetContents =
363  Html::rawElement( 'legend', [], $this->specialSearch->msg( 'powersearch-legend' )->escaped() ) .
364  Html::rawElement( 'h4', [], $this->specialSearch->msg( 'powersearch-ns' )->parse() ) .
365  // Handled by JavaScript if available
367  'div',
368  [ 'id' => 'mw-search-togglebox' ],
369  $toggleBoxContents
370  ) .
371  $divider . implode( $divider, $showSections ) . $hidden . $remember;
372 
373  return Html::rawElement( 'fieldset', [ 'id' => 'mw-searchoptions' ], $fieldSetContents );
374  }
375 
380  protected function getHookContainer() {
381  return $this->hookContainer;
382  }
383 
390  protected function getHookRunner() {
391  return $this->hookRunner;
392  }
393 }
MediaWiki\Search\SearchWidgets\SearchFormWidget
Definition: SearchFormWidget.php:15
MediaWiki\Search\SearchWidgets\SearchFormWidget\__construct
__construct(SpecialSearch $specialSearch, SearchEngineConfig $searchConfig, HookContainer $hookContainer, ILanguageConverter $languageConverter, NamespaceInfo $namespaceInfo, array $profiles)
Definition: SearchFormWidget.php:39
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
MediaWiki\Search\SearchWidgets\SearchFormWidget\$hookRunner
HookRunner $hookRunner
Definition: SearchFormWidget.php:25
MediaWiki\Search\SearchWidgets\SearchFormWidget\startsWithImage
startsWithImage( $term)
Check if query starts with image: prefix.
Definition: SearchFormWidget.php:213
MediaWiki\Search\SearchWidgets\SearchFormWidget\$profiles
array $profiles
Definition: SearchFormWidget.php:21
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:110
MediaWiki\Search\SearchWidgets\SearchFormWidget\getHookRunner
getHookRunner()
Definition: SearchFormWidget.php:390
MediaWiki\Search\SearchWidgets\SearchFormWidget\$specialSearch
SpecialSearch $specialSearch
Definition: SearchFormWidget.php:17
wfScript
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
Definition: GlobalFunctions.php:2282
MediaWiki\Search\SearchWidgets\SearchFormWidget\$namespaceInfo
NamespaceInfo $namespaceInfo
Definition: SearchFormWidget.php:29
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:41
MediaWiki\Widget\SearchInputWidget
Search input widget.
Definition: SearchInputWidget.php:11
Html\hidden
static hidden( $name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
Definition: Html.php:831
ILanguageConverter
The shared interface for all language converters.
Definition: ILanguageConverter.php:29
MediaWiki\Search\SearchWidgets\SearchFormWidget\makeSearchLink
makeSearchLink( $term, $label, $tooltip, array $params=[])
Make a search link with some target namespaces.
Definition: SearchFormWidget.php:230
MediaWiki\Search\SearchWidgets\SearchFormWidget\optionsHtml
optionsHtml( $term, $isPowerSearch, $profile)
Generates HTML for advanced options available with the currently selected search profile.
Definition: SearchFormWidget.php:255
MediaWiki\Search\SearchWidgets\SearchFormWidget\shortDialogHtml
shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset, array $options=[])
Definition: SearchFormWidget.php:113
Xml\tags
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:132
SpecialSearch
implements Special:Search - Run text & title search and display the output
Definition: SpecialSearch.php:41
MediaWiki\Search\SearchWidgets\SearchFormWidget\getHookContainer
getHookContainer()
Definition: SearchFormWidget.php:380
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:119
MediaWiki\Search\SearchWidgets
Definition: BasicSearchResultSetWidget.php:3
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
MediaWiki\Search\SearchWidgets\SearchFormWidget\powerSearchBox
powerSearchBox( $term, array $opts)
Definition: SearchFormWidget.php:276
MediaWiki\Search\SearchWidgets\SearchFormWidget\$languageConverter
ILanguageConverter $languageConverter
Definition: SearchFormWidget.php:27
SearchEngineConfig
Configuration handling class for SearchEngine.
Definition: SearchEngineConfig.php:12
MediaWiki\HookContainer\HookContainer
HookContainer class.
Definition: HookContainer.php:45
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:35
MediaWiki\HookContainer\HookRunner
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:554
MediaWiki\Search\SearchWidgets\SearchFormWidget\profileTabsHtml
profileTabsHtml( $profile, $term)
Generates HTML for the list of available search profiles.
Definition: SearchFormWidget.php:177
NS_FILE
const NS_FILE
Definition: Defines.php:70
MediaWiki\Search\SearchWidgets\SearchFormWidget\$hookContainer
HookContainer $hookContainer
Definition: SearchFormWidget.php:23
Xml
Module of static functions for generating XML.
Definition: Xml.php:28
MediaWiki\Search\SearchWidgets\SearchFormWidget\render
render( $profile, $term, $numResults, $totalResults, $offset, $isPowerSearch, array $options=[])
Definition: SearchFormWidget.php:66
MediaWiki\Search\SearchWidgets\SearchFormWidget\$searchConfig
SearchEngineConfig $searchConfig
Definition: SearchFormWidget.php:19
Xml\checkLabel
static checkLabel( $label, $name, $id, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox with a label.
Definition: Xml.php:425
Html
This class is a collection of static functions that serve two purposes:
Definition: Html.php:49