summaryrefslogtreecommitdiff
path: root/www/wiki/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js')
-rw-r--r--www/wiki/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js250
1 files changed, 250 insertions, 0 deletions
diff --git a/www/wiki/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js b/www/wiki/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js
new file mode 100644
index 00000000..c25ab450
--- /dev/null
+++ b/www/wiki/resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js
@@ -0,0 +1,250 @@
+/*!
+ * 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
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [pushPending=false] 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.
+ * @cfg {string} [dataLocation='header'] Where the search input field will be
+ * used (header or content).
+ */
+ mw.widgets.SearchInputWidget = function MwWidgetsSearchInputWidget( config ) {
+ // The parent constructors will detach this from the DOM, and won't
+ // be reattached until after this function is completed. As such
+ // grab a handle here. If no config.$input is passed tracking of
+ // form submissions won't work.
+ var $form = config.$input ? config.$input.closest( 'form' ) : $();
+
+ config = $.extend( {
+ icon: 'search',
+ maxLength: undefined,
+ performSearchOnClick: true,
+ dataLocation: 'header'
+ }, 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' );
+ this.lastLookupItems = [];
+ if ( !config.pushPending ) {
+ this.pushPending = false;
+ }
+ if ( config.dataLocation ) {
+ this.dataLocation = config.dataLocation;
+ }
+ if ( config.performSearchOnClick ) {
+ this.performSearchOnClick = config.performSearchOnClick;
+ }
+ this.setLookupsDisabled( !this.suggestions );
+
+ $form.on( 'submit', function () {
+ mw.track( 'mw.widgets.SearchInputWidget', {
+ action: 'submit-form',
+ numberOfResults: this.lastLookupItems.length,
+ $form: $form,
+ inputLocation: this.dataLocation || 'header',
+ index: this.lastLookupItems.indexOf(
+ this.$input.val()
+ )
+ } );
+ }.bind( this ) );
+
+ this.connect( this, {
+ change: 'onChange'
+ } );
+
+ this.$element.addClass( 'oo-ui-textInputWidget-type-search' );
+ this.updateSearchIndicator();
+ this.connect( this, {
+ disable: 'onDisable'
+ } );
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.SearchInputWidget, mw.widgets.TitleInputWidget );
+
+ /* Methods */
+
+ /**
+ * @inheritdoc
+ * @protected
+ */
+ mw.widgets.SearchInputWidget.prototype.getInputElement = function () {
+ return $( '<input>' ).attr( 'type', 'search' );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.SearchInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
+ if ( e.which === OO.ui.MouseButtons.LEFT ) {
+ // Clear the text field
+ this.setValue( '' );
+ this.$input[ 0 ].focus();
+ return false;
+ }
+ };
+
+ /**
+ * Update the 'clear' indicator displayed on type: 'search' text
+ * fields, hiding it when the field is already empty or when it's not
+ * editable.
+ */
+ mw.widgets.SearchInputWidget.prototype.updateSearchIndicator = function () {
+ if ( this.getValue() === '' || this.isDisabled() || this.isReadOnly() ) {
+ this.setIndicator( null );
+ } else {
+ this.setIndicator( 'clear' );
+ }
+ };
+
+ /**
+ * @see OO.ui.SearchInputWidget#onChange
+ */
+ mw.widgets.SearchInputWidget.prototype.onChange = function () {
+ this.updateSearchIndicator();
+ };
+
+ /**
+ * Handle disable events.
+ *
+ * @param {boolean} disabled Element is disabled
+ * @private
+ */
+ mw.widgets.SearchInputWidget.prototype.onDisable = function () {
+ this.updateSearchIndicator();
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.SearchInputWidget.prototype.setReadOnly = function ( state ) {
+ mw.widgets.SearchInputWidget.parent.prototype.setReadOnly.call( this, state );
+ this.updateSearchIndicator();
+ return this;
+ };
+
+ /**
+ * @inheritdoc mw.widgets.TitleWidget
+ */
+ mw.widgets.SearchInputWidget.prototype.getSuggestionsPromise = function () {
+ var api = this.getApi(),
+ promise,
+ self = this;
+
+ // reuse the searchSuggest function from mw.searchSuggest
+ promise = mw.searchSuggest.request( api, this.getQueryValue(), $.noop, this.limit, this.getNamespace() );
+
+ // 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)
+ resp = {
+ data: response || {},
+ metadata: {
+ type: this.requestType || 'unknown',
+ query: this.getQueryValue()
+ }
+ };
+ this.requestType = undefined;
+
+ return resp;
+ };
+
+ /**
+ * @inheritdoc mw.widgets.TitleWidget
+ */
+ mw.widgets.SearchInputWidget.prototype.getOptionsFromData = function ( data ) {
+ var items = [],
+ titles = data.data[ 1 ],
+ descriptions = data.data[ 2 ],
+ urls = data.data[ 3 ],
+ self = this;
+
+ $.each( titles, function ( i, result ) {
+ items.push( new mw.widgets.TitleOptionWidget(
+ self.getOptionWidgetData(
+ result,
+ // Create a result object that looks like the one from
+ // the parent's API query.
+ {
+ data: result,
+ url: urls[ i ],
+ imageUrl: null, // The JSON 'opensearch' API doesn't have images
+ description: descriptions[ i ],
+ missing: false,
+ redirect: false,
+ disambiguation: false
+ }
+ )
+ ) );
+ } );
+
+ mw.track( 'mw.widgets.SearchInputWidget', {
+ action: 'impression-results',
+ numberOfResults: items.length,
+ resultSetType: data.metadata.type,
+ query: data.metadata.query,
+ inputLocation: this.dataLocation || 'header'
+ } );
+
+ return items;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.SearchInputWidget.prototype.onLookupMenuItemChoose = function () {
+ mw.widgets.SearchInputWidget.parent.prototype.onLookupMenuItemChoose.apply( this, arguments );
+
+ if ( this.performSearchOnClick ) {
+ this.$element.closest( 'form' ).submit();
+ }
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.SearchInputWidget.prototype.getLookupMenuOptionsFromData = function () {
+ var items = mw.widgets.SearchInputWidget.parent.prototype.getLookupMenuOptionsFromData.apply(
+ this, arguments
+ );
+
+ this.lastLookupItems = items.map( function ( item ) {
+ return item.data;
+ } );
+
+ return items;
+ };
+
+}( jQuery, mediaWiki ) );