wiki.techinc.nl/includes/htmlform/fields/HTMLSelectOrOtherField.php
Daimona Eaytoy ec09c19fba Create an HTMLForm field for selecting a timezone
This patch introduces HTMLTimezoneField, an HTMLForm field type that
allows the user to select a timezone, either from a geographic zone, by
manually entering an offset, or using the wiki/browser default. This
logic is extracted from DefaultPreferencesFactory so that it can be
reused elsewhere.

The widget itself is really just an HTMLSelectOrOtherField, it's just
the list of options and the JS logic that is special.

Bug: T309629
Change-Id: I99a00dff7e3319ce45883191daee16bec1ed68ba
2022-09-23 18:35:51 +02:00

191 lines
4.8 KiB
PHP

<?php
/**
* Select dropdown field, with an additional "other" textbox.
*
* HTMLComboboxField implements the same functionality using a single form field
* and should be used instead.
*
* @stable to extend
*/
class HTMLSelectOrOtherField extends HTMLTextField {
private const FIELD_CLASS = 'mw-htmlform-select-or-other';
/**
* @stable to call
* @inheritDoc
*/
public function __construct( $params ) {
parent::__construct( $params );
$this->getOptions();
if ( !in_array( 'other', $this->mOptions, true ) ) {
$msg =
$params['other'] ?? wfMessage( 'htmlform-selectorother-other' )->text();
// Have 'other' always as first element
$this->mOptions = [ $msg => 'other' ] + $this->mOptions;
}
}
public function getInputHTML( $value ) {
$valInSelect = false;
if ( $value !== false ) {
$value = strval( $value );
$valInSelect = in_array(
$value, HTMLFormField::flattenOptions( $this->getOptions() ), true
);
}
$selected = $valInSelect ? $value : 'other';
$select = new XmlSelect( $this->mName, false, $selected );
$select->addOptions( $this->getOptions() );
$tbAttribs = [ 'size' => $this->getSize() ];
if ( !empty( $this->mParams['disabled'] ) ) {
$select->setAttribute( 'disabled', 'disabled' );
$tbAttribs['disabled'] = 'disabled';
}
if ( isset( $this->mParams['tabindex'] ) ) {
$select->setAttribute( 'tabindex', $this->mParams['tabindex'] );
$tbAttribs['tabindex'] = $this->mParams['tabindex'];
}
$select = $select->getHTML();
if ( isset( $this->mParams['maxlength'] ) ) {
$tbAttribs['maxlength'] = $this->mParams['maxlength'];
}
$textbox = Html::input( $this->mName . '-other', $valInSelect ? '' : $value, 'text', $tbAttribs );
$wrapperAttribs = [
'id' => $this->mID,
'class' => $this->getFieldClasses()
];
if ( $this->mClass !== '' ) {
$wrapperAttribs['class'][] = $this->mClass;
}
return Html::rawElement(
'div',
$wrapperAttribs,
"$select<br />\n$textbox"
);
}
protected function shouldInfuseOOUI() {
return true;
}
protected function getOOUIModules() {
return [ 'mediawiki.widgets.SelectWithInputWidget' ];
}
public function getInputOOUI( $value ) {
$this->mParent->getOutput()->addModuleStyles( 'mediawiki.widgets.SelectWithInputWidget.styles' );
$valInSelect = false;
if ( $value !== false ) {
$value = strval( $value );
$valInSelect = in_array(
$value, HTMLFormField::flattenOptions( $this->getOptions() ), true
);
}
# DropdownInput
$dropdownAttribs = [
'name' => $this->mName,
'options' => $this->getOptionsOOUI(),
'value' => $valInSelect ? $value : 'other',
];
$allowedParams = [
'disabled',
'tabindex',
];
$dropdownAttribs += OOUI\Element::configFromHtmlAttributes(
$this->getAttributes( $allowedParams )
);
# TextInput
$textAttribs = [
'name' => $this->mName . '-other',
'size' => $this->getSize(),
'value' => $valInSelect ? '' : $value,
];
$allowedParams = [
'required',
'autofocus',
'multiple',
'disabled',
'tabindex',
'maxlength',
];
$textAttribs += OOUI\Element::configFromHtmlAttributes(
$this->getAttributes( $allowedParams )
);
if ( $this->mPlaceholder !== '' ) {
$textAttribs['placeholder'] = $this->mPlaceholder;
}
$disabled = false;
if ( isset( $this->mParams[ 'disabled' ] ) && $this->mParams[ 'disabled' ] ) {
$disabled = true;
}
$inputClasses = $this->getFieldClasses();
if ( $this->mClass !== '' ) {
$inputClasses = array_merge( $inputClasses, explode( ' ', $this->mClass ) );
}
return $this->getInputWidget( [
'id' => $this->mID,
'classes' => $inputClasses,
'disabled' => $disabled,
'textinput' => $textAttribs,
'dropdowninput' => $dropdownAttribs,
'required' => $this->mParams[ 'required' ] ?? false,
'or' => true,
] );
}
public function getInputWidget( $params ) {
return new MediaWiki\Widget\SelectWithInputWidget( $params );
}
/**
* @param WebRequest $request
*
* @return string
*/
public function loadDataFromRequest( $request ) {
if ( $request->getCheck( $this->mName ) ) {
$val = $request->getText( $this->mName );
if ( $val === 'other' ) {
$val = $request->getText( $this->mName . '-other' );
}
return $val;
} else {
return $this->getDefault();
}
}
/**
* Returns a list of classes that should be applied to the widget itself. Unfortunately, we can't use
* $this->mClass or the 'cssclass' config option, because they're also added to the outer field wrapper
* (which includes the label). This method exists a temporary workaround until HTMLFormField will have
* a stable way for subclasses to specify additional classes for the widget itself.
* @internal Should only be used in HTMLTimezoneField
* @return string[]
*/
protected function getFieldClasses(): array {
return [ self::FIELD_CLASS ];
}
}