summaryrefslogtreecommitdiff
path: root/www/wiki/includes/widget/search/SearchFormWidget.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/includes/widget/search/SearchFormWidget.php')
-rw-r--r--www/wiki/includes/widget/search/SearchFormWidget.php314
1 files changed, 314 insertions, 0 deletions
diff --git a/www/wiki/includes/widget/search/SearchFormWidget.php b/www/wiki/includes/widget/search/SearchFormWidget.php
new file mode 100644
index 00000000..2c885630
--- /dev/null
+++ b/www/wiki/includes/widget/search/SearchFormWidget.php
@@ -0,0 +1,314 @@
+<?php
+
+namespace MediaWiki\Widget\Search;
+
+use Hooks;
+use Html;
+use MediaWiki\Widget\SearchInputWidget;
+use MWNamespace;
+use SearchEngineConfig;
+use SpecialSearch;
+use Xml;
+
+class SearchFormWidget {
+ /** @var SpecialSearch */
+ protected $specialSearch;
+ /** @var SearchEngineConfig */
+ protected $searchConfig;
+ /** @var array */
+ protected $profiles;
+
+ /**
+ * @param SpecialSearch $specialSearch
+ * @param SearchEngineConfig $searchConfig
+ * @param array $profiles
+ */
+ public function __construct(
+ SpecialSearch $specialSearch,
+ SearchEngineConfig $searchConfig,
+ array $profiles
+ ) {
+ $this->specialSearch = $specialSearch;
+ $this->searchConfig = $searchConfig;
+ $this->profiles = $profiles;
+ }
+
+ /**
+ * @param string $profile The current search profile
+ * @param string $term The current search term
+ * @param int $numResults The number of results shown
+ * @param int $totalResults The total estimated results found
+ * @param int $offset Current offset in search results
+ * @param bool $isPowerSearch Is the 'advanced' section open?
+ * @return string HTML
+ */
+ public function render(
+ $profile,
+ $term,
+ $numResults,
+ $totalResults,
+ $offset,
+ $isPowerSearch
+ ) {
+ return Xml::openElement(
+ 'form',
+ [
+ 'id' => $isPowerSearch ? 'powersearch' : 'search',
+ 'method' => 'get',
+ 'action' => wfScript(),
+ ]
+ ) .
+ '<div id="mw-search-top-table">' .
+ $this->shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset ) .
+ '</div>' .
+ "<div class='mw-search-visualclear'></div>" .
+ "<div class='mw-search-profile-tabs'>" .
+ $this->profileTabsHtml( $profile, $term ) .
+ "<div style='clear:both'></div>" .
+ "</div>" .
+ $this->optionsHtml( $term, $isPowerSearch, $profile ) .
+ '</form>';
+ }
+
+ /**
+ * @param string $profile The current search profile
+ * @param string $term The current search term
+ * @param int $numResults The number of results shown
+ * @param int $totalResults The total estimated results found
+ * @param int $offset Current offset in search results
+ * @return string HTML
+ */
+ protected function shortDialogHtml( $profile, $term, $numResults, $totalResults, $offset ) {
+ $html = '';
+
+ $searchWidget = new SearchInputWidget( [
+ 'id' => 'searchText',
+ 'name' => 'search',
+ 'autofocus' => trim( $term ) === '',
+ 'value' => $term,
+ 'dataLocation' => 'content',
+ 'infusable' => true,
+ ] );
+
+ $layout = new \OOUI\ActionFieldLayout( $searchWidget, new \OOUI\ButtonInputWidget( [
+ 'type' => 'submit',
+ 'label' => $this->specialSearch->msg( 'searchbutton' )->text(),
+ 'flags' => [ 'progressive', 'primary' ],
+ ] ), [
+ 'align' => 'top',
+ ] );
+
+ $html .= $layout;
+
+ if ( $totalResults > 0 && $offset < $totalResults ) {
+ $html .= Xml::tags(
+ 'div',
+ [
+ 'class' => 'results-info',
+ 'data-mw-num-results-offset' => $offset,
+ 'data-mw-num-results-total' => $totalResults
+ ],
+ $this->specialSearch->msg( 'search-showingresults' )
+ ->numParams( $offset + 1, $offset + $numResults, $totalResults )
+ ->numParams( $numResults )
+ ->parse()
+ );
+ }
+
+ $html .=
+ Html::hidden( 'title', $this->specialSearch->getPageTitle()->getPrefixedText() ) .
+ Html::hidden( 'profile', $profile ) .
+ Html::hidden( 'fulltext', '1' );
+
+ return $html;
+ }
+
+ /**
+ * Generates HTML for the list of available search profiles.
+ *
+ * @param string $profile The currently selected profile
+ * @param string $term The user provided search terms
+ * @return string HTML
+ */
+ protected function profileTabsHtml( $profile, $term ) {
+ $bareterm = $this->startsWithImage( $term )
+ ? substr( $term, strpos( $term, ':' ) + 1 )
+ : $term;
+ $lang = $this->specialSearch->getLanguage();
+ $items = [];
+ foreach ( $this->profiles as $id => $profileConfig ) {
+ $profileConfig['parameters']['profile'] = $id;
+ $tooltipParam = isset( $profileConfig['namespace-messages'] )
+ ? $lang->commaList( $profileConfig['namespace-messages'] )
+ : null;
+ $items[] = Xml::tags(
+ 'li',
+ [ 'class' => $profile === $id ? 'current' : 'normal' ],
+ $this->makeSearchLink(
+ $bareterm,
+ $this->specialSearch->msg( $profileConfig['message'] )->text(),
+ $this->specialSearch->msg( $profileConfig['tooltip'], $tooltipParam )->text(),
+ $profileConfig['parameters']
+ )
+ );
+ }
+
+ return "<div class='search-types'>" .
+ "<ul>" . implode( '', $items ) . "</ul>" .
+ "</div>";
+ }
+
+ /**
+ * Check if query starts with image: prefix
+ *
+ * @param string $term The string to check
+ * @return bool
+ */
+ protected function startsWithImage( $term ) {
+ global $wgContLang;
+
+ $parts = explode( ':', $term );
+ return count( $parts ) > 1
+ ? $wgContLang->getNsIndex( $parts[0] ) === NS_FILE
+ : false;
+ }
+
+ /**
+ * Make a search link with some target namespaces
+ *
+ * @param string $term The term to search for
+ * @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, $label, $tooltip, array $params = [] ) {
+ $params += [
+ 'search' => $term,
+ 'fulltext' => 1,
+ ];
+
+ return Xml::element(
+ 'a',
+ [
+ 'href' => $this->specialSearch->getPageTitle()->getLocalURL( $params ),
+ 'title' => $tooltip,
+ ],
+ $label
+ );
+ }
+
+ /**
+ * Generates HTML for advanced options available with the currently
+ * selected search profile.
+ *
+ * @param string $term User provided search term
+ * @param bool $isPowerSearch Is the advanced search profile enabled?
+ * @param string $profile The current search profile
+ * @return string HTML
+ */
+ protected function optionsHtml( $term, $isPowerSearch, $profile ) {
+ $html = '';
+
+ if ( $isPowerSearch ) {
+ $html .= $this->powerSearchBox( $term, [] );
+ } else {
+ $form = '';
+ Hooks::run( 'SpecialSearchProfileForm', [
+ $this->specialSearch, &$form, $profile, $term, []
+ ] );
+ $html .= $form;
+ }
+
+ return $html;
+ }
+
+ /**
+ * @param string $term The current search term
+ * @param array $opts Additional key/value pairs that will be submitted
+ * with the generated form.
+ * @return string HTML
+ */
+ protected function powerSearchBox( $term, array $opts ) {
+ global $wgContLang;
+
+ $rows = [];
+ $activeNamespaces = $this->specialSearch->getNamespaces();
+ foreach ( $this->searchConfig->searchableNamespaces() as $namespace => $name ) {
+ $subject = MWNamespace::getSubject( $namespace );
+ if ( !isset( $rows[$subject] ) ) {
+ $rows[$subject] = "";
+ }
+
+ $name = $wgContLang->getConverter()->convertNamespace( $namespace );
+ if ( $name === '' ) {
+ $name = $this->specialSearch->msg( 'blanknamespace' )->text();
+ }
+
+ $rows[$subject] .=
+ '<td>' .
+ Xml::checkLabel(
+ $name,
+ "ns{$namespace}",
+ "mw-search-ns{$namespace}",
+ in_array( $namespace, $activeNamespaces )
+ ) .
+ '</td>';
+ }
+
+ // Lays out namespaces in multiple floating two-column tables so they'll
+ // be arranged nicely while still accomodating diferent screen widths
+ $tableRows = [];
+ foreach ( $rows as $row ) {
+ $tableRows[] = "<tr>{$row}</tr>";
+ }
+ $namespaceTables = [];
+ foreach ( array_chunk( $tableRows, 4 ) as $chunk ) {
+ $namespaceTables[] = implode( '', $chunk );
+ }
+
+ $showSections = [
+ 'namespaceTables' => "<table>" . implode( '</table><table>', $namespaceTables ) . '</table>',
+ ];
+ Hooks::run( 'SpecialSearchPowerBox', [ &$showSections, $term, $opts ] );
+
+ $hidden = '';
+ foreach ( $opts as $key => $value ) {
+ $hidden .= Html::hidden( $key, $value );
+ }
+
+ $divider = "<div class='divider'></div>";
+
+ // Stuff to feed SpecialSearch::saveNamespaces()
+ $user = $this->specialSearch->getUser();
+ $remember = '';
+ if ( $user->isLoggedIn() ) {
+ $remember = $divider . Xml::checkLabel(
+ $this->specialSearch->msg( '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)
+ [ 'value' => $user->getEditToken(
+ 'searchnamespace',
+ $this->specialSearch->getRequest()
+ ) ]
+ );
+ }
+
+ return "<fieldset id='mw-searchoptions'>" .
+ "<legend>" . $this->specialSearch->msg( 'powersearch-legend' )->escaped() . '</legend>' .
+ "<h4>" . $this->specialSearch->msg( 'powersearch-ns' )->parse() . '</h4>' .
+ // populated by js if available
+ "<div id='mw-search-togglebox'></div>" .
+ $divider .
+ implode(
+ $divider,
+ $showSections
+ ) .
+ $hidden .
+ $remember .
+ "</fieldset>";
+ }
+}