summaryrefslogtreecommitdiff
path: root/www/wiki/resources/src/mediawiki.widgets/mw.widgets.UsersMultiselectWidget.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/resources/src/mediawiki.widgets/mw.widgets.UsersMultiselectWidget.js')
-rw-r--r--www/wiki/resources/src/mediawiki.widgets/mw.widgets.UsersMultiselectWidget.js173
1 files changed, 173 insertions, 0 deletions
diff --git a/www/wiki/resources/src/mediawiki.widgets/mw.widgets.UsersMultiselectWidget.js b/www/wiki/resources/src/mediawiki.widgets/mw.widgets.UsersMultiselectWidget.js
new file mode 100644
index 00000000..f0ad0565
--- /dev/null
+++ b/www/wiki/resources/src/mediawiki.widgets/mw.widgets.UsersMultiselectWidget.js
@@ -0,0 +1,173 @@
+/*!
+ * MediaWiki Widgets - UsersMultiselectWidget class.
+ *
+ * @copyright 2017 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * UsersMultiselectWidget can be used to input list of users in a single
+ * line.
+ *
+ * If used inside HTML form the results will be sent as the list of
+ * newline-separated usernames.
+ *
+ * @class
+ * @extends OO.ui.MenuTagMultiselectWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {mw.Api} [api] Instance of mw.Api (or subclass thereof) to use for queries
+ * @cfg {number} [limit=10] Number of results to show in autocomplete menu
+ * @cfg {string} [name] Name of input to submit results (when used in HTML forms)
+ */
+ mw.widgets.UsersMultiselectWidget = function MwWidgetsUsersMultiselectWidget( config ) {
+ // Config initialization
+ config = $.extend( {
+ limit: 10
+ }, config, {
+ // Because of using autocomplete (constantly changing menu), we need to
+ // allow adding usernames, which do not present in the menu.
+ allowArbitrary: true
+ } );
+
+ // Parent constructor
+ mw.widgets.UsersMultiselectWidget.parent.call( this, $.extend( {}, config, {} ) );
+
+ // Mixin constructors
+ OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$handle } ) );
+
+ // Properties
+ this.limit = config.limit;
+
+ if ( 'name' in config ) {
+ // Use this instead of <input type="hidden">, because hidden inputs do not have separate
+ // 'value' and 'defaultValue' properties. The script on Special:Preferences
+ // (mw.special.preferences.confirmClose) checks this property to see if a field was changed.
+ this.hiddenInput = $( '<textarea>' )
+ .addClass( 'oo-ui-element-hidden' )
+ .attr( 'name', config.name )
+ .appendTo( this.$element );
+ // Update with preset values
+ this.updateHiddenInput();
+ // Set the default value (it might be different from just being empty)
+ this.hiddenInput.prop( 'defaultValue', this.getSelectedUsernames().join( '\n' ) );
+ }
+
+ this.menu = this.getMenu();
+
+ // Events
+ // When list of selected usernames changes, update hidden input
+ this.connect( this, {
+ change: 'onMultiselectChange'
+ } );
+
+ // API init
+ this.api = config.api || new mw.Api();
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.UsersMultiselectWidget, OO.ui.MenuTagMultiselectWidget );
+ OO.mixinClass( mw.widgets.UsersMultiselectWidget, OO.ui.mixin.PendingElement );
+
+ /* Methods */
+
+ /**
+ * Get currently selected usernames
+ *
+ * @return {string[]} usernames
+ */
+ mw.widgets.UsersMultiselectWidget.prototype.getSelectedUsernames = function () {
+ return this.getValue();
+ };
+
+ /**
+ * Update autocomplete menu with items
+ *
+ * @private
+ */
+ mw.widgets.UsersMultiselectWidget.prototype.updateMenuItems = function () {
+ var inputValue = this.input.getValue();
+
+ if ( inputValue === this.inputValue ) {
+ // Do not restart api query if nothing has changed in the input
+ return;
+ } else {
+ this.inputValue = inputValue;
+ }
+
+ this.api.abort(); // Abort all unfinished api requests
+
+ if ( inputValue.length > 0 ) {
+ this.pushPending();
+
+ this.api.get( {
+ action: 'query',
+ list: 'allusers',
+ // Prefix of list=allusers is case sensitive. Normalise first
+ // character to uppercase so that "fo" may yield "Foo".
+ auprefix: inputValue[ 0 ].toUpperCase() + inputValue.slice( 1 ),
+ aulimit: this.limit
+ } ).done( function ( response ) {
+ var suggestions = response.query.allusers,
+ selected = this.getSelectedUsernames();
+
+ // Remove usernames, which are already selected from suggestions
+ suggestions = suggestions.map( function ( user ) {
+ if ( selected.indexOf( user.name ) === -1 ) {
+ return new OO.ui.MenuOptionWidget( {
+ data: user.name,
+ label: user.name
+ } );
+ }
+ } ).filter( function ( item ) {
+ return item !== undefined;
+ } );
+
+ // Remove all items from menu add fill it with new
+ this.menu.clearItems();
+ this.menu.addItems( suggestions );
+ // Make the menu visible; it might not be if it was previously empty
+ this.menu.toggle( true );
+
+ this.popPending();
+ }.bind( this ) ).fail( this.popPending.bind( this ) );
+ } else {
+ this.menu.clearItems();
+ }
+ };
+
+ mw.widgets.UsersMultiselectWidget.prototype.onInputChange = function () {
+ mw.widgets.UsersMultiselectWidget.parent.prototype.onInputChange.apply( this, arguments );
+
+ this.updateMenuItems();
+ };
+
+ /**
+ * If used inside HTML form, then update hiddenInput with list o
+ * newline-separated usernames.
+ *
+ * @private
+ */
+ mw.widgets.UsersMultiselectWidget.prototype.updateHiddenInput = function () {
+ if ( 'hiddenInput' in this ) {
+ this.hiddenInput.val( this.getSelectedUsernames().join( '\n' ) );
+ // Trigger a 'change' event as if a user edited the text
+ // (it is not triggered when changing the value from JS code).
+ this.hiddenInput.trigger( 'change' );
+ }
+ };
+
+ /**
+ * React to the 'change' event.
+ *
+ * Updates the hidden input and clears the text from the text box.
+ */
+ mw.widgets.UsersMultiselectWidget.prototype.onMultiselectChange = function () {
+ this.updateHiddenInput();
+ this.input.setValue( '' );
+ };
+
+}( jQuery, mediaWiki ) );