HTMLMultiSelectField: Add 'dropdown' option for 'mw-chosen' behavior and document
authorBartosz Dziewoński <matma.rex@gmail.com>
Mon, 8 Aug 2016 19:40:12 +0000 (21:40 +0200)
committerJforrester <jforrester@wikimedia.org>
Mon, 22 Aug 2016 17:58:53 +0000 (17:58 +0000)
Previously, you could pass 'cssclass' => 'mw-chosen' in the form
descriptor for a 'multiselect' field, and it'd be automatically
converted to a text field with a dropdown allowing values to be
selected. This is not very intuitive (unless you know what the Chosen
library is) and was not documented anywhere except for release notes.

The new recommended and documented way to achieve this is by passing
'dropdown' => true. Old way is supported for backwards compatibility.

Also, add the 'jquery.chosen' module to the page server-side.

Change-Id: I3a025e1c3c7571e930a35e020d73d558fdc433d0

includes/htmlform/fields/HTMLMultiSelectField.php
resources/src/mediawiki/htmlform/multiselect.js

index a231b2f..38d231f 100644 (file)
@@ -4,6 +4,22 @@
  * Multi-select field
  */
 class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable {
+       /**
+        * @param array $params
+        *   In adition to the usual HTMLFormField parameters, this can take the following fields:
+        *   - dropdown: If given, the options will be displayed inside a dropdown with a text field that
+        *     can be used to filter them. This is desirable mostly for very long lists of options.
+        *     This only works for users with JavaScript support and falls back to the list of checkboxes.
+        */
+       public function __construct( $params ) {
+               parent::__construct( $params );
+
+               // For backwards compatibility, also handle the old way with 'cssclass' => 'mw-chosen'
+               if ( isset( $params['dropdown'] ) || strpos( $this->mClass, 'mw-chosen' ) !== false ) {
+                       $this->mClass .= ' mw-htmlform-dropdown';
+               }
+       }
+
        function validate( $value, $alldata ) {
                $p = parent::validate( $value, $alldata );
 
@@ -28,6 +44,10 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable
        }
 
        function getInputHTML( $value ) {
+               if ( isset( $this->mParams['dropdown'] ) ) {
+                       $this->mParent->getOutput()->addModules( 'jquery.chosen' );
+               }
+
                $value = HTMLFormField::forceToStringRecursive( $value );
                $html = $this->formatOptions( $this->getOptions(), $value );
 
index 3cdab3c..a8786ef 100644 (file)
@@ -6,7 +6,7 @@
 
        function addMulti( $oldContainer, $container ) {
                var name = $oldContainer.find( 'input:first-child' ).attr( 'name' ),
-                       oldClass = ( ' ' + $oldContainer.attr( 'class' ) + ' ' ).replace( /(mw-htmlform-field-HTMLMultiSelectField|mw-chosen)/g, '' ),
+                       oldClass = ( ' ' + $oldContainer.attr( 'class' ) + ' ' ).replace( /(mw-htmlform-field-HTMLMultiSelectField|mw-chosen|mw-htmlform-dropdown)/g, '' ),
                        $select = $( '<select>' ),
                        dataPlaceholder = mw.message( 'htmlform-chosen-placeholder' );
                oldClass = $.trim( oldClass );
@@ -53,9 +53,9 @@
        }
 
        mw.hook( 'htmlform.enhance' ).add( function ( $root ) {
-               if ( $root.find( '.mw-chosen' ).length ) {
+               if ( $root.find( '.mw-htmlform-dropdown' ).length ) {
                        mw.loader.using( 'jquery.chosen', function () {
-                               $root.find( '.mw-chosen' ).each( function () {
+                               $root.find( '.mw-htmlform-dropdown' ).each( function () {
                                        var type = this.nodeName.toLowerCase(),
                                                $converted = convertCheckboxesToMulti( $( this ), type );
                                        $converted.find( '.htmlform-chzn-select' ).chosen( { width: 'auto' } );