From: Florian Date: Thu, 12 Nov 2015 17:34:12 +0000 (+0100) Subject: Convert Special:Search input to OOUI X-Git-Tag: 1.31.0-rc.0~7319^2 X-Git-Url: http://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=commitdiff_plain;h=e429497501abd8e155511a38eb734160cf046019 Convert Special:Search input to OOUI Bug: T100898 Change-Id: I24801495dfad71f457bc4afdd28474f74b219024 --- diff --git a/includes/specials/SpecialSearch.php b/includes/specials/SpecialSearch.php index dfab8d437c..45ef679a1b 100644 --- a/includes/specials/SpecialSearch.php +++ b/includes/specials/SpecialSearch.php @@ -97,7 +97,7 @@ class SpecialSearch extends SpecialPage { $out->allowClickjacking(); $out->addModuleStyles( [ 'mediawiki.special', 'mediawiki.special.search', 'mediawiki.ui', 'mediawiki.ui.button', - 'mediawiki.ui.input', + 'mediawiki.ui.input', 'mediawiki.widgets.SearchInputWidget.styles', ] ); $this->addHelpLink( 'Help:Searching' ); @@ -323,6 +323,7 @@ class SpecialSearch extends SpecialPage { $num = $titleMatchesNum + $textMatchesNum; $totalRes = $numTitleMatches + $numTextMatches; + $out->enableOOUI(); $out->addHTML( # This is an awful awful ID name. It's not a table, but we # named it poorly from when this was a table so now we're @@ -1218,23 +1219,23 @@ class SpecialSearch extends SpecialPage { * @return string */ protected function shortDialog( $term, $resultsShown, $totalNum ) { - $out = Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ); - $out .= Html::hidden( 'profile', $this->profile ) . "\n"; - // Term box - $out .= Html::input( 'search', $term, 'search', [ - 'id' => $this->isPowerSearch() ? 'powerSearchText' : 'searchText', - 'size' => '50', + $searchWidget = new MediaWiki\Widget\SearchInputWidget( [ + 'id' => 'searchText', + 'name' => 'search', 'autofocus' => trim( $term ) === '', - 'class' => 'mw-ui-input mw-ui-input-inline', - // identifies the location of the search bar for tracking purposes - 'data-search-loc' => 'content', - ] ) . "\n"; - $out .= Html::hidden( 'fulltext', 'Search' ) . "\n"; - $out .= Html::submitButton( - $this->msg( 'searchbutton' )->text(), - [ 'class' => 'mw-ui-button mw-ui-progressive' ], - [ 'mw-ui-progressive' ] - ) . "\n"; + 'value' => $term, + ] ); + + $out = + Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ) . + Html::hidden( 'profile', $this->profile ) . + Html::hidden( 'fulltext', 'Search' ) . + $searchWidget . + new OOUI\ButtonInputWidget( [ + 'type' => 'submit', + 'label' => $this->msg( 'searchbutton' )->text(), + 'flags' => [ 'progressive', 'primary' ], + ] ); // Results-info if ( $totalNum > 0 && $this->offset < $totalNum ) { diff --git a/includes/widget/SearchInputWidget.php b/includes/widget/SearchInputWidget.php index 7b3de4a557..5ff411df4e 100644 --- a/includes/widget/SearchInputWidget.php +++ b/includes/widget/SearchInputWidget.php @@ -13,6 +13,7 @@ namespace MediaWiki\Widget; class SearchInputWidget extends TitleInputWidget { protected $pushPending = false; + protected $performSearchOnClick = true; protected $validateTitle = false; protected $highlightFirst = false; @@ -20,23 +21,36 @@ class SearchInputWidget extends TitleInputWidget { * @param array $config Configuration options * @param int|null $config['pushPending'] Whether the input should be visually marked as * "pending", while requesting suggestions (default: true) + * @param boolean|null $config['performSearchOnClick'] If true, the script will start a search + * whenever a user hits a suggestion. If false, the text of the suggestion is inserted into the + * text field only (default: true) */ public function __construct( array $config = [] ) { + $config = array_merge( [ + 'infusable' => true, + 'maxLength' => null, + 'type' => 'search', + 'icon' => 'search', + 'dataLocation' => 'content', + ], $config ); + // Parent constructor - parent::__construct( - array_merge( [ - 'infusable' => true, - 'maxLength' => null, - 'type' => 'search', - 'icon' => 'search' - ], $config ) - ); + parent::__construct( $config ); // Properties, which are ignored in PHP and just shipped back to JS if ( isset( $config['pushPending'] ) ) { $this->pushPending = $config['pushPending']; } + if ( isset( $config['performSearchOnClick'] ) ) { + $this->performSearchOnClick = $config['performSearchOnClick']; + } + + if ( $config['dataLocation'] ) { + // identifies the location of the search bar for tracking purposes + $this->dataLocation = $config['dataLocation']; + } + // Initialization $this->addClasses( [ 'mw-widget-searchInputWidget' ] ); } @@ -47,6 +61,10 @@ class SearchInputWidget extends TitleInputWidget { public function getConfig( &$config ) { $config['pushPending'] = $this->pushPending; + $config['performSearchOnClick'] = $this->performSearchOnClick; + if ( $this->dataLocation ) { + $config['dataLocation'] = $this->dataLocation; + } return parent::getConfig( $config ); } } diff --git a/resources/Resources.php b/resources/Resources.php index 07cd7b5328..0be46932a1 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -1847,6 +1847,7 @@ return [ 'position' => 'top', 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.search.js', 'styles' => 'resources/src/mediawiki.special/mediawiki.special.search.css', + 'dependencies' => 'mediawiki.widgets.SearchInputWidget', 'messages' => [ 'powersearch-togglelabel', 'powersearch-toggleall', diff --git a/resources/src/mediawiki.special/mediawiki.special.search.js b/resources/src/mediawiki.special/mediawiki.special.search.js index ab83e1af2f..e809f2ea93 100644 --- a/resources/src/mediawiki.special/mediawiki.special.search.js +++ b/resources/src/mediawiki.special/mediawiki.special.search.js @@ -3,7 +3,7 @@ */ ( function ( mw, $ ) { $( function () { - var $checkboxes, $headerLinks; + var $checkboxes, $headerLinks, updateHeaderLinks, searchWidget; // Emulate HTML5 autofocus behavior in non HTML5 compliant browsers if ( !( 'autofocus' in document.createElement( 'input' ) ) ) { @@ -33,8 +33,8 @@ // Change the header search links to what user entered $headerLinks = $( '.search-types a' ); - $( '#searchText, #powerSearchText' ).change( function () { - var searchterm = $( this ).val(); + searchWidget = OO.ui.infuse( 'searchText' ); + updateHeaderLinks = function ( value ) { $headerLinks.each( function () { var parts = $( this ).attr( 'href' ).split( 'search=' ), lastpart = '', @@ -44,9 +44,11 @@ } else { prefix = '&search='; } - this.href = parts[ 0 ] + prefix + encodeURIComponent( searchterm ) + lastpart; + this.href = parts[ 0 ] + prefix + encodeURIComponent( value ) + lastpart; } ); - } ).trigger( 'change' ); + }; + searchWidget.on( 'change', updateHeaderLinks ); + updateHeaderLinks( searchWidget.getValue() ); // When saving settings, use the proper request method (POST instead of GET). $( '#mw-search-powersearch-remember' ).change( function () { diff --git a/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js index 1f526e254c..8c2b53af26 100644 --- a/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js +++ b/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js @@ -15,12 +15,16 @@ * @constructor * @cfg {boolean} [pushPending=true] Visually mark the input field as "pending", while * requesting suggestions. + * @cfg {boolean} [performSearchOnClick=true] If true, the script will start a search when- + * ever a user hits a suggestion. If false, the text of the suggestion is inserted into the + * text field only. */ mw.widgets.SearchInputWidget = function MwWidgetsSearchInputWidget( config ) { config = $.extend( { type: 'search', icon: 'search', - maxLength: undefined + maxLength: undefined, + performSearchOnClick: true }, config ); // Parent constructor @@ -32,6 +36,12 @@ if ( !config.pushPending ) { this.pushPending = false; } + if ( config.dataLocation ) { + this.dataLocation = config.dataLocation; + } + if ( config.performSearchOnClick ) { + this.performSearchOnClick = config.performSearchOnClick; + } this.setLookupsDisabled( !this.suggestions ); }; @@ -45,19 +55,39 @@ * @inheritdoc mw.widgets.TitleWidget */ mw.widgets.SearchInputWidget.prototype.getSuggestionsPromise = function () { - var api = new mw.Api(); + var api = new mw.Api(), + promise, + self = this; // reuse the searchSuggest function from mw.searchSuggest - return mw.searchSuggest.request( api, this.getQueryValue(), $.noop, this.limit ); + promise = mw.searchSuggest.request( api, this.getQueryValue(), $.noop, this.limit ); + + // tracking purposes + promise.done( function ( data, jqXHR ) { + self.requestType = jqXHR.getResponseHeader( 'X-OpenSearch-Type' ); + } ); + + return promise; }; /** * @inheritdoc mw.widgets.TitleInputWidget */ mw.widgets.SearchInputWidget.prototype.getLookupCacheDataFromResponse = function ( response ) { + var resp; + // mw.widgets.TitleInputWidget uses response.query, which doesn't exist for opensearch, // so return the whole response (titles only, and links) - return response || {}; + resp = { + data: response || {}, + metadata: { + type: this.requestType || 'unknown', + query: this.getQueryValue() + } + }; + this.requestType = undefined; + + return resp; }; /** @@ -70,17 +100,19 @@ // mw.widgets.TitleWidget does a lot more work here, because the TitleOptionWidgets can // differ a lot, depending on the returned data from the request. With the request used here // we get only the search results. - $.each( data[ 1 ], function ( i, result ) { + $.each( data.data[ 1 ], function ( i, result ) { items.push( new mw.widgets.TitleOptionWidget( // data[ 3 ][ i ] is the link for this result - self.getOptionWidgetData( result, null, data[ 3 ][ i ] ) + self.getOptionWidgetData( result, null, data.data[ 3 ][ i ] ) ) ); } ); mw.track( 'mw.widgets.SearchInputWidget', { action: 'impression-results', numberOfResults: items.length, - resultSetType: mw.searchSuggest.type + resultSetType: data.metadata.type, + query: data.metadata.query, + inputLocation: this.dataLocation || 'header' } ); return items; @@ -108,4 +140,26 @@ }; }; + /** + * @inheritdoc + */ + mw.widgets.SearchInputWidget.prototype.onLookupMenuItemChoose = function ( item ) { + var items; + + // get items which was suggested before the input changes + items = this.lookupMenu.items; + + mw.widgets.SearchInputWidget.parent.prototype.onLookupMenuItemChoose.apply( this, arguments ); + + mw.track( 'mw.widgets.SearchInputWidget', { + action: 'click-result', + numberOfResults: items.length, + clickIndex: items.indexOf( item ) + 1 + } ); + + if ( this.performSearchOnClick ) { + this.$element.closest( 'form' ).submit(); + } + }; + }( jQuery, mediaWiki ) ); diff --git a/resources/src/mediawiki/mediawiki.searchSuggest.js b/resources/src/mediawiki/mediawiki.searchSuggest.js index 17a3b21eeb..2d603bf8d4 100644 --- a/resources/src/mediawiki/mediawiki.searchSuggest.js +++ b/resources/src/mediawiki/mediawiki.searchSuggest.js @@ -208,9 +208,6 @@ searchboxesSelectors = [ // Primary searchbox on every page in standard skins '#searchInput', - // Special:Search - '#powerSearchText', - '#searchText', // Generic selector for skins with multiple searchboxes (used by CologneBlue) // and for MediaWiki itself (special pages with page title inputs) '.mw-searchInput'