MediaWiki REL1_35
SearchFormWidget.php
Go to the documentation of this file.
1<?php
2
4
5use Html;
12use Xml;
13
16 protected $specialSearch;
18 protected $searchConfig;
20 protected $profiles;
24 private $hookRunner;
25
32 public function __construct(
36 array $profiles
37 ) {
38 $this->specialSearch = $specialSearch;
39 $this->searchConfig = $searchConfig;
40 $this->hookContainer = $hookContainer;
41 $this->hookRunner = new HookRunner( $hookContainer );
42 $this->profiles = $profiles;
43 }
44
55 public function render(
56 $profile,
57 $term,
58 $numResults,
59 $totalResults,
60 $offset,
61 $isPowerSearch,
62 array $options = []
63 ) {
64 $user = $this->specialSearch->getUser();
65
66 return '<div class="mw-search-form-wrapper">' .
67 Xml::openElement(
68 'form',
69 [
70 'id' => $isPowerSearch ? 'powersearch' : 'search',
71 // T151903: default to POST in case JS is disabled
72 'method' => ( $isPowerSearch && $user->isLoggedIn() ) ? 'post' : 'get',
73 'action' => wfScript(),
74 ]
75 ) .
76 '<div id="mw-search-top-table">' .
77 $this->shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset, $options ) .
78 '</div>' .
79 "<div class='mw-search-visualclear'></div>" .
80 "<div class='mw-search-profile-tabs'>" .
81 $this->profileTabsHtml( $profile, $term ) .
82 "<div style='clear:both'></div>" .
83 "</div>" .
84 $this->optionsHtml( $term, $isPowerSearch, $profile ) .
85 '</form>' .
86 '</div>';
87 }
88
98 protected function shortDialogHtml(
99 $profile,
100 $term,
101 $numResults,
102 $totalResults,
103 $offset,
104 array $options = []
105 ) {
106 $html = '';
107
108 $searchWidget = new SearchInputWidget( $options + [
109 'id' => 'searchText',
110 'name' => 'search',
111 'autofocus' => trim( $term ) === '',
112 'title' => $this->specialSearch->msg( 'searchsuggest-search' )->text(),
113 'value' => $term,
114 'dataLocation' => 'content',
115 'infusable' => true,
116 ] );
117
118 $layout = new \OOUI\ActionFieldLayout( $searchWidget, new \OOUI\ButtonInputWidget( [
119 'type' => 'submit',
120 'label' => $this->specialSearch->msg( 'searchbutton' )->text(),
121 'flags' => [ 'progressive', 'primary' ],
122 ] ), [
123 'align' => 'top',
124 ] );
125
126 $html .= $layout;
127
128 if ( $this->specialSearch->getPrefix() !== '' ) {
129 $html .= Html::hidden( 'prefix', $this->specialSearch->getPrefix() );
130 }
131
132 if ( $totalResults > 0 && $offset < $totalResults ) {
133 $html .= Xml::tags(
134 'div',
135 [
136 'class' => 'results-info',
137 'data-mw-num-results-offset' => $offset,
138 'data-mw-num-results-total' => $totalResults
139 ],
140 $this->specialSearch->msg( 'search-showingresults' )
141 ->numParams( $offset + 1, $offset + $numResults, $totalResults )
142 ->numParams( $numResults )
143 ->parse()
144 );
145 }
146
147 $html .=
148 Html::hidden( 'title', $this->specialSearch->getPageTitle()->getPrefixedText() ) .
149 Html::hidden( 'profile', $profile ) .
150 Html::hidden( 'fulltext', '1' );
151
152 return $html;
153 }
154
162 protected function profileTabsHtml( $profile, $term ) {
163 $bareterm = $this->startsWithImage( $term )
164 ? substr( $term, strpos( $term, ':' ) + 1 )
165 : $term;
166 $lang = $this->specialSearch->getLanguage();
167 $items = [];
168 foreach ( $this->profiles as $id => $profileConfig ) {
169 $profileConfig['parameters']['profile'] = $id;
170 $tooltipParam = isset( $profileConfig['namespace-messages'] )
171 ? $lang->commaList( $profileConfig['namespace-messages'] )
172 : null;
173 $items[] = Xml::tags(
174 'li',
175 [ 'class' => $profile === $id ? 'current' : 'normal' ],
176 $this->makeSearchLink(
177 $bareterm,
178 $this->specialSearch->msg( $profileConfig['message'] )->text(),
179 $this->specialSearch->msg( $profileConfig['tooltip'], $tooltipParam )->text(),
180 $profileConfig['parameters']
181 )
182 );
183 }
184
185 return "<div class='search-types'>" .
186 "<ul>" . implode( '', $items ) . "</ul>" .
187 "</div>";
188 }
189
196 protected function startsWithImage( $term ) {
197 $parts = explode( ':', $term );
198 return count( $parts ) > 1
199 ? MediaWikiServices::getInstance()->getContentLanguage()->getNsIndex( $parts[0] ) ===
200 NS_FILE
201 : false;
202 }
203
213 protected function makeSearchLink( $term, $label, $tooltip, array $params = [] ) {
214 $params += [
215 'search' => $term,
216 'fulltext' => 1,
217 ];
218
219 return Xml::element(
220 'a',
221 [
222 'href' => $this->specialSearch->getPageTitle()->getLocalURL( $params ),
223 'title' => $tooltip,
224 ],
225 $label
226 );
227 }
228
238 protected function optionsHtml( $term, $isPowerSearch, $profile ) {
239 $html = '';
240
241 if ( $isPowerSearch ) {
242 $html .= $this->powerSearchBox( $term, [] );
243 } else {
244 $form = '';
245 $this->getHookRunner()->onSpecialSearchProfileForm(
246 $this->specialSearch, $form, $profile, $term, [] );
247 $html .= $form;
248 }
249
250 return $html;
251 }
252
259 protected function powerSearchBox( $term, array $opts ) {
260 $rows = [];
261 $activeNamespaces = $this->specialSearch->getNamespaces();
262 $langConverter = $this->specialSearch->getLanguage();
263 foreach ( $this->searchConfig->searchableNamespaces() as $namespace => $name ) {
264 $subject = MediaWikiServices::getInstance()->getNamespaceInfo()->
265 getSubject( $namespace );
266 if ( !isset( $rows[$subject] ) ) {
267 $rows[$subject] = "";
268 }
269
270 $name = $langConverter->convertNamespace( $namespace );
271 if ( $name === '' ) {
272 $name = $this->specialSearch->msg( 'blanknamespace' )->text();
273 }
274
275 $rows[$subject] .=
276 '<td>' .
277 Xml::checkLabel(
278 $name,
279 "ns{$namespace}",
280 "mw-search-ns{$namespace}",
281 in_array( $namespace, $activeNamespaces )
282 ) .
283 '</td>';
284 }
285
286 // Lays out namespaces in multiple floating two-column tables so they'll
287 // be arranged nicely while still accomodating diferent screen widths
288 $tableRows = [];
289 foreach ( $rows as $row ) {
290 $tableRows[] = "<tr>{$row}</tr>";
291 }
292 $namespaceTables = [];
293 foreach ( array_chunk( $tableRows, 4 ) as $chunk ) {
294 $namespaceTables[] = implode( '', $chunk );
295 }
296
297 $showSections = [
298 'namespaceTables' => "<table>" . implode( '</table><table>', $namespaceTables ) . '</table>',
299 ];
300 $this->getHookRunner()->onSpecialSearchPowerBox( $showSections, $term, $opts );
301
302 $hidden = '';
303 foreach ( $opts as $key => $value ) {
304 $hidden .= Html::hidden( $key, $value );
305 }
306
307 $divider = "<div class='divider'></div>";
308
309 // Stuff to feed SpecialSearch::saveNamespaces()
310 $user = $this->specialSearch->getUser();
311 $remember = '';
312 if ( $user->isLoggedIn() ) {
313 $remember = $divider . Xml::checkLabel(
314 $this->specialSearch->msg( 'powersearch-remember' )->text(),
315 'nsRemember',
316 'mw-search-powersearch-remember',
317 false,
318 // The token goes here rather than in a hidden field so it
319 // is only sent when necessary (not every form submission)
320 [ 'value' => $user->getEditToken(
321 'searchnamespace',
322 $this->specialSearch->getRequest()
323 ) ]
324 );
325 }
326
327 return "<fieldset id='mw-searchoptions'>" .
328 "<legend>" . $this->specialSearch->msg( 'powersearch-legend' )->escaped() . '</legend>' .
329 "<h4>" . $this->specialSearch->msg( 'powersearch-ns' )->parse() . '</h4>' .
330 // Handled by JavaScript if available
331 '<div id="mw-search-togglebox">' .
332 '<label>' . $this->specialSearch->msg( 'powersearch-togglelabel' )->escaped() . '</label>' .
333 '<input type="button" id="mw-search-toggleall" value="' .
334 $this->specialSearch->msg( 'powersearch-toggleall' )->escaped() . '"/>' .
335 '<input type="button" id="mw-search-togglenone" value="' .
336 $this->specialSearch->msg( 'powersearch-togglenone' )->escaped() . '"/>' .
337 '</div>' .
338 $divider .
339 implode(
340 $divider,
341 $showSections
342 ) .
343 $hidden .
344 $remember .
345 "</fieldset>";
346 }
347
352 protected function getHookContainer() {
354 }
355
362 protected function getHookRunner() {
363 return $this->hookRunner;
364 }
365}
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
This class is a collection of static functions that serve two purposes:
Definition Html.php:49
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
MediaWikiServices is the service locator for the application scope of MediaWiki.
static getInstance()
Returns the global default instance of the top level service locator.
optionsHtml( $term, $isPowerSearch, $profile)
Generates HTML for advanced options available with the currently selected search profile.
startsWithImage( $term)
Check if query starts with image: prefix.
shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset, array $options=[])
profileTabsHtml( $profile, $term)
Generates HTML for the list of available search profiles.
render( $profile, $term, $numResults, $totalResults, $offset, $isPowerSearch, array $options=[])
__construct(SpecialSearch $specialSearch, SearchEngineConfig $searchConfig, HookContainer $hookContainer, array $profiles)
makeSearchLink( $term, $label, $tooltip, array $params=[])
Make a search link with some target namespaces.
Configuration handling class for SearchEngine.
implements Special:Search - Run text & title search and display the output
Module of static functions for generating XML.
Definition Xml.php:28
const NS_FILE
Definition Defines.php:76
if(!isset( $args[0])) $lang