diff options
Diffstat (limited to 'includes/htmlform/HTMLForm.php')
-rw-r--r-- | includes/htmlform/HTMLForm.php | 185 |
1 files changed, 137 insertions, 48 deletions
diff --git a/includes/htmlform/HTMLForm.php b/includes/htmlform/HTMLForm.php index ce140038..08fa0a91 100644 --- a/includes/htmlform/HTMLForm.php +++ b/includes/htmlform/HTMLForm.php @@ -51,6 +51,7 @@ * 'id' -- HTML id attribute * 'cssclass' -- CSS class * 'csshelpclass' -- CSS class used to style help text + * 'dir' -- Direction of the element. * 'options' -- associative array mapping labels to values. * Some field types support multi-level arrays. * 'options-messages' -- associative array mapping message keys to values. @@ -75,14 +76,35 @@ * '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() + * @see HTMLFormField::filter() * 'validation-callback' -- a function name to give you the chance * to impose extra validation on the field input. - * @see HTMLForm::validate() + * @see HTMLFormField::validate() * 'name' -- By default, the 'name' attribute of the input field * is "wp{$fieldname}". If you want a different name * (eg one without the "wp" prefix), specify it here and * it will be used without modification. + * 'hide-if' -- expression given as an array stating when the field + * should be hidden. The first array value has to be the + * expression's logic operator. Supported expressions: + * 'NOT' + * [ 'NOT', array $expression ] + * To hide a field if a given expression is not true. + * '===' + * [ '===', string $fieldName, string $value ] + * To hide a field if another field identified by + * $field has the value $value. + * '!==' + * [ '!==', string $fieldName, string $value ] + * Same as [ 'NOT', [ '===', $fieldName, $value ] + * 'OR', 'AND', 'NOR', 'NAND' + * [ 'XXX', array $expression1, ..., array $expressionN ] + * To hide a field if one or more (OR), all (AND), + * neither (NOR) or not all (NAND) given expressions + * are evaluated as true. + * The expressions will be given to a JavaScript frontend + * module which will continually update the field's + * visibility. * * Since 1.20, you can chain mutators to ease the form generation: * @par Example: @@ -103,6 +125,7 @@ class HTMLForm extends ContextSource { public static $typeMappings = array( 'api' => 'HTMLApiField', 'text' => 'HTMLTextField', + 'textwithbutton' => 'HTMLTextFieldWithButton', 'textarea' => 'HTMLTextAreaField', 'select' => 'HTMLSelectField', 'radio' => 'HTMLRadioField', @@ -116,6 +139,7 @@ class HTMLForm extends ContextSource { 'selectorother' => 'HTMLSelectOrOtherField', 'selectandother' => 'HTMLSelectAndOtherField', 'namespaceselect' => 'HTMLSelectNamespace', + 'namespaceselectwithbutton' => 'HTMLSelectNamespaceWithButton', 'tagfilter' => 'HTMLTagFilter', 'submit' => 'HTMLSubmitField', 'hidden' => 'HTMLHiddenField', @@ -129,6 +153,8 @@ class HTMLForm extends ContextSource { 'email' => 'HTMLTextField', 'password' => 'HTMLTextField', 'url' => 'HTMLTextField', + 'title' => 'HTMLTitleTextField', + 'user' => 'HTMLUserTextField', ); public $mFieldData; @@ -141,7 +167,7 @@ class HTMLForm extends ContextSource { protected $mFieldTree; protected $mShowReset = false; protected $mShowSubmit = true; - protected $mSubmitModifierClass = 'mw-ui-constructive'; + protected $mSubmitFlags = array( 'constructive', 'primary' ); protected $mSubmitCallback; protected $mValidationErrorMessage; @@ -216,12 +242,12 @@ class HTMLForm extends ContextSource { */ protected $availableSubclassDisplayFormats = array( 'vform', + 'ooui', ); /** * Construct a HTMLForm object for given display type. May return a HTMLForm subclass. * - * @throws MWException When the display format requested is not known * @param string $displayFormat * @param mixed $arguments... Additional arguments to pass to the constructor. * @return HTMLForm @@ -234,6 +260,9 @@ class HTMLForm extends ContextSource { case 'vform': $reflector = new ReflectionClass( 'VFormHTMLForm' ); return $reflector->newInstanceArgs( $arguments ); + case 'ooui': + $reflector = new ReflectionClass( 'OOUIHTMLForm' ); + return $reflector->newInstanceArgs( $arguments ); default: $reflector = new ReflectionClass( 'HTMLForm' ); $form = $reflector->newInstanceArgs( $arguments ); @@ -266,7 +295,10 @@ class HTMLForm extends ContextSource { } // Evil hack for mobile :( - if ( !$this->getConfig()->get( 'HTMLFormAllowTableFormat' ) && $this->displayFormat === 'table' ) { + if ( + !$this->getConfig()->get( 'HTMLFormAllowTableFormat' ) + && $this->displayFormat === 'table' + ) { $this->displayFormat = 'div'; } @@ -405,7 +437,9 @@ class HTMLForm extends ContextSource { * @throws MWException * @return HTMLFormField Instance of a subclass of HTMLFormField */ - public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) { + public static function loadInputFromParameters( $fieldname, $descriptor, + HTMLForm $parent = null + ) { $class = static::getClassFromDescriptor( $fieldname, $descriptor ); $descriptor['fieldname'] = $fieldname; @@ -677,6 +711,21 @@ class HTMLForm extends ContextSource { } /** + * Get header text. + * + * @param string|null $section The section to get the header text for + * @since 1.26 + * @return string + */ + 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. * * @param string $msg Complete text of message to display @@ -717,6 +766,21 @@ class HTMLForm extends ContextSource { } /** + * 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. * * @param string $msg Complete text of message to display @@ -834,14 +898,15 @@ class HTMLForm extends ContextSource { # 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 ) - . $this->mHeader + . $this->getHeaderText() . $this->getBody() . $this->getHiddenFields() . $this->getButtons() - . $this->mFooter; + . $this->getFooterText(); $html = $this->wrapForm( $html ); @@ -861,7 +926,6 @@ class HTMLForm extends ContextSource { $attribs = array( 'action' => $this->getAction(), 'method' => $this->getMethod(), - 'class' => array( 'visualClear' ), 'enctype' => $encType, ); if ( !empty( $this->mId ) ) { @@ -880,10 +944,11 @@ class HTMLForm extends ContextSource { function wrapForm( $html ) { # Include a <fieldset> wrapper for style, if requested. if ( $this->mWrapperLegend !== false ) { - $html = Xml::fieldset( $this->mWrapperLegend, $html ); + $legend = is_string( $this->mWrapperLegend ) ? $this->mWrapperLegend : false; + $html = Xml::fieldset( $legend, $html ); } - return Html::rawElement( 'form', $this->getFormAttributes(), $html ); + return Html::rawElement( 'form', $this->getFormAttributes() + array( 'class' => 'visualClear' ), $html ); } /** @@ -940,7 +1005,10 @@ class HTMLForm extends ContextSource { $attribs['class'] = array( 'mw-htmlform-submit' ); if ( $useMediaWikiUIEverywhere ) { - array_push( $attribs['class'], 'mw-ui-button', $this->mSubmitModifierClass ); + foreach ( $this->mSubmitFlags as $flag ) { + array_push( $attribs['class'], 'mw-ui-' . $flag ); + } + array_push( $attribs['class'], 'mw-ui-button' ); } $buttons .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n"; @@ -1067,7 +1135,7 @@ class HTMLForm extends ContextSource { * @since 1.24 */ public function setSubmitDestructive() { - $this->mSubmitModifierClass = 'mw-ui-destructive'; + $this->mSubmitFlags = array( 'destructive', 'primary' ); } /** @@ -1075,7 +1143,7 @@ class HTMLForm extends ContextSource { * @since 1.25 */ public function setSubmitProgressive() { - $this->mSubmitModifierClass = 'mw-ui-progressive'; + $this->mSubmitFlags = array( 'progressive', 'primary' ); } /** @@ -1187,9 +1255,10 @@ class HTMLForm extends ContextSource { * Prompt the whole form to be wrapped in a "<fieldset>", with * this text as its "<legend>" element. * - * @param string|bool $legend HTML to go inside the "<legend>" element, or - * false for no <legend> - * Will be escaped + * @param string|bool $legend If false, no wrapper or legend will be displayed. + * If true, a wrapper will be displayed, but no legend. + * If a string, a wrapper will be displayed with that string as a legend. + * The string will be escaped before being output (this doesn't support HTML). * * @return HTMLForm $this for chaining calls (since 1.20) */ @@ -1263,11 +1332,14 @@ class HTMLForm extends ContextSource { * @return HTMLForm $this for chaining calls (since 1.20) */ public function setMethod( $method = 'post' ) { - $this->mMethod = $method; + $this->mMethod = strtolower( $method ); return $this; } + /** + * @return string Always lowercase + */ public function getMethod() { return $this->mMethod; } @@ -1291,7 +1363,7 @@ class HTMLForm extends ContextSource { &$hasUserVisibleFields = false ) { $displayFormat = $this->getDisplayFormat(); - $html = ''; + $html = array(); $subsectionHtml = ''; $hasLabel = false; @@ -1303,7 +1375,7 @@ class HTMLForm extends ContextSource { $v = empty( $value->mParams['nodata'] ) ? $this->mFieldData[$key] : $value->getDefault(); - $html .= $value->$getFieldHtmlMethod( $v ); + $html[] = $value->$getFieldHtmlMethod( $v ); $labelValue = trim( $value->getLabel() ); if ( $labelValue != ' ' && $labelValue !== '' ) { @@ -1330,12 +1402,9 @@ class HTMLForm extends ContextSource { $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 ) { @@ -1349,36 +1418,56 @@ class HTMLForm extends ContextSource { } } - if ( $displayFormat !== 'raw' ) { - $classes = array(); + $html = $this->formatSection( $html, $sectionName, $hasLabel ); - if ( !$hasLabel ) { // Avoid strange spacing when no labels exist - $classes[] = 'mw-htmlform-nolabel'; + if ( $subsectionHtml ) { + if ( $this->mSubSectionBeforeFields ) { + return $subsectionHtml . "\n" . $html; + } else { + return $html . "\n" . $subsectionHtml; } + } else { + return $html; + } + } - $attribs = array( - 'class' => implode( ' ', $classes ), - ); + /** + * 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 ( $sectionName ) { - $attribs['id'] = Sanitizer::escapeId( $sectionName ); - } + if ( $displayFormat === 'raw' ) { + return $html; + } - 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" ); - } else { - $html = Html::rawElement( 'div', $attribs, "\n$html\n" ); - } + $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 ( $this->mSubSectionBeforeFields ) { - return $subsectionHtml . "\n" . $html; + 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 . "\n" . $subsectionHtml; + return Html::rawElement( 'div', $attribs, "\n$html\n" ); } } |