X-Git-Url: https://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2FHTMLForm.php;h=33e447efd661a2c7dc8b53acdca3b1150e52e368;hb=63df600442e6614c21c42390a42651a0a9e8c5eb;hp=c08206d22273415eaf1392065feba4249c24f585;hpb=e593d18a886a9a9286753b41e4941fcb456a616a;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/HTMLForm.php b/includes/HTMLForm.php index c08206d222..33e447efd6 100644 --- a/includes/HTMLForm.php +++ b/includes/HTMLForm.php @@ -140,6 +140,7 @@ class HTMLForm extends ContextSource { protected $mSectionFooters = array(); protected $mPost = ''; protected $mId; + protected $mTableId = ''; protected $mSubmitID; protected $mSubmitName; @@ -200,12 +201,12 @@ class HTMLForm extends ContextSource { $this->setContext( $context ); $this->mTitle = false; // We don't need them to set a title $this->mMessagePrefix = $messagePrefix; - } else { + } elseif ( is_null( $context ) && $messagePrefix !== '' ) { + $this->mMessagePrefix = $messagePrefix; + } elseif ( is_string( $context ) && $messagePrefix === '' ) { // B/C since 1.18 - if ( is_string( $context ) && $messagePrefix === '' ) { - // it's actually $messagePrefix - $this->mMessagePrefix = $context; - } + // it's actually $messagePrefix + $this->mMessagePrefix = $context; } // Expand out into a tree. @@ -587,8 +588,8 @@ class HTMLForm extends ContextSource { } /** - * Display the form (sending to $wgOut), with an appropriate error - * message or stack of messages, and any validation errors, etc. + * Display the form (sending to the context's OutputPage object), with an + * appropriate error message or stack of messages, and any validation errors, etc. * * @attention You should call prepareForm() before calling this function. * Moreover, when doing method chaining this should be the very last method @@ -742,7 +743,7 @@ class HTMLForm extends ContextSource { * @return String */ function getBody() { - return $this->displaySection( $this->mFieldTree ); + return $this->displaySection( $this->mFieldTree, $this->mTableId ); } /** @@ -871,6 +872,18 @@ class HTMLForm extends ContextSource { return $this; } + /** + * Set the id of the \ or outermost \ element. + * + * @since 1.22 + * @param string $id new value of the id attribute, or "" to remove + * @return HTMLForm $this for chaining calls + */ + public function setTableId( $id ) { + $this->mTableId = $id; + return $this; + } + /** * @param string $id DOM id for the form * @return HTMLForm $this for chaining calls (since 1.20) @@ -879,6 +892,7 @@ class HTMLForm extends ContextSource { $this->mId = $id; return $this; } + /** * Prompt the whole form to be wrapped in a "
", with * this text as its "" element. @@ -977,7 +991,7 @@ class HTMLForm extends ContextSource { $hasLabel = true; } } elseif ( is_array( $value ) ) { - $section = $this->displaySection( $value, $key, "$fieldsetIDPrefix$key-" ); + $section = $this->displaySection( $value, "mw-htmlform-$key", "$fieldsetIDPrefix$key-" ); $legend = $this->getLegend( $key ); if ( isset( $this->mSectionHeaders[$key] ) ) { $section = $this->mSectionHeaders[$key] . $section; @@ -1005,7 +1019,7 @@ class HTMLForm extends ContextSource { ); if ( $sectionName ) { - $attribs['id'] = Sanitizer::escapeId( "mw-htmlform-$sectionName" ); + $attribs['id'] = Sanitizer::escapeId( $sectionName ); } if ( $displayFormat === 'table' ) { @@ -1093,7 +1107,6 @@ class HTMLForm extends ContextSource { $this->mAction = $action; return $this; } - } /** @@ -1111,6 +1124,12 @@ abstract class HTMLFormField { protected $mClass = ''; protected $mDefault; + /** + * @var bool If true will generate an empty div element with no label + * @since 1.22 + */ + protected $mShowEmptyLabels = true; + /** * @var HTMLForm */ @@ -1203,6 +1222,8 @@ abstract class HTMLFormField { /** * Initialise the object * @param array $params Associative Array. See HTMLForm doc for syntax. + * + * @since 1.22 The 'label' attribute no longer accepts raw HTML, use 'label-raw' instead * @throws MWException */ function __construct( $params ) { @@ -1221,7 +1242,14 @@ abstract class HTMLFormField { $this->mLabel = wfMessage( $msg, $msgInfo )->parse(); } elseif ( isset( $params['label'] ) ) { - $this->mLabel = $params['label']; + if ( $params['label'] === ' ' ) { + // Apparently some things set   directly and in an odd format + $this->mLabel = ' '; + } else { + $this->mLabel = htmlspecialchars( $params['label'] ); + } + } elseif ( isset( $params['label-raw'] ) ) { + $this->mLabel = $params['label-raw']; } $this->mName = "wp{$params['fieldname']}"; @@ -1266,6 +1294,10 @@ abstract class HTMLFormField { if ( isset( $params['flatlist'] ) ) { $this->mClass .= ' mw-htmlform-flatlist'; } + + if ( isset( $params['hidelabel'] ) ) { + $this->mShowEmptyLabels = false; + } } /** @@ -1326,9 +1358,14 @@ abstract class HTMLFormField { $cellAttributes = array(); $label = $this->getLabelHtml( $cellAttributes ); + $outerDivClass = array( + 'mw-input', + 'mw-htmlform-nolabel' => ( $label === '' ) + ); + $field = Html::rawElement( 'div', - array( 'class' => 'mw-input' ) + $cellAttributes, + array( 'class' => $outerDivClass ) + $cellAttributes, $inputHtml . "\n$errors" ); $html = Html::rawElement( 'div', @@ -1457,7 +1494,7 @@ abstract class HTMLFormField { } function getLabel() { - return $this->mLabel; + return is_null( $this->mLabel ) ? '' : $this->mLabel; } function getLabelHtml( $cellAttributes = array() ) { @@ -1469,20 +1506,32 @@ abstract class HTMLFormField { $for['for'] = $this->mID; } + $labelValue = trim( $this->getLabel() ); + $hasLabel = false; + if ( $labelValue !== ' ' && $labelValue !== '' ) { + $hasLabel = true; + } + $displayFormat = $this->mParent->getDisplayFormat(); - $labelElement = Html::rawElement( 'label', $for, $this->getLabel() ); + $html = ''; - if ( $displayFormat == 'table' ) { - return Html::rawElement( 'td', array( 'class' => 'mw-label' ) + $cellAttributes, - Html::rawElement( 'label', $for, $this->getLabel() ) - ); - } elseif ( $displayFormat == 'div' ) { - return Html::rawElement( 'div', array( 'class' => 'mw-label' ) + $cellAttributes, - Html::rawElement( 'label', $for, $this->getLabel() ) + if ( $displayFormat === 'table' ) { + $html = Html::rawElement( 'td', array( 'class' => 'mw-label' ) + $cellAttributes, + Html::rawElement( 'label', $for, $labelValue ) ); - } else { - return $labelElement; + } elseif ( $hasLabel || $this->mShowEmptyLabels ) { + if ( $displayFormat === 'div' ) { + $html = Html::rawElement( + 'div', + array( 'class' => 'mw-label' ) + $cellAttributes, + Html::rawElement( 'label', $for, $labelValue ) + ); + } else { + $html = Html::rawElement( 'label', $for, $labelValue ); + } } + + return $html; } function getDefault() { @@ -1622,16 +1671,19 @@ class HTMLTextField extends HTMLFormField { } } class HTMLTextAreaField extends HTMLFormField { + const DEFAULT_COLS = 80; + const DEFAULT_ROWS = 25; + function getCols() { return isset( $this->mParams['cols'] ) ? $this->mParams['cols'] - : 80; + : static::DEFAULT_COLS; } function getRows() { return isset( $this->mParams['rows'] ) ? $this->mParams['rows'] - : 25; + : static::DEFAULT_ROWS; } function getInputHTML( $value ) { @@ -1806,9 +1858,39 @@ class HTMLCheckField extends HTMLFormField { * A checkbox matrix * Operates similarly to HTMLMultiSelectField, but instead of using an array of * options, uses an array of rows and an array of columns to dynamically - * construct a matrix of options. + * construct a matrix of options. The tags used to identify a particular cell + * are of the form "columnName-rowName" + * + * Options: + * - columns + * - Required list of columns in the matrix. + * - rows + * - Required list of rows in the matrix. + * - force-options-on + * - Accepts array of column-row tags to be displayed as enabled but unavailable to change + * - force-options-off + * - Accepts array of column-row tags to be displayed as disabled but unavailable to change. + * - tooltips + * - Optional array mapping row label to tooltip content + * - tooltip-class + * - Optional CSS class used on tooltip container span. Defaults to mw-icon-question. */ -class HTMLCheckMatrix extends HTMLFormField { +class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable { + + static private $requiredParams = array( + // Required by underlying HTMLFormField + 'fieldname', + // Required by HTMLCheckMatrix + 'rows', 'columns' + ); + + public function __construct( $params ) { + $missing = array_diff( self::$requiredParams, array_keys( $params ) ); + if ( $missing ) { + throw HTMLFormFieldRequiredOptionsException::create( $this, $missing ); + } + parent::__construct( $params ); + } function validate( $value, $alldata ) { $rows = $this->mParams['rows']; @@ -1868,27 +1950,42 @@ class HTMLCheckMatrix extends HTMLFormField { } $tableContents .= Html::rawElement( 'tr', array(), "\n$headerContents\n" ); + $tooltipClass = 'mw-icon-question'; + if ( isset( $this->mParams['tooltip-class'] ) ) { + $tooltipClass = $this->mParams['tooltip-class']; + } + // Build the options matrix foreach ( $rows as $rowLabel => $rowTag ) { + // Append tooltip if configured + if ( isset( $this->mParams['tooltips'][$rowLabel] ) ) { + $tooltipAttribs = array( + 'class' => "mw-htmlform-tooltip $tooltipClass", + 'title' => $this->mParams['tooltips'][$rowLabel], + ); + $rowLabel .= ' ' . Html::element( 'span', $tooltipAttribs, '' ); + } $rowContents = Html::rawElement( 'td', array(), $rowLabel ); foreach ( $columns as $columnTag ) { - // Knock out any options that are not wanted - if ( isset( $this->mParams['remove-options'] ) - && in_array( "$columnTag-$rowTag", $this->mParams['remove-options'] ) ) - { - $rowContents .= Html::rawElement( 'td', array(), ' ' ); - } else { - // Construct the checkbox - $thisAttribs = array( - 'id' => "{$this->mID}-$columnTag-$rowTag", - 'value' => $columnTag . '-' . $rowTag - ); - $checkbox = Xml::check( - $this->mName . '[]', - in_array( $columnTag . '-' . $rowTag, (array)$value, true ), - $attribs + $thisAttribs ); - $rowContents .= Html::rawElement( 'td', array(), $checkbox ); + $thisTag = "$columnTag-$rowTag"; + // Construct the checkbox + $thisAttribs = array( + 'id' => "{$this->mID}-$thisTag", + 'value' => $thisTag, + ); + $checked = in_array( $thisTag, (array)$value, true ); + if ( $this->isTagForcedOff( $thisTag ) ) { + $checked = false; + $thisAttribs['disabled'] = 1; + } elseif ( $this->isTagForcedOn( $thisTag ) ) { + $checked = true; + $thisAttribs['disabled'] = 1; } + $rowContents .= Html::rawElement( + 'td', + array(), + Xml::check( "{$this->mName}[]", $checked, $attribs + $thisAttribs ) + ); } $tableContents .= Html::rawElement( 'tr', array(), "\n$rowContents\n" ); } @@ -1900,6 +1997,16 @@ class HTMLCheckMatrix extends HTMLFormField { return $html; } + protected function isTagForcedOff( $tag ) { + return isset( $this->mParams['force-options-off'] ) + && in_array( $tag, $this->mParams['force-options-off'] ); + } + + protected function isTagForcedOn( $tag ) { + return isset( $this->mParams['force-options-on'] ) + && in_array( $tag, $this->mParams['force-options-on'] ); + } + /** * Get the complete table row for the input, including help text, * labels, and whatever. @@ -1964,6 +2071,27 @@ class HTMLCheckMatrix extends HTMLFormField { return array(); } } + + function filterDataForSubmit( $data ) { + $columns = HTMLFormField::flattenOptions( $this->mParams['columns'] ); + $rows = HTMLFormField::flattenOptions( $this->mParams['rows'] ); + $res = array(); + foreach ( $columns as $column ) { + foreach ( $rows as $row ) { + // Make sure option hasn't been forced + $thisTag = "$column-$row"; + if ( $this->isTagForcedOff( $thisTag ) ) { + $res[$thisTag] = false; + } elseif ( $this->isTagForcedOn( $thisTag ) ) { + $res[$thisTag] = true; + } else { + $res[$thisTag] = in_array( $thisTag, $data ); + } + } + } + + return $res; + } } /** @@ -2105,7 +2233,7 @@ class HTMLSelectOrOtherField extends HTMLTextField { /** * Multi-select field */ -class HTMLMultiSelectField extends HTMLFormField { +class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable { function validate( $value, $alldata ) { $p = parent::validate( $value, $alldata ); @@ -2198,6 +2326,17 @@ class HTMLMultiSelectField extends HTMLFormField { } } + function filterDataForSubmit( $data ) { + $options = HTMLFormField::flattenOptions( $this->mParams['options'] ); + + $res = array(); + foreach ( $options as $opt ) { + $res["$opt"] = in_array( $opt, $data ); + } + + return $res; + } + protected function needsLabel() { return false; } @@ -2653,3 +2792,22 @@ class HTMLApiField extends HTMLFormField { return ''; } } + +interface HTMLNestedFilterable { + /** + * Support for seperating multi-option preferences into multiple preferences + * Due to lack of array support. + * @param $data array + */ + function filterDataForSubmit( $data ); +} + +class HTMLFormFieldRequiredOptionsException extends MWException { + static public function create( HTMLFormField $field, array $missing ) { + return new self( sprintf( + "Form type `%s` expected the following parameters to be set: %s", + get_class( $field ), + implode( ', ', $missing ) + ) ); + } +}