MediaWiki Widgets: Add new SearchInputWidget
authorFlorian <florian.schmidt.stargatewissen@gmail.com>
Wed, 25 Nov 2015 20:01:58 +0000 (21:01 +0100)
committerFlorianschmidtwelzow <florian.schmidt.stargatewissen@gmail.com>
Thu, 3 Mar 2016 16:29:40 +0000 (16:29 +0000)
SearchInputWidget is similar to a TitleInputWidget, but doesn't has
a visible loading indication, doesn't highlight the first result and
uses the opensearch api endpoint for suggestions, instead of
prefixsearch.

Extra points:
 * Improve documentation of mw.widgets.TitleInputWidget's configuration
   option validateTitle

Bug: T118443
Change-Id: I8b8098041fe2971389fa908d007d2e77255829ec

autoload.php
includes/widget/SearchInputWidget.php [new file with mode: 0644]
resources/Resources.php
resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.css [new file with mode: 0644]
resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js [new file with mode: 0644]
resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js

index e882547..e74df0a 100644 (file)
@@ -821,6 +821,7 @@ $wgAutoloadLocalClasses = [
        'MediaWiki\\Widget\\ComplexNamespaceInputWidget' => __DIR__ . '/includes/widget/ComplexNamespaceInputWidget.php',
        'MediaWiki\\Widget\\ComplexTitleInputWidget' => __DIR__ . '/includes/widget/ComplexTitleInputWidget.php',
        'MediaWiki\\Widget\\NamespaceInputWidget' => __DIR__ . '/includes/widget/NamespaceInputWidget.php',
+       'MediaWiki\\Widget\\SearchInputWidget' => __DIR__ . '/includes/widget/SearchInputWidget.php',
        'MediaWiki\\Widget\\TitleInputWidget' => __DIR__ . '/includes/widget/TitleInputWidget.php',
        'MediaWiki\\Widget\\UserInputWidget' => __DIR__ . '/includes/widget/UserInputWidget.php',
        'MemCachedClientforWiki' => __DIR__ . '/includes/compat/MemcachedClientCompat.php',
diff --git a/includes/widget/SearchInputWidget.php b/includes/widget/SearchInputWidget.php
new file mode 100644 (file)
index 0000000..7b3de4a
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/**
+ * MediaWiki Widgets – SearchInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+namespace MediaWiki\Widget;
+
+/**
+ * Search input widget.
+ */
+class SearchInputWidget extends TitleInputWidget {
+
+       protected $pushPending = false;
+       protected $validateTitle = false;
+       protected $highlightFirst = false;
+
+       /**
+        * @param array $config Configuration options
+        * @param int|null $config['pushPending'] Whether the input should be visually marked as
+        *  "pending", while requesting suggestions (default: true)
+        */
+       public function __construct( array $config = [] ) {
+               // Parent constructor
+               parent::__construct(
+                       array_merge( [
+                               'infusable' => true,
+                               'maxLength' => null,
+                               'type' => 'search',
+                               'icon' => 'search'
+                       ], $config )
+               );
+
+               // Properties, which are ignored in PHP and just shipped back to JS
+               if ( isset( $config['pushPending'] ) ) {
+                       $this->pushPending = $config['pushPending'];
+               }
+
+               // Initialization
+               $this->addClasses( [ 'mw-widget-searchInputWidget' ] );
+       }
+
+       protected function getJavaScriptClassName() {
+               return 'mw.widgets.SearchInputWidget';
+       }
+
+       public function getConfig( &$config ) {
+               $config['pushPending'] = $this->pushPending;
+               return parent::getConfig( $config );
+       }
+}
index dcc02b7..16f6c94 100644 (file)
@@ -2213,6 +2213,25 @@ return [
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'mediawiki.widgets.SearchInputWidget' => [
+               'scripts' => [
+                       'resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js',
+               ],
+               'dependencies' => [
+                       'mediawiki.searchSuggest',
+                       // FIXME: Needs TitleInputWidget only
+                       'mediawiki.widgets',
+               ],
+       ],
+       'mediawiki.widgets.SearchInputWidget.styles' => [
+               'skinStyles' => [
+                       'default' => [
+                               'resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.css',
+                       ],
+               ],
+               'position' => 'top',
+               'targets' => [ 'desktop', 'mobile' ],
+       ],
 
        /* es5-shim */
        'es5-shim' => [
diff --git a/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.css b/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.css
new file mode 100644 (file)
index 0000000..3da5d31
--- /dev/null
@@ -0,0 +1,3 @@
+.mw-widget-searchInputWidget {
+       display: inline-block;
+}
diff --git a/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js
new file mode 100644 (file)
index 0000000..1f526e2
--- /dev/null
@@ -0,0 +1,111 @@
+/*!
+ * MediaWiki Widgets - SearchInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+       /**
+        * Creates a mw.widgets.SearchInputWidget object.
+        *
+        * @class
+        * @extends mw.widgets.TitleInputWidget
+        *
+        * @constructor
+        * @cfg {boolean} [pushPending=true] Visually mark the input field as "pending", while
+        *  requesting suggestions.
+        */
+       mw.widgets.SearchInputWidget = function MwWidgetsSearchInputWidget( config ) {
+               config = $.extend( {
+                       type: 'search',
+                       icon: 'search',
+                       maxLength: undefined
+               }, config );
+
+               // Parent constructor
+               mw.widgets.SearchInputWidget.parent.call( this, config );
+
+               // Initialization
+               this.$element.addClass( 'mw-widget-searchInputWidget' );
+               this.lookupMenu.$element.addClass( 'mw-widget-searchWidget-menu' );
+               if ( !config.pushPending ) {
+                       this.pushPending = false;
+               }
+               this.setLookupsDisabled( !this.suggestions );
+       };
+
+       /* Setup */
+
+       OO.inheritClass( mw.widgets.SearchInputWidget, mw.widgets.TitleInputWidget );
+
+       /* Methods */
+
+       /**
+        * @inheritdoc mw.widgets.TitleWidget
+        */
+       mw.widgets.SearchInputWidget.prototype.getSuggestionsPromise = function () {
+               var api = new mw.Api();
+
+               // reuse the searchSuggest function from mw.searchSuggest
+               return mw.searchSuggest.request( api, this.getQueryValue(), $.noop, this.limit );
+       };
+
+       /**
+        * @inheritdoc mw.widgets.TitleInputWidget
+        */
+       mw.widgets.SearchInputWidget.prototype.getLookupCacheDataFromResponse = function ( response ) {
+               // mw.widgets.TitleInputWidget uses response.query, which doesn't exist for opensearch,
+               // so return the whole response (titles only, and links)
+               return response || {};
+       };
+
+       /**
+        * @inheritdoc mw.widgets.TitleWidget
+        */
+       mw.widgets.SearchInputWidget.prototype.getOptionsFromData = function ( data ) {
+               var items = [],
+                       self = this;
+
+               // 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 ) {
+                       items.push( new mw.widgets.TitleOptionWidget(
+                               // data[ 3 ][ i ] is the link for this result
+                               self.getOptionWidgetData( result, null, data[ 3 ][ i ] )
+                       ) );
+               } );
+
+               mw.track( 'mw.widgets.SearchInputWidget', {
+                       action: 'impression-results',
+                       numberOfResults: items.length,
+                       resultSetType: mw.searchSuggest.type
+               } );
+
+               return items;
+       };
+
+       /**
+        * @inheritdoc mw.widgets.TitleWidget
+        *
+        * @param {string} title
+        * @param {Object} data
+        * @param {string} url The Url to the result
+        */
+       mw.widgets.SearchInputWidget.prototype.getOptionWidgetData = function ( title, data, url ) {
+               // the values used in mw.widgets-TitleWidget doesn't exist here, that's why
+               // the values are hard-coded here
+               return {
+                       data: title,
+                       url: url,
+                       imageUrl: null,
+                       description: null,
+                       missing: false,
+                       redirect: false,
+                       disambiguation: false,
+                       query: this.getQueryValue()
+               };
+       };
+
+}( jQuery, mediaWiki ) );
index abe1228..b805e65 100644 (file)
@@ -23,7 +23,8 @@
         * @cfg {boolean} [showRedlink] Show red link to exact match if it doesn't exist
         * @cfg {boolean} [showImages] Show page images
         * @cfg {boolean} [showDescriptions] Show page descriptions
-        * @cfg {boolean} [validateTitle=true] Whether the input must be a valid title
+        * @cfg {boolean} [validateTitle=true] Whether the input must be a valid title (if set to true,
+        *  the widget will marks itself red for invalid inputs, including an empty query).
         * @cfg {Object} [cache] Result cache which implements a 'set' method, taking keyed values as an argument
         */
        mw.widgets.TitleWidget = function MwWidgetsTitleWidget( config ) {