diff options
author | Func <Funcer@outlook.com> | 2024-11-28 00:24:41 +0800 |
---|---|---|
committer | Func <Funcer@outlook.com> | 2024-12-16 22:29:35 +0800 |
commit | b909a648ed223163ca947ce9bf6d7c6eabf6c756 (patch) | |
tree | 548f20607882d0d5d121bdbed4d50064c8fe73a4 /includes/htmlform/fields | |
parent | 372cc166d9e128bd984bf304e43f1a5344f7efef (diff) | |
download | mediawikicore-b909a648ed223163ca947ce9bf6d7c6eabf6c756.tar.gz mediawikicore-b909a648ed223163ca947ce9bf6d7c6eabf6c756.zip |
Support sections in the dropdown mode of HtmlMultiSelectField
Created a new input widget and used it for the dropdown mode of
HtmlMultiSelectField. Dropped the `mw-htmlform-dropdown` class
to avoid being affected by old site/user js/css targeting it.
Also, generalised the creation of no-js fallback implementation,
so subclass of TagMultiselectWidget can provide a friendly
interface suited for their options' data.
Bug: T380995
Change-Id: Ieeb02ad875c6932cf594de6585cdda79771f7e50
Diffstat (limited to 'includes/htmlform/fields')
-rw-r--r-- | includes/htmlform/fields/HTMLMultiSelectField.php | 107 |
1 files changed, 61 insertions, 46 deletions
diff --git a/includes/htmlform/fields/HTMLMultiSelectField.php b/includes/htmlform/fields/HTMLMultiSelectField.php index 115ff545285c..39323543e46d 100644 --- a/includes/htmlform/fields/HTMLMultiSelectField.php +++ b/includes/htmlform/fields/HTMLMultiSelectField.php @@ -7,6 +7,7 @@ use MediaWiki\HTMLForm\HTMLFormField; use MediaWiki\HTMLForm\HTMLNestedFilterable; use MediaWiki\HTMLForm\OOUIHTMLForm; use MediaWiki\Request\WebRequest; +use MediaWiki\Widget\MenuTagMultiselectWidget; use MediaWiki\Xml\Xml; use RuntimeException; @@ -16,8 +17,10 @@ use RuntimeException; * @stable to extend */ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable { - /** @var string */ - private $mPlaceholder; + + private bool $mDropdown = false; + + private ?string $mPlaceholder = null; /** * @stable to call @@ -42,7 +45,7 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable } if ( isset( $params['dropdown'] ) ) { - $this->mClass .= ' mw-htmlform-dropdown'; + $this->mDropdown = true; if ( isset( $params['placeholder'] ) ) { $this->mPlaceholder = $params['placeholder']; } elseif ( isset( $params['placeholder-message'] ) ) { @@ -157,14 +160,28 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable } } - /** - * Get options and make them into arrays suitable for OOUI. - * @stable to override - */ public function getOptionsOOUI() { - // @phan-suppress-previous-line PhanPluginNeverReturnMethod - // Sections make this difficult. See getInputOOUI(). - throw new RuntimeException( __METHOD__ . ' is not supported' ); + $optionsOouiSections = []; + $options = $this->getOptions(); + + // If the options are supposed to be split into sections, each section becomes a separate + // CheckboxMultiselectInputWidget. + foreach ( $options as $label => $section ) { + if ( is_array( $section ) ) { + $optionsOouiSections[ $label ] = Html::listDropdownOptionsOoui( $section ); + unset( $options[$label] ); + } + } + + // If anything remains in the array, they are sectionless options. Put them at the beginning. + if ( $options ) { + $optionsOouiSections = array_merge( + [ '' => Html::listDropdownOptionsOoui( $options ) ], + $optionsOouiSections + ); + } + + return $optionsOouiSections; } /** @@ -176,55 +193,36 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable * @stable to override * @since 1.28 * @param string[] $value - * @return string|\OOUI\CheckboxMultiselectInputWidget + * @return \OOUI\Widget|string * @suppress PhanParamSignatureMismatch */ public function getInputOOUI( $value ) { $this->mParent->getOutput()->addModules( 'oojs-ui-widgets' ); + if ( $this->mDropdown ) { + $this->mParent->getOutput()->addModuleStyles( 'mediawiki.widgets.TagMultiselectWidget.styles' ); + } // Reject nested arrays (T274955) $value = array_filter( $value, 'is_scalar' ); - $hasSections = false; - $optionsOouiSections = []; - $options = $this->getOptions(); - // If the options are supposed to be split into sections, each section becomes a separate - // CheckboxMultiselectInputWidget. - foreach ( $options as $label => $section ) { - if ( is_array( $section ) ) { - $optionsOouiSections[ $label ] = Html::listDropdownOptionsOoui( $section ); - unset( $options[$label] ); - $hasSections = true; - } - } - // If anything remains in the array, they are sectionless options. Put them in a separate widget - // at the beginning. - if ( $options ) { - $optionsOouiSections = array_merge( - [ '' => Html::listDropdownOptionsOoui( $options ) ], - $optionsOouiSections - ); - } - '@phan-var array[][] $optionsOouiSections'; - $out = []; - foreach ( $optionsOouiSections as $sectionLabel => $optionsOoui ) { + $optionsSections = $this->getOptionsOOUI(); + foreach ( $optionsSections as $sectionLabel => &$groupedOptions ) { $attr = []; $attr['name'] = "{$this->mName}[]"; $attr['value'] = $value; - $options = $optionsOoui; - foreach ( $options as &$option ) { + foreach ( $groupedOptions as &$option ) { $option['disabled'] = in_array( $option['data'], $this->mParams['disabled-options'], true ); } if ( $this->mOptionsLabelsNotFromMessage ) { - foreach ( $options as &$option ) { + foreach ( $groupedOptions as &$option ) { $option['label'] = new \OOUI\HtmlSnippet( $option['label'] ); } } unset( $option ); - $attr['options'] = $options; + $attr['options'] = $groupedOptions; $attr += \OOUI\Element::configFromHtmlAttributes( $this->getAttributes( [ 'disabled', 'tabindex' ] ) @@ -245,16 +243,25 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable $out[] = $widget; } } + unset( $groupedOptions ); - if ( !$hasSections && $out ) { + $params = []; + if ( $this->mPlaceholder ) { + $params['placeholder'] = $this->mPlaceholder; + } + if ( isset( $this->mParams['max'] ) ) { + $params['tagLimit'] = $this->mParams['max']; + } + if ( $this->mDropdown ) { + return new MenuTagMultiselectWidget( [ + 'name' => $this->mName, + 'options' => $optionsSections, + 'default' => $value, + 'noJsFallback' => $out, + ] + $params ); + } elseif ( count( $out ) === 1 ) { $firstFieldData = $out[0]->getData() ?: []; - if ( $this->mPlaceholder ) { - $firstFieldData['placeholder'] = $this->mPlaceholder; - } - if ( isset( $this->mParams['max'] ) ) { - $firstFieldData['tagLimit'] = $this->mParams['max']; - } - $out[0]->setData( $firstFieldData ); + $out[0]->setData( $firstFieldData + $params ); // Directly return the only OOUI\CheckboxMultiselectInputWidget. // This allows it to be made infusable and later tweaked by JS code. return $out[0]; @@ -263,6 +270,14 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable return implode( '', $out ); } + protected function getOOUIModules() { + return $this->mDropdown ? [ 'mediawiki.widgets.MenuTagMultiselectWidget' ] : []; + } + + protected function shouldInfuseOOUI() { + return $this->mDropdown; + } + /** * @stable to override * @param WebRequest $request |