'textwithbutton' => 'HTMLTextFieldWithButton',
'textarea' => 'HTMLTextAreaField',
'select' => 'HTMLSelectField',
+ 'combobox' => 'HTMLComboboxField',
'radio' => 'HTMLRadioField',
'multiselect' => 'HTMLMultiSelectField',
'limitselect' => 'HTMLSelectLimitField',
'selectandother' => 'HTMLSelectAndOtherField',
'namespaceselect' => 'HTMLSelectNamespace',
'namespaceselectwithbutton' => 'HTMLSelectNamespaceWithButton',
- 'advancednamespaceselect' => 'HTMLAdvancedSelectNamespace',
- 'advancednamespaceselectwithbutton' => 'HTMLAdvancedSelectNamespaceWithButton',
'tagfilter' => 'HTMLTagFilter',
'submit' => 'HTMLSubmitField',
'hidden' => 'HTMLHiddenField',
return false;
}
+ /**
+ * Same as self::show with the difference, that the form will be
+ * added to the output, no matter, if the validation was good or not.
+ * @return bool|Status Whether submission was successful.
+ */
+ function showAlways() {
+ $this->prepareForm();
+
+ $result = $this->tryAuthorizedSubmit();
+
+ $this->displayForm( $result );
+
+ return $result;
+ }
+
/**
* Validate all the fields, and call the submission callback
* function if everything is kosher.
* params) or strings (message keys)
*/
function trySubmit() {
+ $valid = true;
+ $hoistedErrors = array();
+ $hoistedErrors[] = isset( $this->mValidationErrorMessage )
+ ? $this->mValidationErrorMessage
+ : array( 'htmlform-invalid-input' );
+
$this->mWasSubmitted = true;
# Check for cancelled submission
if ( $field->isHidden( $this->mFieldData ) ) {
continue;
}
- if ( $field->validate(
- $this->mFieldData[$fieldname],
- $this->mFieldData )
- !== true
- ) {
- return isset( $this->mValidationErrorMessage )
- ? $this->mValidationErrorMessage
- : array( 'htmlform-invalid-input' );
+ $res = $field->validate( $this->mFieldData[$fieldname], $this->mFieldData );
+ if ( $res !== true ) {
+ $valid = false;
+ if ( $res !== false && !$field->canDisplayErrors() ) {
+ $hoistedErrors[] = array( 'rawmessage', $res );
+ }
+ }
+ }
+
+ if ( !$valid ) {
+ if ( count( $hoistedErrors ) === 1 ) {
+ $hoistedErrors = $hoistedErrors[0];
}
+ return $hoistedErrors;
}
$callback = $this->mSubmitCallback;
}
/**
- * Set the introductory message, overwriting any existing message.
+ * Set the introductory message HTML, overwriting any existing message.
* @since 1.19
*
- * @param string $msg Complete text of message to display
+ * @param string $msg Complete HTML of message to display
*
* @return HTMLForm $this for chaining calls (since 1.20)
*/
}
/**
- * Add introductory text.
+ * Add HTML to introductory message.
*
- * @param string $msg Complete text of message to display
+ * @param string $msg Complete HTML of message to display
*
* @return HTMLForm $this for chaining calls (since 1.20)
*/
}
/**
- * Add header text, inside the form.
+ * Add HTML to the header, inside the form.
*
- * @param string $msg Complete text of message to display
+ * @param string $msg Additional HTML to display in header
* @param string|null $section The section to add the header to
*
* @return HTMLForm $this for chaining calls (since 1.20)
* Set header text, inside the form.
* @since 1.19
*
- * @param string $msg Complete text of message to display
+ * @param string $msg Complete HTML of header to display
* @param string|null $section The section to add the header to
*
* @return HTMLForm $this for chaining calls (since 1.20)
return $this;
}
+ /**
+ * Get header text.
+ *
+ * @param string|null $section The section to get the header text for
+ * @since 1.26
+ * @return string HTML
+ */
+ function getHeaderText( $section = null ) {
+ if ( is_null( $section ) ) {
+ return $this->mHeader;
+ } else {
+ return isset( $this->mSectionHeaders[$section] ) ? $this->mSectionHeaders[$section] : '';
+ }
+ }
+
/**
* Add footer text, inside the form.
*
return $this;
}
+ /**
+ * Get footer text.
+ *
+ * @param string|null $section The section to get the footer text for
+ * @since 1.26
+ * @return string
+ */
+ function getFooterText( $section = null ) {
+ if ( is_null( $section ) ) {
+ return $this->mFooter;
+ } else {
+ return isset( $this->mSectionFooters[$section] ) ? $this->mSectionFooters[$section] : '';
+ }
+ }
+
/**
* Add text to the end of the display.
*
/**
* Add a button to the form
*
- * @param string $name Field name.
- * @param string $value Field value
- * @param string $id DOM id for the button (default: null)
- * @param array $attribs
- *
+ * @since 1.27 takes an array as shown. Earlier versions accepted
+ * 'name', 'value', 'id', and 'attribs' as separate parameters in that
+ * order.
+ * @note Custom labels ('label', 'label-message', 'label-raw') are not
+ * supported for IE6 and IE7 due to bugs in those browsers. If detected,
+ * they will be served buttons using 'value' as the button label.
+ * @param array $data Data to define the button:
+ * - name: (string) Button name.
+ * - value: (string) Button value.
+ * - label-message: (string, optional) Button label message key to use
+ * instead of 'value'. Overrides 'label' and 'label-raw'.
+ * - label: (string, optional) Button label text to use instead of
+ * 'value'. Overrides 'label-raw'.
+ * - label-raw: (string, optional) Button label HTML to use instead of
+ * 'value'.
+ * - id: (string, optional) DOM id for the button.
+ * - attribs: (array, optional) Additional HTML attributes.
+ * - flags: (string|string[], optional) OOUI flags.
* @return HTMLForm $this for chaining calls (since 1.20)
*/
- public function addButton( $name, $value, $id = null, $attribs = null ) {
- $this->mButtons[] = compact( 'name', 'value', 'id', 'attribs' );
+ public function addButton( $data ) {
+ if ( !is_array( $data ) ) {
+ $args = func_get_args();
+ if ( count( $args ) < 2 || count( $args ) > 4 ) {
+ throw new InvalidArgumentException(
+ 'Incorrect number of arguments for deprecated calling style'
+ );
+ }
+ $data = array(
+ 'name' => $args[0],
+ 'value' => $args[1],
+ 'id' => isset( $args[2] ) ? $args[2] : null,
+ 'attribs' => isset( $args[3] ) ? $args[3] : null,
+ );
+ } else {
+ if ( !isset( $data['name'] ) ) {
+ throw new InvalidArgumentException( 'A name is required' );
+ }
+ if ( !isset( $data['value'] ) ) {
+ throw new InvalidArgumentException( 'A value is required' );
+ }
+ }
+ $this->mButtons[] = $data + array(
+ 'id' => null,
+ 'attribs' => null,
+ 'flags' => null,
+ );
return $this;
}
*
* @param bool|string|array|Status $submitResult Output from HTMLForm::trySubmit()
*
- * @return string
+ * @return string HTML
*/
function getHTML( $submitResult ) {
# For good measure (it is the default)
$this->getOutput()->preventClickjacking();
$this->getOutput()->addModules( 'mediawiki.htmlform' );
+ $this->getOutput()->addModuleStyles( 'mediawiki.htmlform.styles' );
$html = ''
. $this->getErrors( $submitResult )
- // In OOUI forms, we handle mHeader elsewhere. FIXME This is horrible.
- . ( $this->getDisplayFormat() === 'ooui' ? '' : $this->mHeader )
+ . $this->getHeaderText()
. $this->getBody()
. $this->getHiddenFields()
. $this->getButtons()
- . $this->mFooter;
+ . $this->getFooterText();
$html = $this->wrapForm( $html );
$html = Xml::fieldset( $legend, $html );
}
- return Html::rawElement( 'form', $this->getFormAttributes() + array( 'class' => 'visualClear' ), $html );
+ return Html::rawElement(
+ 'form',
+ $this->getFormAttributes() + array( 'class' => 'visualClear' ),
+ $html
+ );
}
/**
) . "\n";
}
+ // IE<8 has bugs with <button>, so we'll need to avoid them.
+ $isBadIE = preg_match( '/MSIE [1-7]\./i', $this->getRequest()->getHeader( 'User-Agent' ) );
+
foreach ( $this->mButtons as $button ) {
$attrs = array(
'type' => 'submit',
'value' => $button['value']
);
+ if ( isset( $button['label-message'] ) ) {
+ $label = $this->msg( $button['label-message'] )->parse();
+ } elseif ( isset( $button['label'] ) ) {
+ $label = htmlspecialchars( $button['label'] );
+ } elseif ( isset( $button['label-raw'] ) ) {
+ $label = $button['label-raw'];
+ } else {
+ $label = htmlspecialchars( $button['value'] );
+ }
+
if ( $button['attribs'] ) {
$attrs += $button['attribs'];
}
$attrs['class'][] = 'mw-ui-button';
}
- $buttons .= Html::element( 'input', $attrs ) . "\n";
+ if ( $isBadIE ) {
+ $buttons .= Html::element( 'input', $attrs ) . "\n";
+ } else {
+ $buttons .= Html::rawElement( 'button', $attrs, $label ) . "\n";
+ }
}
$html = Html::rawElement( 'span',
return $this->mMethod;
}
+ /**
+ * Wraps the given $section into an user-visible fieldset.
+ *
+ * @param string $legend Legend text for the fieldset
+ * @param string $section The section content in plain Html
+ * @param array $attributes Additional attributes for the fieldset
+ * @return string The fieldset's Html
+ */
+ protected function wrapFieldSetSection( $legend, $section, $attributes ) {
+ return Xml::fieldset( $legend, $section, $attributes ) . "\n";
+ }
+
/**
* @todo Document
*
&$hasUserVisibleFields = false ) {
$displayFormat = $this->getDisplayFormat();
- $html = '';
+ $html = array();
$subsectionHtml = '';
$hasLabel = false;
// Conveniently, PHP method names are case-insensitive.
+ // For grep: this can call getDiv, getRaw, getInline, getVForm, getOOUI
$getFieldHtmlMethod = $displayFormat == 'table' ? 'getTableRow' : ( 'get' . $displayFormat );
foreach ( $fields as $key => $value ) {
$v = empty( $value->mParams['nodata'] )
? $this->mFieldData[$key]
: $value->getDefault();
- $html .= $value->$getFieldHtmlMethod( $v );
- $labelValue = trim( $value->getLabel() );
- if ( $labelValue != ' ' && $labelValue !== '' ) {
- $hasLabel = true;
- }
+ $retval = $value->$getFieldHtmlMethod( $v );
+
+ // check, if the form field should be added to
+ // the output.
+ if ( $value->hasVisibleOutput() ) {
+ $html[] = $retval;
+
+ $labelValue = trim( $value->getLabel() );
+ if ( $labelValue != ' ' && $labelValue !== '' ) {
+ $hasLabel = true;
+ }
- if ( get_class( $value ) !== 'HTMLHiddenField' &&
- get_class( $value ) !== 'HTMLApiField'
- ) {
$hasUserVisibleFields = true;
}
} elseif ( is_array( $value ) ) {
$legend = $this->getLegend( $key );
- if ( isset( $this->mSectionHeaders[$key] ) ) {
- $section = $this->mSectionHeaders[$key] . $section;
- }
- if ( isset( $this->mSectionFooters[$key] ) ) {
- $section .= $this->mSectionFooters[$key];
- }
+ $section = $this->getHeaderText( $key ) .
+ $section .
+ $this->getFooterText( $key );
$attributes = array();
if ( $fieldsetIDPrefix ) {
$attributes['id'] = Sanitizer::escapeId( "$fieldsetIDPrefix$key" );
}
- $subsectionHtml .= Xml::fieldset( $legend, $section, $attributes ) . "\n";
+ $subsectionHtml .= $this->wrapFieldSetSection( $legend, $section, $attributes );
} else {
// Just return the inputs, nothing fancy.
$subsectionHtml .= $section;
}
}
- if ( $displayFormat !== 'raw' ) {
- $classes = array();
-
- if ( !$hasLabel ) { // Avoid strange spacing when no labels exist
- $classes[] = 'mw-htmlform-nolabel';
- }
-
- $attribs = array(
- 'class' => implode( ' ', $classes ),
- );
-
- if ( $sectionName ) {
- $attribs['id'] = Sanitizer::escapeId( $sectionName );
- }
-
- if ( $displayFormat === 'table' ) {
- $html = Html::rawElement( 'table',
- $attribs,
- Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
- } elseif ( $displayFormat === 'inline' ) {
- $html = Html::rawElement( 'span', $attribs, "\n$html\n" );
- } elseif ( $displayFormat === 'ooui' ) {
- $config = array(
- 'classes' => $classes,
- );
- if ( $sectionName ) {
- $config['id'] = Sanitizer::escapeId( $sectionName );
- }
- if ( is_string( $this->mWrapperLegend ) ) {
- $config['label'] = $this->mWrapperLegend;
- }
- $fieldset = new OOUI\FieldsetLayout( $config );
- // Ewww. We should pass this as $config['items'], but there might be string snippets.
- $fieldset->group->appendContent( new OOUI\HtmlSnippet( $html ) );
- $html = $fieldset;
- } else {
- $html = Html::rawElement( 'div', $attribs, "\n$html\n" );
- }
- }
+ $html = $this->formatSection( $html, $sectionName, $hasLabel );
if ( $subsectionHtml ) {
if ( $this->mSubSectionBeforeFields ) {
}
}
+ /**
+ * Put a form section together from the individual fields' HTML, merging it and wrapping.
+ * @param array $fieldsHtml
+ * @param string $sectionName
+ * @param bool $anyFieldHasLabel
+ * @return string HTML
+ */
+ protected function formatSection( array $fieldsHtml, $sectionName, $anyFieldHasLabel ) {
+ $displayFormat = $this->getDisplayFormat();
+ $html = implode( '', $fieldsHtml );
+
+ if ( $displayFormat === 'raw' ) {
+ return $html;
+ }
+
+ $classes = array();
+
+ if ( !$anyFieldHasLabel ) { // Avoid strange spacing when no labels exist
+ $classes[] = 'mw-htmlform-nolabel';
+ }
+
+ $attribs = array(
+ 'class' => implode( ' ', $classes ),
+ );
+
+ if ( $sectionName ) {
+ $attribs['id'] = Sanitizer::escapeId( $sectionName );
+ }
+
+ if ( $displayFormat === 'table' ) {
+ return Html::rawElement( 'table',
+ $attribs,
+ Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
+ } elseif ( $displayFormat === 'inline' ) {
+ return Html::rawElement( 'span', $attribs, "\n$html\n" );
+ } else {
+ return Html::rawElement( 'div', $attribs, "\n$html\n" );
+ }
+ }
+
/**
* Construct the form fields from the Descriptor array
*/