From 317836768b5c635032ffe12da00fb22e69038735 Mon Sep 17 00:00:00 2001 From: Happy-melon Date: Sat, 10 Apr 2010 12:03:30 +0000 Subject: [PATCH] Improvements and fixes to HTMLForm: * allow css classes to be specified in form descriptors * Don't overwrite $field['name'] if it's set * Allow IDs on hidden fields * Enforce 'required' validation on Text fields * Fix type validation on Int fields to correctly handle numbers larger than PHP_MAX_INT or with leading zeroes (eg phone numbers on 32 bit systems) * Fix weak-typing error in MultiSelect field * Formatting and doc fixes --- includes/HTMLForm.php | 84 ++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/includes/HTMLForm.php b/includes/HTMLForm.php index d51c29032a..e629155d63 100644 --- a/includes/HTMLForm.php +++ b/includes/HTMLForm.php @@ -19,11 +19,12 @@ * * 'class' -- the subclass of HTMLFormField that will be used * to create the object. *NOT* the CSS class! - * 'type' -- roughly translates into the type attribute. * if 'class' is not specified, this is used as a map * through HTMLForm::$typeMappings to get the class name. * 'default' -- default value when the form is displayed - * 'id' -- HTML id attribute + * 'id' -- HTML id attribute + * 'cssclass' -- CSS class * 'options' -- varies according to the specific object. * 'label-message' -- message key for a message to use as the label. * can be an array of msg key and then parameters to @@ -35,7 +36,7 @@ * the message. * 'required' -- passed through to the object, indicating that it * is a required field. - * 'size' -- the length of text fields + * 'size' -- the length of text fields * 'filter-callback -- a function name to give you the chance to * massage the inputted value before it's processed. * @see HTMLForm::filter() @@ -111,14 +112,17 @@ class HTMLForm { $this->mFlatFields = array(); foreach( $descriptor as $fieldname => $info ) { - $section = ''; - if ( isset( $info['section'] ) ) - $section = $info['section']; + $section = isset( $info['section'] ) + ? $info['section'] + : ''; - $info['name'] = $fieldname; + $info['name'] = isset( $info['name'] ) + ? $info['name'] + : $fieldname; - if ( isset( $info['type'] ) && $info['type'] == 'file' ) + if ( isset( $info['type'] ) && $info['type'] == 'file' ){ $this->mUseMultipart = true; + } $field = self::loadInputFromParameters( $info ); $field->mParent = $this; @@ -219,8 +223,9 @@ class HTMLForm { function trySubmit() { # Check for validation foreach( $this->mFlatFields as $fieldname => $field ) { - if ( !empty( $field->mParams['nodata'] ) ) + if ( !empty( $field->mParams['nodata'] ) ){ continue; + } if ( $field->validate( $this->mFieldData[$fieldname], $this->mFieldData ) @@ -290,9 +295,10 @@ class HTMLForm { * Add a hidden field to the output * @param $name String field name * @param $value String field value + * @param $attribs Array */ - public function addHiddenField( $name, $value ){ - $this->mHiddenFields[ $name ] = $value; + public function addHiddenField( $name, $value, $attribs=array() ){ + $this->mHiddenFields[ $name ] = array( $value, $attribs ); } public function addButton( $name, $value, $id=null, $attribs=null ){ @@ -367,7 +373,8 @@ class HTMLForm { $html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n"; foreach( $this->mHiddenFields as $name => $value ){ - $html .= Html::hidden( $name, $value ) . "\n"; + list( $value, $attribs ) = $value; + $html .= Html::hidden( $name, $value, $attribs ) . "\n"; } return $html; @@ -592,8 +599,9 @@ class HTMLForm { $fieldData = array(); foreach( $this->mFlatFields as $fieldname => $field ) { - if ( !empty( $field->mParams['nodata'] ) ) continue; - if ( !empty( $field->mParams['disabled'] ) ) { + if ( !empty( $field->mParams['nodata'] ) ){ + continue; + } elseif ( !empty( $field->mParams['disabled'] ) ) { $fieldData[$fieldname] = $field->getDefault(); } else { $fieldData[$fieldname] = $field->loadDataFromRequest( $wgRequest ); @@ -605,7 +613,7 @@ class HTMLForm { $field = $this->mFlatFields[$name]; $value = $field->filter( $value, $this->mFlatFields ); } - + $this->mFieldData = $fieldData; } @@ -642,6 +650,7 @@ abstract class HTMLFormField { public $mParams; protected $mLabel; # String label. Set on construction protected $mID; + protected $mClass = ''; protected $mDefault; public $mParent; @@ -660,7 +669,7 @@ abstract class HTMLFormField { * field input. Don't forget to call parent::validate() to ensure * that the user-defined callback mValidationCallback is still run * @param $value String the value the field was submitted with - * @param $alldata $all the data collected from the form + * @param $alldata Array the data collected from the form * @return Mixed Bool true on success, or String error to display. */ function validate( $value, $alldata ) { @@ -749,6 +758,10 @@ abstract class HTMLFormField { $this->mID = $id; } + if ( isset( $params['cssclass'] ) ) { + $this->mClass = $params['cssclass']; + } + if ( isset( $params['validation-callback'] ) ) { $this->mValidationCallback = $params['validation-callback']; } @@ -776,13 +789,19 @@ abstract class HTMLFormField { } $html = $this->getLabelHtml(); - $html .= Html::rawElement( 'td', array( 'class' => 'mw-input' ), - $this->getInputHTML( $value ) ."\n$errors" ); + $html .= Html::rawElement( + 'td', + array( 'class' => 'mw-input' ), + $this->getInputHTML( $value ) ."\n$errors" + ); $fieldType = get_class( $this ); - $html = Html::rawElement( 'tr', array( 'class' => "mw-htmlform-field-$fieldType" ), - $html ) . "\n"; + $html = Html::rawElement( + 'tr', + array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass}" ), + $html + ) . "\n"; $helptext = null; if ( isset( $this->mParams['help-message'] ) ) { @@ -929,6 +948,16 @@ class HTMLTextField extends HTMLFormField { return Html::element( 'input', $attribs ); } + + public function validate( $value, $alldata ){ + $p = parent::validate( $value, $alldata ); + if( $p !== true ) return $p; + + if( isset( $this->mParams['required'] ) && $value === '' ){ + return wfMsgExt( 'htmlform-required', 'parseinline' ); + } + return true; + } } class HTMLTextAreaField extends HTMLFormField { @@ -1018,7 +1047,9 @@ class HTMLIntField extends HTMLFloatField { if ( $p !== true ) return $p; - if ( intval( $value ) != $value ) { + if ( $value !== '' + && ( !is_numeric( $value ) || round( $value ) != $value ) ) + { return wfMsgExt( 'htmlform-int-invalid', 'parse' ); } @@ -1223,7 +1254,7 @@ class HTMLMultiSelectField extends HTMLFormField { } else { $thisAttribs = array( 'id' => $this->mID . "-$info", 'value' => $info ); - $checkbox = Xml::check( $this->mName . '[]', in_array( $info, $value ), + $checkbox = Xml::check( $this->mName . '[]', $info === $value, $attribs + $thisAttribs ); $checkbox .= ' ' . Html::rawElement( 'label', array( 'for' => $this->mID . "-$info" ), $label ); @@ -1352,9 +1383,14 @@ class HTMLInfoField extends HTMLFormField { class HTMLHiddenField extends HTMLFormField { public function getTableRow( $value ){ + $params = array(); + if( $this->mID ){ + $params['id'] = $this->mID; + } $this->mParent->addHiddenField( - $this->mParams['name'], - $this->mParams['default'] + $this->mName, + $this->mDefault, + $params ); return ''; } -- 2.20.1