'HTMLInfoField' => __DIR__ . '/includes/htmlform/fields/HTMLInfoField.php',
'HTMLIntField' => __DIR__ . '/includes/htmlform/fields/HTMLIntField.php',
'HTMLMultiSelectField' => __DIR__ . '/includes/htmlform/fields/HTMLMultiSelectField.php',
+ 'HTMLNamespacesMultiselectField' => __DIR__ . '/includes/htmlform/fields/HTMLNamespacesMultiselectField.php',
'HTMLNestedFilterable' => __DIR__ . '/includes/htmlform/HTMLNestedFilterable.php',
'HTMLRadioField' => __DIR__ . '/includes/htmlform/fields/HTMLRadioField.php',
'HTMLRestrictionsField' => __DIR__ . '/includes/htmlform/fields/HTMLRestrictionsField.php',
'MediaWiki\\Widget\\DateTimeInputWidget' => __DIR__ . '/includes/widget/DateTimeInputWidget.php',
'MediaWiki\\Widget\\ExpiryInputWidget' => __DIR__ . '/includes/widget/ExpiryInputWidget.php',
'MediaWiki\\Widget\\NamespaceInputWidget' => __DIR__ . '/includes/widget/NamespaceInputWidget.php',
+ 'MediaWiki\\Widget\\NamespacesMultiselectWidget' => __DIR__ . '/includes/widget/NamespacesMultiselectWidget.php',
'MediaWiki\\Widget\\PendingTextInputWidget' => __DIR__ . '/includes/widget/PendingTextInputWidget.php',
'MediaWiki\\Widget\\SearchInputWidget' => __DIR__ . '/includes/widget/SearchInputWidget.php',
'MediaWiki\\Widget\\Search\\BasicSearchResultSetWidget' => __DIR__ . '/includes/widget/search/BasicSearchResultSetWidget.php',
'user' => HTMLUserTextField::class,
'usersmultiselect' => HTMLUsersMultiselectField::class,
'titlesmultiselect' => HTMLTitlesMultiselectField::class,
+ 'namespacesmultiselect' => HTMLNamespacesMultiselectField::class,
];
public $mFieldData;
--- /dev/null
+<?php
+
+use MediaWiki\Widget\NamespacesMultiselectWidget;
+
+/**
+ * Implements a tag multiselect input field for namespaces.
+ *
+ * The result is the array of namespaces
+ *
+ * TODO: This widget duplicates a lot from HTMLTitlesMultiselectField,
+ * which itself duplicates HTMLUsersMultiselectField. These classes
+ * should be refactored.
+ *
+ * @note This widget is not likely to remain functional in non-OOUI forms.
+ */
+class HTMLNamespacesMultiselectField extends HTMLSelectNamespace {
+ public function loadDataFromRequest( $request ) {
+ $value = $request->getText( $this->mName, $this->getDefault() );
+
+ $namespaces = explode( "\n", $value );
+ // Remove empty lines
+ $namespaces = array_values( array_filter( $namespaces, function ( $namespace ) {
+ return trim( $namespace ) !== '';
+ } ) );
+ // This function is expected to return a string
+ return implode( "\n", $namespaces );
+ }
+
+ public function validate( $value, $alldata ) {
+ if ( !$this->mParams['exists'] ) {
+ return true;
+ }
+
+ if ( is_null( $value ) ) {
+ return false;
+ }
+
+ // $value is a string, because HTMLForm fields store their values as strings
+ $namespaces = explode( "\n", $value );
+
+ if ( isset( $this->mParams['max'] ) ) {
+ if ( count( $namespaces ) > $this->mParams['max'] ) {
+ return $this->msg( 'htmlform-int-toohigh', $this->mParams['max'] );
+ }
+ }
+
+ foreach ( $namespaces as $namespace ) {
+ $result = parent::validate( $namespace, $alldata );
+ if ( $result !== true ) {
+ return $result;
+ }
+ }
+
+ return true;
+ }
+
+ public function getInputHTML( $value ) {
+ $this->mParent->getOutput()->enableOOUI();
+ return $this->getInputOOUI( $value );
+ }
+
+ public function getInputOOUI( $value ) {
+ $params = [
+ 'id' => $this->mID,
+ 'name' => $this->mName,
+ 'dir' => $this->mDir,
+ ];
+
+ if ( isset( $this->mParams['disabled'] ) ) {
+ $params['disabled'] = $this->mParams['disabled'];
+ }
+
+ if ( isset( $this->mParams['default'] ) ) {
+ $params['default'] = $this->mParams['default'];
+ }
+
+ if ( isset( $this->mParams['placeholder'] ) ) {
+ $params['placeholder'] = $this->mParams['placeholder'];
+ } else {
+ $params['placeholder'] = $this->msg( 'mw-widgets-titlesmultiselect-placeholder' )->plain();
+ }
+
+ if ( isset( $this->mParams['max'] ) ) {
+ $params['tagLimit'] = $this->mParams['max'];
+ }
+
+ if ( isset( $this->mParams['input'] ) ) {
+ $params['input'] = $this->mParams['input'];
+ }
+
+ if ( !is_null( $value ) ) {
+ // $value is a string, but the widget expects an array
+ $params['default'] = $value === '' ? [] : explode( "\n", $value );
+ }
+
+ // Make the field auto-infusable when it's used inside a legacy HTMLForm rather than OOUIHTMLForm
+ $params['infusable'] = true;
+ $params['classes'] = [ 'mw-htmlform-field-autoinfuse' ];
+ $widget = new NamespacesMultiselectWidget( $params );
+ $widget->setAttributes( [ 'data-mw-modules' => implode( ',', $this->getOOUIModules() ) ] );
+
+ return $widget;
+ }
+
+ protected function shouldInfuseOOUI() {
+ return true;
+ }
+
+ protected function getOOUIModules() {
+ return [ 'mediawiki.widgets.NamespacesMultiselectWidget' ];
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Widget;
+
+/**
+ * Widget to select multiple namespaces.
+ *
+ * @copyright 2017 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license MIT
+ */
+class NamespacesMultiselectWidget extends TagMultiselectWidget {
+
+ /**
+ * @param array $config Configuration options
+ */
+ public function __construct( array $config = [] ) {
+ parent::__construct( $config );
+
+ $this->addClasses( [ 'mw-widgets-namespacesMultiselectWidget' ] );
+ }
+
+ protected function getJavaScriptClassName() {
+ return 'mw.widgets.NamespacesMultiselectWidget';
+ }
+
+ public function getConfig( &$config ) {
+ return parent::getConfig( $config );
+ }
+
+}
'oojs-ui.styles.icons-editing-advanced',
'mediawiki.widgets.DateInputWidget',
'mediawiki.widgets.SelectWithInputWidget',
+ 'mediawiki.widgets.NamespacesMultiselectWidget',
'mediawiki.widgets.TitlesMultiselectWidget',
'mediawiki.widgets.UserInputWidget',
'mediawiki.util',
],
'targets' => [ 'desktop', 'mobile' ],
],
+ 'mediawiki.widgets.NamespacesMultiselectWidget' => [
+ 'scripts' => [
+ 'resources/src/mediawiki.widgets/mw.widgets.NamespacesMultiselectWidget.js',
+ ],
+ 'dependencies' => [
+ 'oojs-ui-widgets',
+ ],
+ 'targets' => [ 'desktop', 'mobile' ],
+ ],
'mediawiki.widgets.TitlesMultiselectWidget' => [
'scripts' => [
'resources/src/mediawiki.widgets/mw.widgets.TitlesMultiselectWidget.js',
*/
mw.widgets.NamespaceInputWidget = function MwWidgetsNamespaceInputWidget( config ) {
// Configuration initialization
- config = $.extend( {}, config, { options: this.getNamespaceDropdownOptions( config ) } );
+ config = $.extend( {}, config, { options: this.constructor.static.getNamespaceDropdownOptions( config ) } );
// Parent constructor
mw.widgets.NamespaceInputWidget.parent.call( this, config );
OO.inheritClass( mw.widgets.NamespaceInputWidget, OO.ui.DropdownInputWidget );
- /* Methods */
+ /* Static methods */
/**
- * @private
+ * Get a list of namespace options, sorted by ID.
+ *
* @param {Object} [config] Configuration options
* @return {Object[]} Dropdown options
*/
- mw.widgets.NamespaceInputWidget.prototype.getNamespaceDropdownOptions = function ( config ) {
+ mw.widgets.NamespaceInputWidget.static.getNamespaceDropdownOptions = function ( config ) {
var options,
exclude = config.exclude || [],
mainNamespace = mw.config.get( 'wgNamespaceIds' )[ '' ];
--- /dev/null
+/*!
+ * MediaWiki Widgets - NamespacesMultiselectWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function () {
+
+ /**
+ * Creates an mw.widgets.NamespacesMultiselectWidget object
+ *
+ * TODO: A lot of this is duplicated in mw.widgets.UsersMultiselectWidget
+ * and mw.widgets.TitlesMultiselectWidget. These classes should be
+ * refactored.
+ *
+ * @class
+ * @extends OO.ui.MenuTagMultiselectWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+ mw.widgets.NamespacesMultiselectWidget = function MwWidgetsNamespacesMultiselectWidget( config ) {
+ var i, ilen, option,
+ namespaces = {},
+ options = mw.widgets.NamespaceInputWidget.static.getNamespaceDropdownOptions( {} );
+
+ for ( i = 0, ilen = options.length; i < ilen; i++ ) {
+ option = options[ i ];
+ namespaces[ option.data ] = option.label;
+ }
+
+ config = $.extend( true, {
+ options: mw.widgets.NamespaceInputWidget.static.getNamespaceDropdownOptions( {} )
+ }, config );
+
+ // Parent constructor
+ mw.widgets.NamespacesMultiselectWidget.parent.call( this, $.extend( true,
+ {
+ clearInputOnChoose: true,
+ inputPosition: 'inline',
+ allowEditTags: false
+ },
+ config,
+ {
+ selected: config && config.selected ? config.selected.map( function ( id ) {
+ return {
+ data: id,
+ label: namespaces[ id ]
+ };
+ } ) : undefined
+ }
+ ) );
+
+ // Initialization
+ this.$element
+ .addClass( 'mw-widgets-namespacesMultiselectWidget' );
+
+ 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
+ // Set the default value (it might be different from just being empty)
+ this.hiddenInput.prop( 'defaultValue', this.getItems().map( function ( item ) {
+ return item.getData();
+ } ).join( '\n' ) );
+ this.on( 'change', function ( items ) {
+ this.hiddenInput.val( items.map( function ( item ) {
+ return item.getData();
+ } ).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' );
+ }.bind( this ) );
+ }
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.NamespacesMultiselectWidget, OO.ui.MenuTagMultiselectWidget );
+ OO.mixinClass( mw.widgets.NamespacesMultiselectWidget, OO.ui.mixin.PendingElement );
+
+}() );