aboutsummaryrefslogtreecommitdiffstats
path: root/includes/htmlform/fields
diff options
context:
space:
mode:
authorFunc <Funcer@outlook.com>2024-11-28 00:24:41 +0800
committerFunc <Funcer@outlook.com>2024-12-16 22:29:35 +0800
commitb909a648ed223163ca947ce9bf6d7c6eabf6c756 (patch)
tree548f20607882d0d5d121bdbed4d50064c8fe73a4 /includes/htmlform/fields
parent372cc166d9e128bd984bf304e43f1a5344f7efef (diff)
downloadmediawikicore-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.php107
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